Skip to content

Commit 816e76a

Browse files
crisbetopkozlowski-opensource
authored andcommitted
fix(migrations): automatically prune root module after bootstrap step (#49030)
Currently as a part of the bootstrapping API migration we comment out the metadata of the root module and instruct users to re-run the module pruning step which can be cumbersome. These changes run the module pruning automatically. Note that initially I tried to reuse the module pruning logic and to run it against the existing program, but it was problematic, because it was common to have conflicting changes for the same AST nodes. PR Close #49030
1 parent b97d591 commit 816e76a

File tree

4 files changed

+135
-86
lines changed

4 files changed

+135
-86
lines changed

packages/core/schematics/ng-generate/standalone-migration/README.md

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,7 @@ modules were skipped explicitly in the first step of the migration.
194194
5. Adjust any dynamic import paths so that they're correct when they're copied over.
195195
6. If an API with a standalone equivalent is detected, it may be converted automatically as well.
196196
E.g. `RouterModule.forRoot` will become `provideRouter`.
197-
7. Comment out the module metadata of the root class and leave a TODO to remove it. This can also
198-
be done automatically by running the "Remove unnecessary NgModules" step again.
197+
7. Remove the root module.
199198

200199
If the migration detects that the `providers` or `imports` of the root module are referencing code
201200
outside of the class declaration, it will attempt to carry over as much of it as it can to the new
@@ -276,26 +275,6 @@ interface NonImportedInterface {
276275
const token = new InjectionToken<NonImportedInterface>('token');
277276

278277
export class ExportedConfigClass {}
279-
280-
@NgModule(/*
281-
TODO(standalone-migration): clean up removed NgModule class manually or run the "Remove unnecessary NgModule classes" step of the migration again.
282-
{
283-
imports: [
284-
SharedModule,
285-
BrowserAnimationsModule,
286-
RouterModule.forRoot([{
287-
path: 'shop',
288-
loadComponent: () => import('./shop/shop.component').then(m => m.ShopComponent)
289-
}])
290-
],
291-
declarations: [AppComponent],
292-
bootstrap: [AppComponent],
293-
providers: [
294-
{provide: token, useValue: {foo: true, bar: {baz: false}}},
295-
{provide: CONFIG, useClass: ExportedConfigClass}
296-
]
297-
}*/)
298-
export class AppModule {}
299278
```
300279

301280
```typescript

packages/core/schematics/ng-generate/standalone-migration/index.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ interface Options {
3232
}
3333

3434
export default function(options: Options): Rule {
35-
return async (tree) => {
35+
return async (tree, context) => {
3636
const {buildPaths, testPaths} = await getProjectTsConfigPaths(tree);
3737
const basePath = process.cwd();
3838
const allPaths = [...buildPaths, ...testPaths];
@@ -54,12 +54,17 @@ export default function(options: Options): Rule {
5454
throw new SchematicsException(`Could not find any files to migrate under the path ${
5555
pathToMigrate}. Cannot run the standalone migration.`);
5656
}
57+
58+
context.logger.info('🎉 Automated migration step has finished! 🎉');
59+
context.logger.info(
60+
'IMPORTANT! Please verify manually that your application builds and behaves as expected.');
61+
// TODO(crisbeto): log a link to the guide once it's published
5762
};
5863
}
5964

6065
function standaloneMigration(
6166
tree: Tree, tsconfigPath: string, basePath: string, pathToMigrate: string,
62-
schematicOptions: Options): number {
67+
schematicOptions: Options, oldProgram?: NgtscProgram): number {
6368
if (schematicOptions.path.startsWith('..')) {
6469
throw new SchematicsException(
6570
'Cannot run standalone migration outside of the current project.');
@@ -75,7 +80,7 @@ function standaloneMigration(
7580
skipDefaultLibCheck: true,
7681
});
7782
const referenceLookupExcludedFiles = /node_modules|\.ngtypecheck\.ts/;
78-
const program = createProgram({rootNames, host, options}) as NgtscProgram;
83+
const program = createProgram({rootNames, host, options, oldProgram}) as NgtscProgram;
7984
const printer = ts.createPrinter();
8085

8186
if (existsSync(pathToMigrate) && !statSync(pathToMigrate).isDirectory()) {
@@ -134,5 +139,15 @@ function standaloneMigration(
134139
}
135140
}
136141

142+
// Run the module pruning after the standalone bootstrap to automatically remove the root module.
143+
// Note that we can't run the module pruning internally without propagating the changes to disk,
144+
// because there may be conflicting AST node changes.
145+
if (schematicOptions.mode === MigrationMode.standaloneBootstrap) {
146+
return standaloneMigration(
147+
tree, tsconfigPath, basePath, pathToMigrate,
148+
{...schematicOptions, mode: MigrationMode.pruneModules}, program) +
149+
sourceFiles.length;
150+
}
151+
137152
return sourceFiles.length;
138153
}

packages/core/schematics/ng-generate/standalone-migration/standalone-bootstrap.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,11 @@ function migrateBootstrapCall(
151151
const moduleImportsInNewCall: ts.Expression[] = [];
152152
let nodeLookup: NodeLookup|null = null;
153153

154-
// We can't reuse the module pruning logic, because we would have to recreate the entire program.
155-
// Instead we comment out the module's metadata so that the user doesn't get compilation errors
156-
// for the classes that are left in the `declarations` array. This should allow the app to
157-
// run and the user can run module pruning themselves to get rid of the module afterwards.
154+
// Comment out the metadata so that it'll be removed when we run the module pruning afterwards.
155+
// If the pruning is left for some reason, the user will still have an actionable TODO.
158156
tracker.insertText(
159157
moduleSourceFile, analysis.metadata.getStart(),
160-
'/* TODO(standalone-migration): clean up removed NgModule class manually or run the ' +
161-
'"Remove unnecessary NgModule classes" step of the migration again. \n');
158+
'/* TODO(standalone-migration): clean up removed NgModule class manually. \n');
162159
tracker.insertText(moduleSourceFile, analysis.metadata.getEnd(), ' */');
163160

164161
if (providers && ts.isPropertyAssignment(providers)) {

0 commit comments

Comments
 (0)