UNPKG

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