Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion goldens/public-api/platform-browser/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ export enum HydrationFeatureKind {
// (undocumented)
IncrementalHydration = 4,
// (undocumented)
NoHttpTransferCache = 0
NoHttpTransferCache = 0,
// (undocumented)
NoIncrementalHydration = 5
}

// @public
Expand Down Expand Up @@ -215,6 +217,9 @@ export function withIncrementalHydration(): HydrationFeature<HydrationFeatureKin
// @public
export function withNoHttpTransferCache(): HydrationFeature<HydrationFeatureKind.NoHttpTransferCache>;

// @public
export function withNoIncrementalHydration(): HydrationFeature<HydrationFeatureKind.NoIncrementalHydration>;

// (No @packageDocumentation comment for this package)

```
2 changes: 1 addition & 1 deletion integration/platform-server-hydration/size.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dist/browser/main-[hash].js": 232126,
"dist/browser/main-[hash].js": 240329,
"dist/browser/polyfills-[hash].js": 35726,
"dist/browser/event-dispatch-contract.min.js": 476
}
5 changes: 5 additions & 0 deletions packages/core/schematics/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ bundle_entrypoints = [
"can-match-snapshot-required",
"packages/core/schematics/migrations/can-match-snapshot-required/index.js",
],
[
"incremental-hydration",
"packages/core/schematics/migrations/incremental-hydration/index.js",
],
]

rollup.rollup(
Expand All @@ -147,6 +151,7 @@ rollup.rollup(
"//packages/core/schematics/migrations/can-match-snapshot-required",
"//packages/core/schematics/migrations/change-detection-eager",
"//packages/core/schematics/migrations/http-xhr-backend",
"//packages/core/schematics/migrations/incremental-hydration",
"//packages/core/schematics/migrations/strict-template",
"//packages/core/schematics/ng-generate/cleanup-unused-imports",
"//packages/core/schematics/ng-generate/common-to-standalone-migration",
Expand Down
5 changes: 5 additions & 0 deletions packages/core/schematics/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
"version": "22.0.0",
"description": "Adds the required third argument to canMatch callsites.",
"factory": "./bundles/can-match-snapshot-required.cjs#migrate"
},
"incremental-hydration": {
"version": "22.0.0",
"description": "Adds withNoIncrementalHydration() opt out to provideClientHydration() when incremental hydration is not enabled to retain pre-v22 behavior-.",
"factory": "./bundles/incremental-hydration.cjs#migrate"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("//tools:defaults.bzl", "ts_project")

package(
default_visibility = [
"//packages/core/schematics:__pkg__",
"//packages/core/schematics/test:__pkg__",
],
)

ts_project(
name = "incremental-hydration",
srcs = glob(
["**/*.ts"],
exclude = ["*.spec.ts"],
),
deps = [
"//:node_modules/@angular-devkit/schematics",
"//:node_modules/@types/node",
"//:node_modules/typescript",
"//packages/compiler-cli",
"//packages/compiler-cli/private",
"//packages/core/schematics/utils",
"//packages/core/schematics/utils/tsurge",
"//packages/core/schematics/utils/tsurge/helpers/angular_devkit",
"//packages/core/schematics/utils/tsurge/helpers/ast",
],
)
20 changes: 20 additions & 0 deletions packages/core/schematics/migrations/incremental-hydration/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @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 {Rule} from '@angular-devkit/schematics';
import {runMigrationInDevkit} from '../../utils/tsurge/helpers/angular_devkit';
import {IncrementalHydrationMigration} from './migration';

export function migrate(): Rule {
return async (tree, context) => {
await runMigrationInDevkit({
tree,
getMigration: (fs) => new IncrementalHydrationMigration(),
});
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @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 {absoluteFrom} from '@angular/compiler-cli';
import {initMockFileSystem} from '@angular/compiler-cli/private/testing';
import {runTsurgeMigration} from '../../utils/tsurge/testing';
import {IncrementalHydrationMigration} from './migration';

describe('IncrementalHydration migration', () => {
beforeEach(() => {
initMockFileSystem('Native');
});

it('should not change anything if withIncrementalHydration() is present', async () => {
const {fs} = await runTsurgeMigration(new IncrementalHydrationMigration(), [
{
name: absoluteFrom('/index.ts'),
isProgramRootFile: true,
contents: `
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';

