mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 11:03:53 +08:00
feat(@angular/ssr): move CommonEngine
API to /node
entry-point
Refactored the `CommonEngine` API import path to remove Node.js dependencies from the `@angular/ssr` main entry-point. BREAKING CHANGE: The `CommonEngine` API now needs to be imported from `@angular/ssr/node`. **Before** ```ts import { CommonEngine } from '@angular/ssr'; ``` **After** ```ts import { CommonEngine } from '@angular/ssr/node'; ```
This commit is contained in:
parent
ac6935db26
commit
4b09887a9c
@ -4,37 +4,6 @@
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
|
||||||
import { ApplicationRef } from '@angular/core';
|
|
||||||
import { StaticProvider } from '@angular/core';
|
|
||||||
import { Type } from '@angular/core';
|
|
||||||
|
|
||||||
// @public
|
|
||||||
export class CommonEngine {
|
|
||||||
constructor(options?: CommonEngineOptions | undefined);
|
|
||||||
render(opts: CommonEngineRenderOptions): Promise<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export interface CommonEngineOptions {
|
|
||||||
bootstrap?: Type<{}> | (() => Promise<ApplicationRef>);
|
|
||||||
enablePerformanceProfiler?: boolean;
|
|
||||||
providers?: StaticProvider[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export interface CommonEngineRenderOptions {
|
|
||||||
bootstrap?: Type<{}> | (() => Promise<ApplicationRef>);
|
|
||||||
// (undocumented)
|
|
||||||
document?: string;
|
|
||||||
// (undocumented)
|
|
||||||
documentFilePath?: string;
|
|
||||||
inlineCriticalCss?: boolean;
|
|
||||||
providers?: StaticProvider[];
|
|
||||||
publicPath?: string;
|
|
||||||
// (undocumented)
|
|
||||||
url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
40
goldens/public-api/angular/ssr/node/index.api.md
Normal file
40
goldens/public-api/angular/ssr/node/index.api.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
## API Report File for "@angular/ssr_node"
|
||||||
|
|
||||||
|
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||||
|
|
||||||
|
```ts
|
||||||
|
|
||||||
|
import { ApplicationRef } from '@angular/core';
|
||||||
|
import { StaticProvider } from '@angular/core';
|
||||||
|
import { Type } from '@angular/core';
|
||||||
|
|
||||||
|
// @public
|
||||||
|
export class CommonEngine {
|
||||||
|
constructor(options?: CommonEngineOptions | undefined);
|
||||||
|
render(opts: CommonEngineRenderOptions): Promise<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface CommonEngineOptions {
|
||||||
|
bootstrap?: Type<{}> | (() => Promise<ApplicationRef>);
|
||||||
|
enablePerformanceProfiler?: boolean;
|
||||||
|
providers?: StaticProvider[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface CommonEngineRenderOptions {
|
||||||
|
bootstrap?: Type<{}> | (() => Promise<ApplicationRef>);
|
||||||
|
// (undocumented)
|
||||||
|
document?: string;
|
||||||
|
// (undocumented)
|
||||||
|
documentFilePath?: string;
|
||||||
|
inlineCriticalCss?: boolean;
|
||||||
|
providers?: StaticProvider[];
|
||||||
|
publicPath?: string;
|
||||||
|
// (undocumented)
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
|
```
|
@ -44,6 +44,7 @@ ng_package(
|
|||||||
tags = ["release-package"],
|
tags = ["release-package"],
|
||||||
deps = [
|
deps = [
|
||||||
":ssr",
|
":ssr",
|
||||||
|
"//packages/angular/ssr/node",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
20
packages/angular/ssr/node/BUILD.bazel
Normal file
20
packages/angular/ssr/node/BUILD.bazel
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
load("//tools:defaults.bzl", "ts_library")
|
||||||
|
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
ts_library(
|
||||||
|
name = "node",
|
||||||
|
srcs = glob(
|
||||||
|
[
|
||||||
|
"*.ts",
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
module_name = "@angular/ssr/node",
|
||||||
|
deps = [
|
||||||
|
"//packages/angular/ssr",
|
||||||
|
"@npm//@angular/core",
|
||||||
|
"@npm//@angular/platform-server",
|
||||||
|
"@npm//@types/node",
|
||||||
|
],
|
||||||
|
)
|
9
packages/angular/ssr/node/index.ts
Normal file
9
packages/angular/ssr/node/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @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.dev/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './public_api';
|
13
packages/angular/ssr/node/public_api.ts
Normal file
13
packages/angular/ssr/node/public_api.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @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.dev/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {
|
||||||
|
CommonEngine,
|
||||||
|
type CommonEngineRenderOptions,
|
||||||
|
type CommonEngineOptions,
|
||||||
|
} from './src/common-engine/common-engine';
|
@ -6,8 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.dev/license
|
* found in the LICENSE file at https://angular.dev/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ɵInlineCriticalCssProcessor as InlineCriticalCssProcessor } from '@angular/ssr';
|
||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import { InlineCriticalCssProcessor } from '../utils/inline-critical-css';
|
|
||||||
|
|
||||||
export class CommonEngineInlineCriticalCssProcessor {
|
export class CommonEngineInlineCriticalCssProcessor {
|
||||||
private readonly resourceCache = new Map<string, string>();
|
private readonly resourceCache = new Map<string, string>();
|
@ -16,3 +16,5 @@ export {
|
|||||||
setAngularAppManifest as ɵsetAngularAppManifest,
|
setAngularAppManifest as ɵsetAngularAppManifest,
|
||||||
setAngularAppEngineManifest as ɵsetAngularAppEngineManifest,
|
setAngularAppEngineManifest as ɵsetAngularAppEngineManifest,
|
||||||
} from './src/manifest';
|
} from './src/manifest';
|
||||||
|
|
||||||
|
export { InlineCriticalCssProcessor as ɵInlineCriticalCssProcessor } from './src/utils/inline-critical-css';
|
||||||
|
@ -6,10 +6,4 @@
|
|||||||
* found in the LICENSE file at https://angular.dev/license
|
* found in the LICENSE file at https://angular.dev/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {
|
|
||||||
CommonEngine,
|
|
||||||
type CommonEngineRenderOptions,
|
|
||||||
type CommonEngineOptions,
|
|
||||||
} from './src/common-engine/common-engine';
|
|
||||||
|
|
||||||
export * from './private_export';
|
export * from './private_export';
|
||||||
|
@ -365,7 +365,7 @@ LARGE_SPECS = {
|
|||||||
"@npm//browser-sync",
|
"@npm//browser-sync",
|
||||||
"@npm//express",
|
"@npm//express",
|
||||||
"@npm//undici",
|
"@npm//undici",
|
||||||
"//packages/angular/ssr",
|
"//packages/angular/ssr/node",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ describe('Serve SSR Builder', () => {
|
|||||||
'src/main.server.ts': `
|
'src/main.server.ts': `
|
||||||
import 'zone.js/node';
|
import 'zone.js/node';
|
||||||
|
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import { resolve, join } from 'node:path';
|
import { resolve, join } from 'node:path';
|
||||||
import { AppServerModule } from './app/app.module.server';
|
import { AppServerModule } from './app/app.module.server';
|
||||||
|
@ -25,7 +25,7 @@ describe('Serve SSR Builder', () => {
|
|||||||
'src/main.server.ts': `
|
'src/main.server.ts': `
|
||||||
import 'zone.js/node';
|
import 'zone.js/node';
|
||||||
|
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import { resolve, join } from 'node:path';
|
import { resolve, join } from 'node:path';
|
||||||
import { AppServerModule } from './app/app.module.server';
|
import { AppServerModule } from './app/app.module.server';
|
||||||
|
@ -24,7 +24,7 @@ describe('Serve SSR Builder', () => {
|
|||||||
'src/main.server.ts': `
|
'src/main.server.ts': `
|
||||||
import 'zone.js/node';
|
import 'zone.js/node';
|
||||||
|
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import { resolve, join } from 'node:path';
|
import { resolve, join } from 'node:path';
|
||||||
import { AppServerModule } from './app/app.module.server';
|
import { AppServerModule } from './app/app.module.server';
|
||||||
|
@ -11,6 +11,11 @@
|
|||||||
"version": "19.0.0",
|
"version": "19.0.0",
|
||||||
"factory": "./update-workspace-config/migration",
|
"factory": "./update-workspace-config/migration",
|
||||||
"description": "Update the workspace configuration by replacing deprecated options in 'angular.json' for compatibility with the latest Angular CLI changes."
|
"description": "Update the workspace configuration by replacing deprecated options in 'angular.json' for compatibility with the latest Angular CLI changes."
|
||||||
|
},
|
||||||
|
"update-ssr-imports": {
|
||||||
|
"version": "19.0.0",
|
||||||
|
"factory": "./update-ssr-imports/migration",
|
||||||
|
"description": "Update '@angular/ssr' import paths to use the new '/node' entry point when 'CommonEngine' is detected."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* @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.dev/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('CommonEngine') && !content.includes('@angular/ssr/node')) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schematics rule that identifies and updates import declarations in TypeScript files.
|
||||||
|
* Specifically, it modifies imports of '@angular/ssr' by appending '/node' if the
|
||||||
|
* `CommonEngine` is used from the old entry point.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export default function (): Rule {
|
||||||
|
return (tree) => {
|
||||||
|
for (const sourceFile of visit(tree.root)) {
|
||||||
|
let recorder: UpdateRecorder | undefined;
|
||||||
|
|
||||||
|
const allImportDeclarations = sourceFile.statements.filter((n) => ts.isImportDeclaration(n));
|
||||||
|
if (allImportDeclarations.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssrImports = allImportDeclarations.filter(
|
||||||
|
(n) => ts.isStringLiteral(n.moduleSpecifier) && n.moduleSpecifier.text === '@angular/ssr',
|
||||||
|
);
|
||||||
|
for (const ssrImport of ssrImports) {
|
||||||
|
const ssrNamedBinding = getNamedImports(ssrImport);
|
||||||
|
if (ssrNamedBinding) {
|
||||||
|
const isUsingOldEntryPoint = ssrNamedBinding.elements.some((e) =>
|
||||||
|
e.name.text.startsWith('CommonEngine'),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isUsingOldEntryPoint) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
recorder ??= tree.beginUpdate(sourceFile.fileName);
|
||||||
|
recorder.insertRight(ssrImport.moduleSpecifier.getEnd() - 1, '/node');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recorder) {
|
||||||
|
tree.commitUpdate(recorder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNamedImports(
|
||||||
|
importDeclaration: ts.ImportDeclaration | undefined,
|
||||||
|
): ts.NamedImports | undefined {
|
||||||
|
const namedBindings = importDeclaration?.importClause?.namedBindings;
|
||||||
|
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
||||||
|
return namedBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* @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.dev/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { tags } from '@angular-devkit/core';
|
||||||
|
import { EmptyTree } from '@angular-devkit/schematics';
|
||||||
|
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
||||||
|
|
||||||
|
describe('CommonEngine migration', () => {
|
||||||
|
const schematicRunner = new SchematicTestRunner(
|
||||||
|
'migrations',
|
||||||
|
require.resolve('../migration-collection.json'),
|
||||||
|
);
|
||||||
|
|
||||||
|
let tree: UnitTestTree;
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = new UnitTestTree(new EmptyTree());
|
||||||
|
});
|
||||||
|
|
||||||
|
function runMigration(): Promise<UnitTestTree> {
|
||||||
|
return schematicRunner.runSchematic('update-ssr-imports', {}, tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
it(`should replace 'CommonEngine*' imports from '@angular/ssr' to '@angular/ssr/node'`, async () => {
|
||||||
|
tree.create(
|
||||||
|
'/index.ts',
|
||||||
|
tags.stripIndents`
|
||||||
|
import { CommonEngine } from '@angular/ssr';
|
||||||
|
import type { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr';
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const newTree = await runMigration();
|
||||||
|
expect(newTree.readContent('/index.ts')).toBe(tags.stripIndents`
|
||||||
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
|
import type { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr/node';
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should not replace 'CommonEngine*' imports from '@angular/ssr/node'`, async () => {
|
||||||
|
const input = tags.stripIndents`
|
||||||
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
|
import type { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr/node';
|
||||||
|
`;
|
||||||
|
|
||||||
|
tree.create('/index.ts', input);
|
||||||
|
|
||||||
|
const newTree = await runMigration();
|
||||||
|
expect(newTree.readContent('/index.ts')).toBe(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should not replace 'CommonEngine*' imports from other package`, async () => {
|
||||||
|
const input = tags.stripIndents`
|
||||||
|
import { CommonEngine } from 'unknown';
|
||||||
|
import type { CommonEngineOptions, CommonEngineRenderOptions } from 'unknown';
|
||||||
|
`;
|
||||||
|
|
||||||
|
tree.create('/index.ts', input);
|
||||||
|
|
||||||
|
const newTree = await runMigration();
|
||||||
|
expect(newTree.readContent('/index.ts')).toBe(input);
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,5 @@
|
|||||||
import { APP_BASE_HREF } from '@angular/common';
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname, join, resolve } from 'node:path';
|
import { dirname, join, resolve } from 'node:path';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'zone.js/node';
|
import 'zone.js/node';
|
||||||
|
|
||||||
import { APP_BASE_HREF } from '@angular/common';
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'zone.js/node';
|
import 'zone.js/node';
|
||||||
|
|
||||||
import { APP_BASE_HREF } from '@angular/common';
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr/node';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user