Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c9c27a6

Browse files
FrozenPandazBrocco
authored andcommitted
refactor(@ngtools/webpack): refactor bootstrap refactoring
1 parent 1e1160f commit c9c27a6

File tree

4 files changed

+81
-48
lines changed

4 files changed

+81
-48
lines changed

‎packages/@ngtools/webpack/src/loader.ts‎

Lines changed: 74 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,7 @@ function _removeDecorators(refactor: TypeScriptFileRefactor) {
187187
}
188188

189189

190-
function _replaceBootstrap(plugin: AotPlugin, refactor: TypeScriptFileRefactor) {
191-
// If bootstrapModule can't be found, bail out early.
192-
if (!refactor.sourceMatch(/\bbootstrapModule\b/)) {
193-
return;
194-
}
195-
190+
function _getNgFactoryPath(plugin: AotPlugin, refactor: TypeScriptFileRefactor) {
196191
// Calculate the base path.
197192
const basePath = path.normalize(plugin.basePath);
198193
const genDir = path.normalize(plugin.genDir);
@@ -202,44 +197,20 @@ function _replaceBootstrap(plugin: AotPlugin, refactor: TypeScriptFileRefactor)
202197
const relativeEntryModulePath = path.relative(basePath, entryModuleFileName);
203198
const fullEntryModulePath = path.resolve(genDir, relativeEntryModulePath);
204199
const relativeNgFactoryPath = path.relative(dirName, fullEntryModulePath);
205-
const ngFactoryPath = './' + relativeNgFactoryPath.replace(/\\/g, '/');
206-
207-
const allCalls = refactor.findAstNodes(refactor.sourceFile,
208-
ts.SyntaxKind.CallExpression, true) as ts.CallExpression[];
209-
210-
const bootstraps = allCalls
211-
.filter(call => call.expression.kind == ts.SyntaxKind.PropertyAccessExpression)
212-
.map(call => call.expression as ts.PropertyAccessExpression)
213-
.filter(access => {
214-
return access.name.kind == ts.SyntaxKind.Identifier
215-
&& access.name.text == 'bootstrapModule';
216-
});
200+
return './' + relativeNgFactoryPath.replace(/\\/g, '/');
201+
}
217202

218-
const calls: ts.CallExpression[] = bootstraps
219-
.reduce((previous, access) => {
220-
const expressions
221-
= refactor.findAstNodes(access, ts.SyntaxKind.CallExpression, true) as ts.CallExpression[];
222-
return previous.concat(expressions);
223-
}, [])
224-
.filter((call: ts.CallExpression) => call.expression.kind == ts.SyntaxKind.Identifier)
225-
.filter((call: ts.CallExpression) => {
226-
// Find if the expression matches one of the replacement targets
227-
return !!changeMap[(call.expression as ts.Identifier).text];
228-
});
229203

230-
if (calls.length == 0) {
231-
// Didn't find any dynamic bootstrapping going on.
232-
return;
233-
}
234-
235-
// Create the changes we need.
236-
allCalls
237-
.filter(call => bootstraps.some(bs => bs == call.expression))
238-
.forEach((call: ts.CallExpression) => {
239-
refactor.replaceNode(call.arguments[0], entryModule.className + 'NgFactory');
240-
});
204+
function _replacePlatform(
205+
refactor: TypeScriptFileRefactor, bootstrapCall: ts.PropertyAccessExpression) {
206+
const platforms = (refactor.findAstNodes(bootstrapCall,
207+
ts.SyntaxKind.CallExpression, true) as ts.CallExpression[])
208+
.filter(call => {
209+
return call.expression.kind == ts.SyntaxKind.Identifier;
210+
})
211+
.filter(call => !!changeMap[(call.expression as ts.Identifier).text]);
241212

242-
calls.forEach(call => {
213+
platforms.forEach(call => {
243214
const platform = changeMap[(call.expression as ts.Identifier).text];
244215

245216
// Replace with mapped replacement
@@ -248,14 +219,70 @@ function _replaceBootstrap(plugin: AotPlugin, refactor: TypeScriptFileRefactor)
248219
// Add the appropriate import
249220
refactor.insertImport(platform.name, platform.importLocation);
250221
});
222+
}
223+
224+
225+
function _replaceBootstrap(refactor: TypeScriptFileRefactor, call: ts.CallExpression) {
226+
// If bootstrapModule can't be found, bail out early.
227+
if (!call.getText().includes('bootstrapModule')) {
228+
return;
229+
}
230+
231+
if (call.expression.kind == ts.SyntaxKind.PropertyAccessExpression) {
232+
const access = call.expression as ts.PropertyAccessExpression;
233+
234+
if (access.name.text === 'bootstrapModule') {
235+
_replacePlatform(refactor, access);
236+
refactor.replaceNode(access.name, 'bootstrapModuleFactory');
237+
}
238+
}
239+
}
240+
241+
242+
function _getCaller(node: ts.Node): ts.CallExpression {
243+
while (node = node.parent) {
244+
if (node.kind === ts.SyntaxKind.CallExpression) {
245+
return node as ts.CallExpression;
246+
}
247+
}
248+
return null;
249+
}
250+
251251

252-
bootstraps
253-
.forEach((bs: ts.PropertyAccessExpression) => {
254-
// This changes the call.
255-
refactor.replaceNode(bs.name, 'bootstrapModuleFactory');
252+
function _replaceEntryModule(plugin: AotPlugin, refactor: TypeScriptFileRefactor) {
253+
const modules = refactor.findAstNodes(refactor.sourceFile, ts.SyntaxKind.Identifier, true)
254+
.filter(identifier => identifier.getText() === plugin.entryModule.className)
255+
.filter(identifier =>
256+
identifier.parent.kind === ts.SyntaxKind.CallExpression ||
257+
identifier.parent.kind === ts.SyntaxKind.PropertyAssignment)
258+
.filter(node => !!_getCaller(node));
259+
260+
if (modules.length == 0) {
261+
return;
262+
}
263+
264+
const factoryClassName = plugin.entryModule.className + 'NgFactory';
265+
266+
refactor.insertImport(factoryClassName, _getNgFactoryPath(plugin, refactor));
267+
268+
modules
269+
.forEach(reference => {
270+
refactor.replaceNode(reference, factoryClassName);
271+
_replaceBootstrap(refactor, _getCaller(reference));
256272
});
273+
}
274+
275+
276+
function _refactorBootstrap(plugin: AotPlugin, refactor: TypeScriptFileRefactor) {
277+
const genDir = path.normalize(plugin.genDir);
278+
const dirName = path.normalize(path.dirname(refactor.fileName));
279+
280+
// Bail if in the generated directory
281+
if (dirName.startsWith(genDir)) {
282+
return;
283+
}
257284

258-
refactor.insertImport(entryModule.className+'NgFactory',ngFactoryPath);
285+
_replaceEntryModule(plugin,refactor);
259286
}
260287

261288
export function removeModuleIdOnlyForTesting(refactor: TypeScriptFileRefactor) {
@@ -410,7 +437,7 @@ export function ngcLoader(this: LoaderContext & { _compilation: any }) {
410437
if (!plugin.skipCodeGeneration) {
411438
return Promise.resolve()
412439
.then(() => _removeDecorators(refactor))
413-
.then(() => _replaceBootstrap(plugin, refactor));
440+
.then(() => _refactorBootstrap(plugin, refactor));
414441
} else {
415442
return Promise.resolve()
416443
.then(() => _replaceResources(refactor))

‎tests/e2e/assets/webpack/test-server-app/app/app.module.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ export class HomeView {}
2424
],
2525
bootstrap: [AppComponent]
2626
})
27-
export class AppModule { }
27+
export class AppModule {
28+
static testProp: string;
29+
}

‎tests/e2e/assets/webpack/test-server-app/app/main.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ import 'core-js/es7/reflect';
22
import {platformDynamicServer} from '@angular/platform-server';
33
import {AppModule} from './app.module';
44

5+
AppModule.testProp = 'testing';
6+
57
platformDynamicServer().bootstrapModule(AppModule);

‎tests/e2e/tests/packages/webpack/server.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ export default function(skipCleaning: () => void) {
1616
+ 'type: undefined, decorators.*Inject.*args: .*DOCUMENT.*'))
1717
.then(() => expectFileToMatch('dist/app.main.js',
1818
new RegExp('AppComponent.ctorParameters = .*MyInjectable'))
19+
.then(() => expectFileToMatch('dist/app.main.js',
20+
/AppModule.*\.testProp=\'testing\'/)
1921
.then(() => skipCleaning());
2022
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /