UNPKG

7.54 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
12}) : (function(o, m, k, k2) {
13 if (k2 === undefined) k2 = k;
14 o[k2] = m[k];
15}));
16var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17 Object.defineProperty(o, "default", { enumerable: true, value: v });
18}) : function(o, v) {
19 o["default"] = v;
20});
21var __importStar = (this && this.__importStar) || function (mod) {
22 if (mod && mod.__esModule) return mod;
23 var result = {};
24 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
25 __setModuleDefault(result, mod);
26 return result;
27};
28Object.defineProperty(exports, "__esModule", { value: true });
29const architect_1 = require("@angular-devkit/architect");
30const core_1 = require("@angular-devkit/core");
31const fs = __importStar(require("fs"));
32const path = __importStar(require("path"));
33const utils_1 = require("../utils");
34const inline_critical_css_1 = require("../utils/index-file/inline-critical-css");
35const service_worker_1 = require("../utils/service-worker");
36const spinner_1 = require("../utils/spinner");
37async function _renderUniversal(options, context, browserResult, serverResult, spinner) {
38 // Get browser target options.
39 const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
40 const rawBrowserOptions = (await context.getTargetOptions(browserTarget));
41 const browserBuilderName = await context.getBuilderNameForTarget(browserTarget);
42 const browserOptions = await context.validateOptions(rawBrowserOptions, browserBuilderName);
43 // Initialize zone.js
44 const root = context.workspaceRoot;
45 const zonePackage = require.resolve('zone.js', { paths: [root] });
46 await Promise.resolve().then(() => __importStar(require(zonePackage)));
47 const projectName = context.target && context.target.project;
48 if (!projectName) {
49 throw new Error('The builder requires a target.');
50 }
51 const projectMetadata = await context.getProjectMetadata(projectName);
52 const projectRoot = core_1.resolve(core_1.normalize(root), core_1.normalize(projectMetadata.root || ''));
53 const { styles } = utils_1.normalizeOptimization(browserOptions.optimization);
54 const inlineCriticalCssProcessor = styles.inlineCritical
55 ? new inline_critical_css_1.InlineCriticalCssProcessor({
56 minify: styles.minify,
57 deployUrl: browserOptions.deployUrl,
58 })
59 : undefined;
60 for (const outputPath of browserResult.outputPaths) {
61 const localeDirectory = path.relative(browserResult.baseOutputPath, outputPath);
62 const browserIndexOutputPath = path.join(outputPath, 'index.html');
63 const indexHtml = await fs.promises.readFile(browserIndexOutputPath, 'utf8');
64 const serverBundlePath = await _getServerModuleBundlePath(options, context, serverResult, localeDirectory);
65 const { AppServerModule, renderModule } = await Promise.resolve().then(() => __importStar(require(serverBundlePath)));
66 const renderModuleFn = renderModule;
67 if (!(renderModuleFn && AppServerModule)) {
68 throw new Error(`renderModule method and/or AppServerModule were not exported from: ${serverBundlePath}.`);
69 }
70 // Load platform server module renderer
71 const renderOpts = {
72 document: indexHtml,
73 url: options.route,
74 };
75 let html = await renderModuleFn(AppServerModule, renderOpts);
76 // Overwrite the client index file.
77 const outputIndexPath = options.outputIndexPath
78 ? path.join(root, options.outputIndexPath)
79 : browserIndexOutputPath;
80 if (inlineCriticalCssProcessor) {
81 const { content, warnings, errors } = await inlineCriticalCssProcessor.process(html, {
82 outputPath,
83 });
84 html = content;
85 if (warnings.length || errors.length) {
86 spinner.stop();
87 warnings.forEach((m) => context.logger.warn(m));
88 errors.forEach((m) => context.logger.error(m));
89 spinner.start();
90 }
91 }
92 await fs.promises.writeFile(outputIndexPath, html);
93 if (browserOptions.serviceWorker) {
94 await service_worker_1.augmentAppWithServiceWorker(core_1.normalize(root), projectRoot, core_1.normalize(outputPath), browserOptions.baseHref || '/', browserOptions.ngswConfigPath);
95 }
96 }
97 return browserResult;
98}
99async function _getServerModuleBundlePath(options, context, serverResult, browserLocaleDirectory) {
100 if (options.appModuleBundle) {
101 return path.join(context.workspaceRoot, options.appModuleBundle);
102 }
103 const { baseOutputPath = '' } = serverResult;
104 const outputPath = path.join(baseOutputPath, browserLocaleDirectory);
105 if (!fs.existsSync(outputPath)) {
106 throw new Error(`Could not find server output directory: ${outputPath}.`);
107 }
108 const re = /^main\.(?:[a-zA-Z0-9]{20}\.)?js$/;
109 const maybeMain = fs.readdirSync(outputPath).find((x) => re.test(x));
110 if (!maybeMain) {
111 throw new Error('Could not find the main bundle.');
112 }
113 return path.join(outputPath, maybeMain);
114}
115async function _appShellBuilder(options, context) {
116 const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
117 const serverTarget = architect_1.targetFromTargetString(options.serverTarget);
118 // Never run the browser target in watch mode.
119 // If service worker is needed, it will be added in _renderUniversal();
120 const browserOptions = (await context.getTargetOptions(browserTarget));
121 const optimization = utils_1.normalizeOptimization(browserOptions.optimization);
122 optimization.styles.inlineCritical = false;
123 const browserTargetRun = await context.scheduleTarget(browserTarget, {
124 watch: false,
125 serviceWorker: false,
126 optimization: optimization,
127 });
128 const serverTargetRun = await context.scheduleTarget(serverTarget, {
129 watch: false,
130 });
131 let spinner;
132 try {
133 const [browserResult, serverResult] = await Promise.all([
134 browserTargetRun.result,
135 serverTargetRun.result,
136 ]);
137 if (browserResult.success === false || browserResult.baseOutputPath === undefined) {
138 return browserResult;
139 }
140 else if (serverResult.success === false) {
141 return serverResult;
142 }
143 spinner = new spinner_1.Spinner();
144 spinner.start('Generating application shell...');
145 const result = await _renderUniversal(options, context, browserResult, serverResult, spinner);
146 spinner.succeed('Application shell generation complete.');
147 return result;
148 }
149 catch (err) {
150 spinner === null || spinner === void 0 ? void 0 : spinner.fail('Application shell generation failed.');
151 return { success: false, error: err.message };
152 }
153 finally {
154 await Promise.all([browserTargetRun.stop(), serverTargetRun.stop()]);
155 }
156}
157exports.default = architect_1.createBuilder(_appShellBuilder);