Skip to content

Commit 588baa5

Browse files
alan-agius4vikerman
authored andcommitted
fix(@angular-devkit/build-angular): i18n app shell with Ivy
1 parent 669abae commit 588baa5

File tree

6 files changed

+231
-70
lines changed

6 files changed

+231
-70
lines changed

packages/angular_devkit/build_angular/src/app-shell/index.ts

Lines changed: 73 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
createBuilder,
1212
targetFromTargetString,
1313
} from '@angular-devkit/architect';
14-
import { JsonObject, join, normalize, resolve, schema } from '@angular-devkit/core';
14+
import { JsonObject, join, normalize, resolve } from '@angular-devkit/core';
1515
import { NodeJsSyncHost } from '@angular-devkit/core/node';
1616
import * as fs from 'fs';
1717
import * as path from 'path';
@@ -27,11 +27,6 @@ async function _renderUniversal(
2727
browserResult: BrowserBuilderOutput,
2828
serverResult: ServerBuilderOutput,
2929
): Promise<BrowserBuilderOutput> {
30-
const browserIndexOutputPath = path.join(browserResult.outputPath || '', 'index.html');
31-
const indexHtml = fs.readFileSync(browserIndexOutputPath, 'utf8');
32-
const serverBundlePath = await _getServerModuleBundlePath(options, context, serverResult);
33-
const root = context.workspaceRoot;
34-
3530
// Get browser target options.
3631
const browserTarget = targetFromTargetString(options.browserTarget);
3732
const rawBrowserOptions = await context.getTargetOptions(browserTarget);
@@ -42,65 +37,72 @@ async function _renderUniversal(
4237
);
4338

4439
// Initialize zone.js
40+
const root = context.workspaceRoot;
4541
const zonePackage = require.resolve('zone.js', { paths: [root] });
4642
await import(zonePackage);
4743

48-
const {
49-
AppServerModule,
50-
AppServerModuleNgFactory,
51-
renderModule,
52-
renderModuleFactory,
53-
} = await import(serverBundlePath);
54-
55-
let renderModuleFn: (module: unknown, options: {}) => Promise<string>;
56-
let AppServerModuleDef: unknown;
57-
58-
if (renderModuleFactory && AppServerModuleNgFactory) {
59-
renderModuleFn = renderModuleFactory;
60-
AppServerModuleDef = AppServerModuleNgFactory;
61-
} else if (renderModule && AppServerModule) {
62-
renderModuleFn = renderModule;
63-
AppServerModuleDef = AppServerModule;
64-
} else {
65-
throw new Error(`renderModule method and/or AppServerModule were not exported from: ${serverBundlePath}.`);
44+
const host = new NodeJsSyncHost();
45+
const projectName = context.target && context.target.project;
46+
if (!projectName) {
47+
throw new Error('The builder requires a target.');
6648
}
6749

68-
// Load platform server module renderer
69-
const renderOpts = {
70-
document: indexHtml,
71-
url: options.route,
72-
};
73-
74-
const html = await renderModuleFn(AppServerModuleDef, renderOpts);
75-
// Overwrite the client index file.
76-
const outputIndexPath = options.outputIndexPath
77-
? path.join(root, options.outputIndexPath)
78-
: browserIndexOutputPath;
79-
80-
fs.writeFileSync(outputIndexPath, html);
81-
82-
if (browserOptions.serviceWorker) {
83-
const host = new NodeJsSyncHost();
50+
const projectMetadata = await context.getProjectMetadata(projectName);
51+
const projectRoot = resolve(
52+
normalize(root),
53+
normalize((projectMetadata.root as string) || ''),
54+
);
8455

85-
const projectName = context.target && context.target.project;
86-
if (!projectName) {
87-
throw new Error('The builder requires a target.');
56+
for (const outputPath of browserResult.outputPaths) {
57+
const localeDirectory = path.relative(browserResult.baseOutputPath, outputPath);
58+
const browserIndexOutputPath = path.join(outputPath, 'index.html');
59+
const indexHtml = fs.readFileSync(browserIndexOutputPath, 'utf8');
60+
const serverBundlePath = await _getServerModuleBundlePath(options, context, serverResult, localeDirectory);
61+
62+
const {
63+
AppServerModule,
64+
AppServerModuleNgFactory,
65+
renderModule,
66+
renderModuleFactory,
67+
} = await import(serverBundlePath);
68+
69+
let renderModuleFn: (module: unknown, options: {}) => Promise<string>;
70+
let AppServerModuleDef: unknown;
71+
72+
if (renderModuleFactory && AppServerModuleNgFactory) {
73+
renderModuleFn = renderModuleFactory;
74+
AppServerModuleDef = AppServerModuleNgFactory;
75+
} else if (renderModule && AppServerModule) {
76+
renderModuleFn = renderModule;
77+
AppServerModuleDef = AppServerModule;
78+
} else {
79+
throw new Error(`renderModule method and/or AppServerModule were not exported from: ${serverBundlePath}.`);
8880
}
8981

90-
const projectMetadata = await context.getProjectMetadata(projectName);
91-
const projectRoot = resolve(
92-
normalize(context.workspaceRoot),
93-
normalize((projectMetadata.root as string) || ''),
94-
);
95-
96-
await augmentAppWithServiceWorker(
97-
host,
98-
normalize(root),
99-
projectRoot,
100-
join(normalize(root), browserOptions.outputPath),
101-
browserOptions.baseHref || '/',
102-
browserOptions.ngswConfigPath,
103-
);
82+
// Load platform server module renderer
83+
const renderOpts = {
84+
document: indexHtml,
85+
url: options.route,
86+
};
87+
88+
const html = await renderModuleFn(AppServerModuleDef, renderOpts);
89+
// Overwrite the client index file.
90+
const outputIndexPath = options.outputIndexPath
91+
? path.join(root, options.outputIndexPath)
92+
: browserIndexOutputPath;
93+
94+
fs.writeFileSync(outputIndexPath, html);
95+
96+
if (browserOptions.serviceWorker) {
97+
await augmentAppWithServiceWorker(
98+
host,
99+
normalize(root),
100+
projectRoot,
101+
normalize(outputPath),
102+
browserOptions.baseHref || '/',
103+
browserOptions.ngswConfigPath,
104+
);
105+
}
104106
}
105107

106108
return browserResult;
@@ -110,11 +112,18 @@ async function _getServerModuleBundlePath(
110112
options: BuildWebpackAppShellSchema,
111113
context: BuilderContext,
112114
serverResult: ServerBuilderOutput,
115+
browserLocaleDirectory: string,
113116
) {
114117
if (options.appModuleBundle) {
115118
return path.join(context.workspaceRoot, options.appModuleBundle);
116119
} else {
117-
const outputPath = serverResult.outputPath || '/';
120+
const { baseOutputPath = '' } = serverResult;
121+
const outputPath = path.join(baseOutputPath, browserLocaleDirectory);
122+
123+
if (!fs.existsSync(outputPath)) {
124+
throw new Error(`Could not find server output directory: ${outputPath}.`);
125+
}
126+
118127
const files = fs.readdirSync(outputPath, 'utf8');
119128
const re = /^main\.(?:[a-zA-Z0-9]{20}\.)?(?:bundle\.)?js$/;
120129
const maybeMain = files.filter(x => re.test(x))[0];
@@ -140,15 +149,17 @@ async function _appShellBuilder(
140149
watch: false,
141150
serviceWorker: false,
142151
});
143-
const serverTargetRun = await context.scheduleTarget(serverTarget, {});
152+
const serverTargetRun = await context.scheduleTarget(serverTarget, {
153+
watch: false,
154+
});
144155

145156
try {
146157
const [browserResult, serverResult] = await Promise.all([
147-
(browserTargetRun.result as {}) as BrowserBuilderOutput,
148-
serverTargetRun.result,
158+
browserTargetRun.result as unknown as BrowserBuilderOutput,
159+
serverTargetRun.result as unknown as ServerBuilderOutput,
149160
]);
150161

151-
if (browserResult.success === false || browserResult.outputPath === undefined) {
162+
if (browserResult.success === false || browserResult.baseOutputPath === undefined) {
152163
return browserResult;
153164
} else if (serverResult.success === false) {
154165
return serverResult;

packages/angular_devkit/build_angular/src/browser/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ const cacheDownlevelPath = cachingDisabled ? undefined : findCachePath('angular-
7575

7676
export type BrowserBuilderOutput = json.JsonObject &
7777
BuilderOutput & {
78+
baseOutputPath: string;
79+
outputPaths: string[];
80+
/**
81+
* @deprecated in version 9. Use 'outputPaths' instead.
82+
*/
7883
outputPath: string;
7984
};
8085

@@ -228,6 +233,7 @@ export function buildWebpackBrowser(
228233
const host = new NodeJsSyncHost();
229234
const root = normalize(context.workspaceRoot);
230235
const baseOutputPath = path.resolve(context.workspaceRoot, options.outputPath);
236+
let outputPaths: undefined | string[];
231237

232238
// Check Angular version.
233239
assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
@@ -278,7 +284,7 @@ export function buildWebpackBrowser(
278284

279285
return { success };
280286
} else if (success) {
281-
const outputPaths = ensureOutputPaths(baseOutputPath, i18n);
287+
outputPaths = ensureOutputPaths(baseOutputPath, i18n);
282288

283289
let noModuleFiles: EmittedFiles[] | undefined;
284290
let moduleFiles: EmittedFiles[] | undefined;
@@ -699,8 +705,9 @@ export function buildWebpackBrowser(
699705
event =>
700706
({
701707
...event,
702-
// If we use differential loading, both configs have the same outputs
708+
baseOutputPath,
703709
outputPath: baseOutputPath,
710+
outputPaths: outputPaths || [baseOutputPath],
704711
} as BrowserBuilderOutput),
705712
),
706713
);

packages/angular_devkit/build_angular/src/server/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ import { Schema as ServerBuilderOptions } from './schema';
3232

3333
// If success is true, outputPath should be set.
3434
export type ServerBuilderOutput = json.JsonObject & BuilderOutput & {
35-
outputPath?: string;
35+
baseOutputPath: string;
36+
outputPaths: string[];
37+
/**
38+
* @deprecated in version 9. Use 'outputPaths' instead.
39+
*/
40+
outputPath: string;
3641
};
3742

3843
export { ServerBuilderOptions };
@@ -52,6 +57,7 @@ export function execute(
5257
const tsConfig = readTsconfig(options.tsConfig, root);
5358
const target = tsConfig.options.target || ScriptTarget.ES5;
5459
const baseOutputPath = path.resolve(root, options.outputPath);
60+
let outputPaths: undefined | string[];
5561

5662
return from(initialize(options, context, transforms.webpackConfiguration)).pipe(
5763
concatMap(({ config, i18n }) => {
@@ -66,7 +72,7 @@ export function execute(
6672
throw new Error('Webpack stats build result is required.');
6773
}
6874

69-
const outputPaths = ensureOutputPaths(baseOutputPath, i18n);
75+
outputPaths = ensureOutputPaths(baseOutputPath, i18n);
7076

7177
const success = await i18nInlineEmittedFiles(
7278
context,
@@ -92,7 +98,9 @@ export function execute(
9298

9399
return {
94100
...output,
95-
outputPath: path.resolve(root, options.outputPath),
101+
baseOutputPath,
102+
outputPath: baseOutputPath,
103+
outputPaths: outputPaths || [baseOutputPath],
96104
} as ServerBuilderOutput;
97105
}),
98106
);

packages/angular_devkit/build_angular/test/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ export async function browserBuild(
7676
const output = (await run.result) as BrowserBuilderOutput;
7777
expect(output.success).toBe(true);
7878

79-
expect(output.outputPath).not.toBeUndefined();
80-
const outputPath = normalize(output.outputPath);
79+
expect(output.outputPaths[0]).not.toBeUndefined();
80+
const outputPath = normalize(output.outputPaths[0]);
8181

8282
const fileNames = await host.list(outputPath).toPromise();
8383
const files = fileNames.reduce((acc: { [name: string]: Promise<string> }, path) => {

0 commit comments

Comments
 (0)