ngc-webpack
Version:
A wrapper for the @ngtools/webpack with hooks into the compilation process
218 lines (211 loc) • 10 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var Path = require("path");
var webpack = require("webpack");
var minimist = require("minimist");
var webpack_1 = require("@ngtools/webpack");
var plugin_1 = require("../plugin");
var utils_1 = require("../utils");
var config_1 = require("./config");
var util_1 = require("./util");
var perform_compile_async_1 = require("./perform_compile_async");
var cli_context_1 = require("./cli-context");
/**
* Resolve the config to an object.
* If it's a fn, invoke.
*
* Also check if it's a mocked ES6 Module in cases where TS file is used that uses "export default"
* @param config
* @returns {any}
*/
function resolveConfig(config) {
if (typeof config === 'function') {
return config();
}
else if (config.__esModule === true && !!config.default) {
return resolveConfig(config.default);
}
else {
return config;
}
}
function findPluginIndex(plugins, type) {
return plugins.findIndex(function (p) { return p instanceof type; });
}
exports.findPluginIndex = findPluginIndex;
function getPluginMeta(plugins) {
var idx = findPluginIndex(plugins, plugin_1.NgcWebpackPlugin);
if (idx > -1) {
return {
idx: idx,
instance: plugins[idx],
options: plugins[idx].ngcWebpackPluginOptions
};
}
idx = findPluginIndex(plugins, webpack_1.AngularCompilerPlugin);
if (idx > -1) {
return {
idx: idx,
instance: plugins[idx],
options: plugins[idx].options
};
}
// TODO: allow running without a plugin and create it here?
throw new Error('Could not find an instance of NgcWebpackPlugin or AngularCompilerPlugin in the provided webpack configuration');
}
exports.getPluginMeta = getPluginMeta;
function normalizeProjectParam(tsConfigPath, args, parsedArgs) {
var _a = [args.indexOf('-p'), args.indexOf('--project')], pIdx = _a[0], projectIdx = _a[1];
parsedArgs.p = tsConfigPath;
if (pIdx > -1) {
args[pIdx + 1] = tsConfigPath;
}
else {
args.push('-p', tsConfigPath);
}
if (projectIdx > -1) {
delete parsedArgs.project;
args.splice(projectIdx, 1);
}
}
function createCliExecutionHostFactory(config) {
var pWrap = utils_1.promiseWrapper();
return {
compilationResult: pWrap.promise,
createCliExecutionHost: function (options) {
var inline = config.options.skipTemplateCodegen;
if (config.options.skipTemplateCodegen && !config.options.fullTemplateTypeCheck) {
/*
Angular cli's compiler host will not generate metadata if skipping template codegen or no full template typescheck.
See https://github.com/angular/angular/blob/master/packages/compiler-cli/src/transformers/compiler_host.ts#L440
This is required if we want to inline the resources while compiling and not in post.
To solve this we need to enforce `fullTemplateTypeCheck`:
options.fullTemplateTypeCheck = true;
but this has issues
see issue: https://github.com/angular/angular/issues/19905
which has pending PR to fix: https://github.com/angular/angular/pull/20490
and also, dev's might want this off...
current workaround will is to disable skipTemplateCodegen
this looks weired because we want it on...
but, at this point we have a config object (NgcParsedConfiguration) which is an angular-cli parsed config
created by called `readNgcCommandLineAndConfiguration`.
The config object has a property `emitFlags` which at this point has the flag `Codegen` OFF !!!
OFF reflects config.options.skipTemplateCodegen = true.
Setting `config.options.skipTemplateCodegen` to false, at this point, will not change the emitFlags.
The compiler will NOT emit template code gen but the `isSourceFile` method in
https://github.com/angular/angular/blob/master/packages/compiler-cli/src/transformers/compiler_host.ts#L440
will return true!
This is a weak workaround and a more solid one is required.
TODO: refactor workaround to a writeFile wrapper that will not write generated files.
*/
// options.fullTemplateTypeCheck = true;
config.options.skipTemplateCodegen = false;
}
var ctx = cli_context_1.createCliContext(config);
var compilerHost = ctx.compilerHost;
return {
execute: function (compiler) {
var compilation = ctx.createCompilation(compiler);
var rootNames = config.rootNames.slice();
perform_compile_async_1.performCompilationAsync({
rootNames: rootNames,
options: config.options,
/*
The compiler host "writeFile" is wrapped with a handler that will
inline all resources into metadata modules (non flat bundle modules)
*/
host: (inline && !config.options.skipMetadataEmit && !config.options.flatModuleOutFile)
? ctx.resourceInliningCompilerHost()
: compilerHost,
emitFlags: config.emitFlags,
// we use the compiler-cli emit callback but we wrap it so we can create a map of source file path to
// output file path
emitCallback: ctx.emitCallback,
customTransformers: {
beforeTs: inline ? [ctx.createInlineResourcesTransformer()] : []
}
})
.then(function (result) {
var parsedDiagnostics = util_1.parseDiagnostics(result.diagnostics, config.options);
if (parsedDiagnostics.exitCode !== 0) {
var error = parsedDiagnostics.error || new Error(parsedDiagnostics.exitCode.toString());
compilation.errors.push(error);
}
// inline resources into the flat metadata json file, if exists.
if (compilation.errors.length === 0 && config.options.flatModuleOutFile) {
// TODO: check that it exists, config.rootNames should not have it (i.e. it was added to rootNames)
var flatModulePath = rootNames[rootNames.length - 1];
ctx.inlineFlatModuleMetadataBundle(Path.dirname(flatModulePath), config.options.flatModuleOutFile);
}
pWrap.resolve(parsedDiagnostics);
})
.catch(function (err) { return pWrap.reject(err); });
},
compilerHost: compilerHost,
transformers: []
};
}
};
}
function runCli(webpackConfig, tsConfigPath, cliParams) {
return Promise.resolve(null)
.then(function () {
// normalize params:
if (tsConfigPath && typeof tsConfigPath !== 'string') {
cliParams = tsConfigPath;
tsConfigPath = undefined;
}
if (!cliParams) {
cliParams = { args: [], parsedArgs: {} };
}
else if (!cliParams.parsedArgs) {
cliParams.parsedArgs = minimist(cliParams.args);
}
var args = cliParams.args, parsedArgs = cliParams.parsedArgs;
if (typeof webpackConfig === 'string') {
var configPath = Path.isAbsolute(webpackConfig)
? webpackConfig
: Path.join(process.cwd(), webpackConfig);
webpackConfig = require(configPath);
}
var configModule = resolveConfig(webpackConfig);
var pluginMeta = getPluginMeta(configModule.plugins || []);
if (!tsConfigPath) {
tsConfigPath = parsedArgs.p || parsedArgs.project || pluginMeta.options.tsConfigPath;
}
if (!tsConfigPath) {
throw new Error('Invalid configuration, please set tsconfig path in cli params -p or --project or in NgcWebpackPlugin configuration');
}
pluginMeta.options.tsConfigPath = tsConfigPath;
normalizeProjectParam(tsConfigPath, args, parsedArgs);
var config = config_1.readNgcCommandLineAndConfiguration(args, parsedArgs);
if (config.errors.length) {
return util_1.parseDiagnostics(config.errors, /*options*/ undefined);
}
var _a = createCliExecutionHostFactory(config), compilationResult = _a.compilationResult, executionHostFactory = _a.createCliExecutionHost;
var plugin = new plugin_1.NgcWebpackPlugin(pluginMeta.options, executionHostFactory);
configModule.plugins.splice(pluginMeta.idx, 1);
var compiler = webpack(configModule);
plugin.apply(compiler);
return compilationResult;
});
}
exports.runCli = runCli;
if (require.main === module) {
var args = process.argv.slice(2);
var parsedArgs = minimist(args);
var webpackConfig = parsedArgs.webpack;
if (!webpackConfig) {
throw new Error('Missing webpack argument');
}
delete parsedArgs.webpack;
args.splice(args.indexOf('--webpack'), 2);
runCli(webpackConfig, { args: args, parsedArgs: parsedArgs })
.then(function (parsedDiagnostics) {
if (parsedDiagnostics.error) {
console.error(parsedDiagnostics.error);
}
process.exit(parsedDiagnostics.exitCode);
});
}
//# sourceMappingURL=cli.js.map