provideClientHydration(withIncrementalHydration());
`,
},
]);

const content = fs.readFile(absoluteFrom('/index.ts'));
expect(content).not.toContain('withNoIncrementalHydration()');
expect(content).toContain('withIncrementalHydration()');
Comment thread
thePunderWoman marked this conversation as resolved.
expect(content).toContain('provideClientHydration()');
});

it('should add withNoIncrementalHydration() if withIncrementalHydration is absent', async () => {
const {fs} = await runTsurgeMigration(new IncrementalHydrationMigration(), [
{
name: absoluteFrom('/index.ts'),
isProgramRootFile: true,
contents: `
import { provideClientHydration } from '@angular/platform-browser';

provideClientHydration();
`,
},
]);

const content = fs.readFile(absoluteFrom('/index.ts'));
expect(content).toContain('withNoIncrementalHydration()');
});
});
123 changes: 123 additions & 0 deletions packages/core/schematics/migrations/incremental-hydration/migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* @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 {ImportManager} from '@angular/compiler-cli/private/migrations';
import ts from 'typescript';
import {
confirmAsSerializable,
ProgramInfo,
projectFile,
Replacement,
Serializable,
TextUpdate,
TsurgeFunnelMigration,
} from '../../utils/tsurge';
import {applyImportManagerChanges} from '../../utils/tsurge/helpers/apply_import_manager';

export interface IncrementalHydrationMigrationData {
replacements: Replacement[];
}

export class IncrementalHydrationMigration extends TsurgeFunnelMigration<
IncrementalHydrationMigrationData,
IncrementalHydrationMigrationData
> {
override async analyze(
info: ProgramInfo,
): Promise<Serializable<IncrementalHydrationMigrationData>> {
const {sourceFiles, program} = info;
const typeChecker = program.getTypeChecker();
const replacements: Replacement[] = [];
const importManager = new ImportManager();
const printer = ts.createPrinter();

for (const sf of sourceFiles) {
ts.forEachChild(sf, function visit(node: ts.Node) {
if (
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === 'provideClientHydration'
) {
let hasIncremental = false;
let incrementalArgNode: ts.CallExpression | null = null;

for (const arg of node.arguments) {
if (
ts.isCallExpression(arg) &&
ts.isIdentifier(arg.expression) &&
arg.expression.text === 'withIncrementalHydration'
) {
hasIncremental = true;
incrementalArgNode = arg;
break;
}
}

if (!hasIncremental) {
// Add withNoIncrementalHydration()
const withNoIncrementalExpr = importManager.addImport({
exportModuleSpecifier: '@angular/platform-browser',
exportSymbolName: 'withNoIncrementalHydration',
requestedFile: sf,
});

const exprText = printer.printNode(ts.EmitHint.Unspecified, withNoIncrementalExpr, sf);

const insertPos = node.arguments.end;
const toInsert = node.arguments.length > 0 ? `, ${exprText}()` : `${exprText}()`;

replacements.push(
new Replacement(
projectFile(sf, info),
new TextUpdate({
position: insertPos,
end: insertPos,
toInsert: toInsert,
}),
),
);
}
}
ts.forEachChild(node, visit);
});
}

applyImportManagerChanges(importManager, replacements, sourceFiles, info);

return confirmAsSerializable({
replacements,
});
}

override async combine(
unitA: IncrementalHydrationMigrationData,
unitB: IncrementalHydrationMigrationData,
): Promise<Serializable<IncrementalHydrationMigrationData>> {
return confirmAsSerializable({
replacements: [...unitA.replacements, ...unitB.replacements],
});
}

override async globalMeta(
combinedData: IncrementalHydrationMigrationData,
): Promise<Serializable<IncrementalHydrationMigrationData>> {
return confirmAsSerializable(combinedData);
}

override async stats(
globalMetadata: IncrementalHydrationMigrationData,
): Promise<Serializable<unknown>> {
return confirmAsSerializable({});
}

override async migrate(
globalData: IncrementalHydrationMigrationData,
): Promise<{replacements: Replacement[]}> {
return {replacements: globalData.replacements};
}
}
Loading
Loading