mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-16 02:24:10 +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
|
||||
|
||||
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)
|
||||
|
||||
```
|
||||
|
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"],
|
||||
deps = [
|
||||
":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
|
||||
*/
|
||||
|
||||
import { ɵInlineCriticalCssProcessor as InlineCriticalCssProcessor } from '@angular/ssr';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { InlineCriticalCssProcessor } from '../utils/inline-critical-css';
|
||||
|
||||
export class CommonEngineInlineCriticalCssProcessor {
|
||||
private readonly resourceCache = new Map<string, string>();
|
@ -16,3 +16,5 @@ export {
|
||||
setAngularAppManifest as ɵsetAngularAppManifest,
|
||||
setAngularAppEngineManifest as ɵsetAngularAppEngineManifest,
|
||||
} 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
|
||||
*/
|
||||
|
||||
export {
|
||||
CommonEngine,
|
||||
type CommonEngineRenderOptions,
|
||||
type CommonEngineOptions,
|
||||
} from './src/common-engine/common-engine';
|
||||
|
||||
export * from './private_export';
|
||||
|
@ -365,7 +365,7 @@ LARGE_SPECS = {
|
||||
"@npm//browser-sync",
|
||||
"@npm//express",
|
||||
"@npm//undici",
|
||||
"//packages/angular/ssr",
|
||||
"//packages/angular/ssr/node",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ describe('Serve SSR Builder', () => {
|
||||
'src/main.server.ts': `
|
||||
import 'zone.js/node';
|
||||
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import * as express from 'express';
|
||||
import { resolve, join } from 'node:path';
|
||||
import { AppServerModule } from './app/app.module.server';
|
||||
|
@ -25,7 +25,7 @@ describe('Serve SSR Builder', () => {
|
||||
'src/main.server.ts': `
|
||||
import 'zone.js/node';
|
||||
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import * as express from 'express';
|
||||
import { resolve, join } from 'node:path';
|
||||
import { AppServerModule } from './app/app.module.server';
|
||||
|
@ -24,7 +24,7 @@ describe('Serve SSR Builder', () => {
|
||||
'src/main.server.ts': `
|
||||
import 'zone.js/node';
|
||||
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import * as express from 'express';
|
||||
import { resolve, join } from 'node:path';
|
||||
import { AppServerModule } from './app/app.module.server';
|
||||
|
@ -11,6 +11,11 @@
|
||||
"version": "19.0.0",
|
||||
"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."
|
||||
},
|
||||
"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 { CommonEngine } from '@angular/ssr';
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import express from 'express';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'zone.js/node';
|
||||
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import * as express from 'express';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'zone.js/node';
|
||||
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import * as express from 'express';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
Loading…
x
Reference in New Issue
Block a user