forked from angular/angular-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(@angular-devkit/build-angular): export `@angular/platform-server…
…` symbols in server bundle This commit adds an internal file to export needed symbols from `@angular/platform-server` when building a server bundle. This is needed. This is needed so that DI tokens can be referenced and set at runtime outside of the bundle. Also, it adds a migration to remove these exports from the users files as otherwise an export collision would occur due to the same symbol being exported multiple times.
- Loading branch information
1 parent
326e923
commit 15d3fc6
Showing
10 changed files
with
258 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
packages/angular_devkit/build_angular/src/builders/server/platform-server-exports-loader.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
/** | ||
* This loader is needed to add additional exports and is a workaround for a Webpack bug that doesn't | ||
* allow exports from multiple files in the same entry. | ||
* @see https://github.com/webpack/webpack/issues/15936. | ||
*/ | ||
export default function ( | ||
this: import('webpack').LoaderContext<{}>, | ||
content: string, | ||
map: Parameters<import('webpack').LoaderDefinitionFunction>[1], | ||
) { | ||
const source = `${content} | ||
// EXPORTS added by @angular-devkit/build-angular | ||
export { renderModule, ɵSERVER_CONTEXT } from '@angular/platform-server'; | ||
`; | ||
|
||
this.callback(null, source, map); | ||
|
||
return; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
packages/schematics/angular/migrations/update-15/remove-platform-server-exports.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import { DirEntry, Rule, UpdateRecorder } from '@angular-devkit/schematics'; | ||
import * as ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript'; | ||
|
||
function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> { | ||
for (const path of directory.subfiles) { | ||
if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { | ||
const entry = directory.file(path); | ||
if (entry) { | ||
const content = entry.content; | ||
if (content.includes('@angular/platform-server') && content.includes('renderModule')) { | ||
const source = ts.createSourceFile( | ||
entry.path, | ||
content.toString().replace(/^\uFEFF/, ''), | ||
ts.ScriptTarget.Latest, | ||
true, | ||
); | ||
|
||
yield source; | ||
} | ||
} | ||
} | ||
} | ||
|
||
for (const path of directory.subdirs) { | ||
if (path === 'node_modules' || path.startsWith('.')) { | ||
continue; | ||
} | ||
|
||
yield* visit(directory.dir(path)); | ||
} | ||
} | ||
|
||
export default function (): Rule { | ||
return (tree) => { | ||
for (const sourceFile of visit(tree.root)) { | ||
let recorder: UpdateRecorder | undefined; | ||
let printer: ts.Printer | undefined; | ||
|
||
ts.forEachChild(sourceFile, function analyze(node) { | ||
if ( | ||
!( | ||
ts.isExportDeclaration(node) && | ||
node.moduleSpecifier && | ||
ts.isStringLiteral(node.moduleSpecifier) && | ||
node.moduleSpecifier.text === '@angular/platform-server' && | ||
node.exportClause && | ||
ts.isNamedExports(node.exportClause) | ||
) | ||
) { | ||
// Not a @angular/platform-server named export. | ||
return; | ||
} | ||
|
||
const exportClause = node.exportClause; | ||
const newElements: ts.ExportSpecifier[] = []; | ||
for (const element of exportClause.elements) { | ||
if (element.name.text !== 'renderModule') { | ||
newElements.push(element); | ||
} | ||
} | ||
|
||
if (newElements.length === exportClause.elements.length) { | ||
// No changes | ||
return; | ||
} | ||
|
||
recorder ??= tree.beginUpdate(sourceFile.fileName); | ||
|
||
if (newElements.length) { | ||
// Update named exports as there are leftovers. | ||
const newExportClause = ts.factory.updateNamedExports(exportClause, newElements); | ||
printer ??= ts.createPrinter(); | ||
const fix = printer.printNode(ts.EmitHint.Unspecified, newExportClause, sourceFile); | ||
|
||
const index = exportClause.getStart(); | ||
const length = exportClause.getWidth(); | ||
recorder.remove(index, length).insertLeft(index, fix); | ||
} else { | ||
// Delete export as no exports remain. | ||
recorder.remove(node.getStart(), node.getWidth()); | ||
} | ||
|
||
ts.forEachChild(node, analyze); | ||
}); | ||
|
||
if (recorder) { | ||
tree.commitUpdate(recorder); | ||
} | ||
} | ||
}; | ||
} |
85 changes: 85 additions & 0 deletions
85
packages/schematics/angular/migrations/update-15/remove-platform-server-exports_spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import { EmptyTree } from '@angular-devkit/schematics'; | ||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; | ||
|
||
describe('Migration to delete platform-server exports', () => { | ||
const schematicName = 'remove-platform-server-exports'; | ||
|
||
const schematicRunner = new SchematicTestRunner( | ||
'migrations', | ||
require.resolve('../migration-collection.json'), | ||
); | ||
|
||
let tree: EmptyTree; | ||
|
||
beforeEach(() => { | ||
tree = new EmptyTree(); | ||
}); | ||
|
||
const testTypeScriptFilePath = './test.ts'; | ||
|
||
describe(`Migration to remove '@angular/platform-server' exports`, () => { | ||
it(`should delete '@angular/platform-server' export when 'renderModule' is the only exported symbol`, async () => { | ||
tree.create( | ||
testTypeScriptFilePath, | ||
` | ||
import { Path, join } from '@angular-devkit/core'; | ||
export { renderModule } from '@angular/platform-server'; | ||
`, | ||
); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const content = newTree.readText(testTypeScriptFilePath); | ||
expect(content).not.toContain('@angular/platform-server'); | ||
expect(content).toContain(`import { Path, join } from '@angular-devkit/core';`); | ||
}); | ||
|
||
it(`should delete only 'renderModule' when there are additional exports`, async () => { | ||
tree.create( | ||
testTypeScriptFilePath, | ||
` | ||
import { Path, join } from '@angular-devkit/core'; | ||
export { renderModule, ServerModule } from '@angular/platform-server'; | ||
`, | ||
); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const content = newTree.readContent(testTypeScriptFilePath); | ||
expect(content).toContain(`import { Path, join } from '@angular-devkit/core';`); | ||
expect(content).toContain(`export { ServerModule } from '@angular/platform-server';`); | ||
}); | ||
|
||
it(`should not delete 'renderModule' when it's exported from another module`, async () => { | ||
tree.create( | ||
testTypeScriptFilePath, | ||
` | ||
export { renderModule } from '@angular/core'; | ||
`, | ||
); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const content = newTree.readText(testTypeScriptFilePath); | ||
expect(content).toContain(`export { renderModule } from '@angular/core';`); | ||
}); | ||
|
||
it(`should not delete 'renderModule' when it's imported from '@angular/platform-server'`, async () => { | ||
tree.create( | ||
testTypeScriptFilePath, | ||
` | ||
import { renderModule } from '@angular/platform-server'; | ||
`, | ||
); | ||
|
||
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); | ||
const content = newTree.readText(testTypeScriptFilePath); | ||
expect(content).toContain(`import { renderModule } from '@angular/platform-server'`); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters