@angular-devkit/build-angular
Version:
Angular Webpack Build Facade
200 lines (199 loc) • 8.26 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.execute = void 0;
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const architect_1 = require("@angular-devkit/architect");
const build_webpack_1 = require("@angular-devkit/build-webpack");
const fs = require("fs");
const path = require("path");
const webpack = require("webpack");
const i18n_options_1 = require("../utils/i18n-options");
const version_1 = require("../utils/version");
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
const configs_1 = require("../webpack/configs");
const stats_1 = require("../webpack/utils/stats");
const schema_1 = require("./schema");
function getI18nOutfile(format) {
switch (format) {
case 'xmb':
return 'messages.xmb';
case 'xlf':
case 'xlif':
case 'xliff':
case 'xlf2':
case 'xliff2':
return 'messages.xlf';
default:
throw new Error(`Unsupported format "${format}"`);
}
}
async function getSerializer(format, sourceLocale, basePath, useLegacyIds = true) {
switch (format) {
case schema_1.Format.Xmb:
const { XmbTranslationSerializer } = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/extract/translation_files/xmb_translation_serializer'));
// tslint:disable-next-line: no-any
return new XmbTranslationSerializer(basePath, useLegacyIds);
case schema_1.Format.Xlf:
case schema_1.Format.Xlif:
case schema_1.Format.Xliff:
const { Xliff1TranslationSerializer } = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/extract/translation_files/xliff1_translation_serializer'));
// tslint:disable-next-line: no-any
return new Xliff1TranslationSerializer(sourceLocale, basePath, useLegacyIds, {});
case schema_1.Format.Xlf2:
case schema_1.Format.Xliff2:
const { Xliff2TranslationSerializer } = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/extract/translation_files/xliff2_translation_serializer'));
// tslint:disable-next-line: no-any
return new Xliff2TranslationSerializer(sourceLocale, basePath, useLegacyIds, {});
}
}
class InMemoryOutputPlugin {
apply(compiler) {
// tslint:disable-next-line:no-any
compiler.outputFileSystem = new webpack.MemoryOutputFileSystem();
}
}
async function execute(options, context, transforms) {
var _a;
// Check Angular version.
version_1.assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
const browserOptions = await context.validateOptions(await context.getTargetOptions(browserTarget), await context.getBuilderNameForTarget(browserTarget));
if (options.i18nFormat !== schema_1.Format.Xlf) {
options.format = options.i18nFormat;
}
switch (options.format) {
case schema_1.Format.Xlf:
case schema_1.Format.Xlif:
case schema_1.Format.Xliff:
options.format = schema_1.Format.Xlf;
break;
case schema_1.Format.Xlf2:
case schema_1.Format.Xliff2:
options.format = schema_1.Format.Xlf2;
break;
case undefined:
options.format = schema_1.Format.Xlf;
break;
}
// We need to determine the outFile name so that AngularCompiler can retrieve it.
let outFile = options.outFile || getI18nOutfile(options.format);
if (options.outputPath) {
// AngularCompilerPlugin doesn't support genDir so we have to adjust outFile instead.
outFile = path.join(options.outputPath, outFile);
}
outFile = path.resolve(context.workspaceRoot, outFile);
if (!context.target || !context.target.project) {
throw new Error('The builder requires a target.');
}
const metadata = await context.getProjectMetadata(context.target);
const i18n = i18n_options_1.createI18nOptions(metadata);
let usingIvy = false;
const ivyMessages = [];
const { config, projectRoot } = await webpack_browser_config_1.generateBrowserWebpackConfigFromContext({
...browserOptions,
optimization: {
scripts: false,
styles: false,
},
sourceMap: {
scripts: true,
styles: false,
vendor: true,
},
buildOptimizer: false,
i18nLocale: options.i18nLocale || i18n.sourceLocale,
i18nFormat: options.format,
i18nFile: outFile,
aot: true,
progress: options.progress,
assets: [],
scripts: [],
styles: [],
deleteOutputPath: false,
}, context, (wco) => {
const isIvyApplication = wco.tsConfig.options.enableIvy !== false;
// Ivy extraction is the default for Ivy applications.
usingIvy = (isIvyApplication && options.ivy === undefined) || !!options.ivy;
if (usingIvy) {
if (!isIvyApplication) {
context.logger.warn('Ivy extraction enabled but application is not Ivy enabled. Extraction may fail.');
}
}
else if (isIvyApplication) {
context.logger.warn('Ivy extraction not enabled but application is Ivy enabled. ' +
'If the extraction fails, the `--ivy` flag will enable Ivy extraction.');
}
const partials = [
{ plugins: [new InMemoryOutputPlugin()] },
configs_1.getCommonConfig(wco),
// Only use VE extraction if not using Ivy
configs_1.getAotConfig(wco, !usingIvy),
configs_1.getStatsConfig(wco),
];
// Add Ivy application file extractor support
if (usingIvy) {
partials.unshift({
module: {
rules: [
{
test: /\.[t|j]s$/,
loader: require.resolve('./ivy-extract-loader'),
options: {
messageHandler: (messages) => ivyMessages.push(...messages),
},
},
],
},
});
}
// Replace all stylesheets with an empty default export
partials.push({
plugins: [
new webpack.NormalModuleReplacementPlugin(/\.(css|scss|sass|styl|less)$/, path.join(__dirname, 'empty-export-default.js')),
],
});
return partials;
});
if (usingIvy) {
try {
require.resolve('@angular/localize');
}
catch (_b) {
return {
success: false,
error: `Ivy extraction requires the '@angular/localize' package.`,
};
}
}
const webpackResult = await build_webpack_1.runWebpack((await ((_a = transforms === null || transforms === void 0 ? void 0 : transforms.webpackConfiguration) === null || _a === void 0 ? void 0 : _a.call(transforms, config))) || config, context, {
logging: stats_1.createWebpackLoggingCallback(false, context.logger),
webpackFactory: webpack,
}).toPromise();
// Complete if using VE
if (!usingIvy) {
return webpackResult;
}
// Nothing to process if the Webpack build failed
if (!webpackResult.success) {
return webpackResult;
}
// Serialize all extracted messages
const serializer = await getSerializer(options.format, i18n.sourceLocale, config.context || projectRoot);
const content = serializer.serialize(ivyMessages);
// Ensure directory exists
const outputPath = path.dirname(outFile);
if (!fs.existsSync(outputPath)) {
fs.mkdirSync(outputPath, { recursive: true });
}
// Write translation file
fs.writeFileSync(outFile, content);
return webpackResult;
}
exports.execute = execute;
exports.default = architect_1.createBuilder(execute);