UNPKG

ngc-webpack

Version:

A wrapper for the @ngtools/webpack with hooks into the compilation process

218 lines (211 loc) 10 kB
"use strict"; 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