mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(compiler): pass more information to HMR replacement function (#59854)
Adjusts the code we generate for HMR so that it passes in the HMR ID and `import.meta` to the `replaceMetadata` call. This is necessary so we can do better logging of errors. PR Close #59854
This commit is contained in:
committed by
Andrew Scott
parent
27c39f5a8a
commit
6e999300a7
@@ -104,18 +104,19 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain(`import * as i0 from "@angular/core";`);
|
||||
expect(jsContents).toContain('const id = "test.ts%40Cmp";');
|
||||
expect(jsContents).toContain('function Cmp_HmrLoad(t) {');
|
||||
expect(jsContents).toContain(
|
||||
'import(/* @vite-ignore */\nnew URL("./@ng/component?c=test.ts%40Cmp&t=" + encodeURIComponent(t), import.meta.url).href)',
|
||||
'import(/* @vite-ignore */\nnew URL("./@ng/component?c=" + id + "&t=" + encodeURIComponent(t), import.meta.url).href)',
|
||||
);
|
||||
expect(jsContents).toContain(
|
||||
').then(m => m.default && i0.ɵɵreplaceMetadata(Cmp, m.default, [i0], ' +
|
||||
'[Dep, transformValue, TOKEN, Component, Inject, ViewChild, Input]));',
|
||||
'[Dep, transformValue, TOKEN, Component, Inject, ViewChild, Input], import.meta, id));',
|
||||
);
|
||||
expect(jsContents).toContain('Cmp_HmrLoad(Date.now());');
|
||||
expect(jsContents).toContain(
|
||||
'import.meta.hot && import.meta.hot.on("angular:component-update", ' +
|
||||
'd => d.id === "test.ts%40Cmp" && Cmp_HmrLoad(d.timestamp)',
|
||||
'd => d.id === id && Cmp_HmrLoad(d.timestamp)',
|
||||
);
|
||||
|
||||
expect(hmrContents).toContain(
|
||||
@@ -171,18 +172,19 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
expect(jsContents).toContain(`import * as i0 from "@angular/core";`);
|
||||
expect(jsContents).toContain(`import * as i1 from "./dep";`);
|
||||
expect(jsContents).toContain('const id = "test.ts%40Cmp";');
|
||||
expect(jsContents).toContain('function Cmp_HmrLoad(t) {');
|
||||
expect(jsContents).toContain(
|
||||
'import(/* @vite-ignore */\nnew URL("./@ng/component?c=test.ts%40Cmp&t=" + encodeURIComponent(t), import.meta.url).href)',
|
||||
'import(/* @vite-ignore */\nnew URL("./@ng/component?c=" + id + "&t=" + encodeURIComponent(t), import.meta.url).href)',
|
||||
);
|
||||
expect(jsContents).toContain(
|
||||
').then(m => m.default && i0.ɵɵreplaceMetadata(Cmp, m.default, [i0, i1], ' +
|
||||
'[DepModule, Component]));',
|
||||
'[DepModule, Component], import.meta, id));',
|
||||
);
|
||||
expect(jsContents).toContain('Cmp_HmrLoad(Date.now());');
|
||||
expect(jsContents).toContain(
|
||||
'import.meta.hot && import.meta.hot.on("angular:component-update", ' +
|
||||
'd => d.id === "test.ts%40Cmp" && Cmp_HmrLoad(d.timestamp)',
|
||||
'd => d.id === id && Cmp_HmrLoad(d.timestamp)',
|
||||
);
|
||||
|
||||
expect(hmrContents).toContain(
|
||||
@@ -340,7 +342,9 @@ runInEachFileSystem(() => {
|
||||
expect(jsContents).toContain('const Cmp_Defer_1_DepsFn = () => [Dep];');
|
||||
expect(jsContents).toContain('function Cmp_Defer_0_Template(rf, ctx) { if (rf & 1) {');
|
||||
expect(jsContents).toContain('i0.ɵɵdefer(1, 0, Cmp_Defer_1_DepsFn);');
|
||||
expect(jsContents).toContain('ɵɵreplaceMetadata(Cmp, m.default, [i0], [Dep]));');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [Dep], import.meta, id));',
|
||||
);
|
||||
expect(jsContents).not.toContain('setClassMetadata');
|
||||
|
||||
expect(hmrContents).toContain(
|
||||
@@ -422,7 +426,9 @@ runInEachFileSystem(() => {
|
||||
const jsContents = env.getContents('test.js');
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
expect(jsContents).toContain('dependencies: [Cmp]');
|
||||
expect(jsContents).toContain('ɵɵreplaceMetadata(Cmp, m.default, [i0], [Component]));');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, Component) {',
|
||||
);
|
||||
@@ -445,7 +451,9 @@ runInEachFileSystem(() => {
|
||||
const jsContents = env.getContents('test.js');
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
expect(jsContents).not.toContain('dependencies');
|
||||
expect(jsContents).toContain('ɵɵreplaceMetadata(Cmp, m.default, [i0], [Component]));');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, Component) {',
|
||||
);
|
||||
@@ -471,7 +479,7 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [providers, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [providers, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, providers, Component) {',
|
||||
@@ -508,7 +516,7 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, token, value, Component) {',
|
||||
@@ -542,7 +550,7 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, token, value, Component) {',
|
||||
@@ -574,7 +582,7 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [condition, providersA, providersB, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [condition, providersA, providersB, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, condition, providersA, providersB, Component) {',
|
||||
@@ -608,7 +616,7 @@ runInEachFileSystem(() => {
|
||||
const jsContents = env.getContents('test.js');
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, otherValue, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, otherValue, Component], import.meta, id));',
|
||||
);
|
||||
expect(jsContents).toContain('useFactory: () => [(value), ((((otherValue))))]');
|
||||
expect(hmrContents).toContain(
|
||||
@@ -646,7 +654,7 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, Optional, dep, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, value, Optional, dep, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, token, value, Optional, dep, Component) {',
|
||||
@@ -697,7 +705,9 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain('dependencies: [Dep]');
|
||||
expect(jsContents).toContain('ɵɵreplaceMetadata(Cmp, m.default, [i0], [Dep]));');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [Dep], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain('function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, Dep) {');
|
||||
});
|
||||
|
||||
@@ -741,7 +751,9 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain('dependencies: [DepModule, i1.Dep]');
|
||||
expect(jsContents).toContain('ɵɵreplaceMetadata(Cmp, m.default, [i0, i1], [DepModule]));');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0, i1], [DepModule], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain('function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, DepModule) {');
|
||||
});
|
||||
|
||||
@@ -797,7 +809,9 @@ runInEachFileSystem(() => {
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
|
||||
expect(jsContents).toContain('dependencies: [i1.Dep]');
|
||||
expect(jsContents).toContain('ɵɵreplaceMetadata(Cmp, m.default, [i0, i1], []));');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0, i1], [], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain('function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces) {');
|
||||
});
|
||||
|
||||
@@ -834,7 +848,7 @@ runInEachFileSystem(() => {
|
||||
const jsContents = env.getContents('test.js');
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, { one: 0, two: "2", three: 3 }, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, { one: 0, two: "2", three: 3 }, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, token, Foo, Component) {',
|
||||
@@ -881,7 +895,7 @@ runInEachFileSystem(() => {
|
||||
const jsContents = env.getContents('test.js');
|
||||
const hmrContents = env.driveHmr('test.ts', 'Cmp');
|
||||
expect(jsContents).toContain(
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, { one: 0, two: "2", three: 3 }, Component]));',
|
||||
'ɵɵreplaceMetadata(Cmp, m.default, [i0], [token, { one: 0, two: "2", three: 3 }, Component], import.meta, id));',
|
||||
);
|
||||
expect(hmrContents).toContain(
|
||||
'export default function Cmp_UpdateMetadata(Cmp, ɵɵnamespaces, token, Foo, Component) {',
|
||||
|
||||
@@ -53,11 +53,10 @@ export interface R3HmrNamespaceDependency {
|
||||
* @param meta HMR metadata extracted from the class.
|
||||
*/
|
||||
export function compileHmrInitializer(meta: R3HmrMetadata): o.Expression {
|
||||
const id = encodeURIComponent(`${meta.filePath}@${meta.className}`);
|
||||
const urlPartial = `./@ng/component?c=${id}&t=`;
|
||||
const moduleName = 'm';
|
||||
const dataName = 'd';
|
||||
const timestampName = 't';
|
||||
const idName = 'id';
|
||||
const importCallbackName = `${meta.className}_HmrLoad`;
|
||||
const namespaces = meta.namespaceDependencies.map((dep) => {
|
||||
return new o.ExternalExpr({moduleName: dep.moduleName, name: null});
|
||||
@@ -66,7 +65,7 @@ export function compileHmrInitializer(meta: R3HmrMetadata): o.Expression {
|
||||
// m.default
|
||||
const defaultRead = o.variable(moduleName).prop('default');
|
||||
|
||||
// ɵɵreplaceMetadata(Comp, m.default, [...namespaces], [...locals]);
|
||||
// ɵɵreplaceMetadata(Comp, m.default, [...namespaces], [...locals], import.meta, id);
|
||||
const replaceCall = o
|
||||
.importExpr(R3.replaceMetadata)
|
||||
.callFn([
|
||||
@@ -74,14 +73,18 @@ export function compileHmrInitializer(meta: R3HmrMetadata): o.Expression {
|
||||
defaultRead,
|
||||
o.literalArr(namespaces),
|
||||
o.literalArr(meta.localDependencies.map((l) => l.runtimeRepresentation)),
|
||||
o.variable('import').prop('meta'),
|
||||
o.variable(idName),
|
||||
]);
|
||||
|
||||
// (m) => m.default && ɵɵreplaceMetadata(...)
|
||||
const replaceCallback = o.arrowFn([new o.FnParam(moduleName)], defaultRead.and(replaceCall));
|
||||
|
||||
// '<urlPartial>' + encodeURIComponent(t)
|
||||
// '<url>?c=' + id + '&t=' + encodeURIComponent(t)
|
||||
const urlValue = o
|
||||
.literal(urlPartial)
|
||||
.literal(`./@ng/component?c=`)
|
||||
.plus(o.variable(idName))
|
||||
.plus(o.literal('&t='))
|
||||
.plus(o.variable('encodeURIComponent').callFn([o.variable(timestampName)]));
|
||||
|
||||
// import.meta.url
|
||||
@@ -109,13 +112,13 @@ export function compileHmrInitializer(meta: R3HmrMetadata): o.Expression {
|
||||
o.StmtModifier.Final,
|
||||
);
|
||||
|
||||
// (d) => d.id === <id> && Cmp_HmrLoad(d.timestamp)
|
||||
// (d) => d.id === id && Cmp_HmrLoad(d.timestamp)
|
||||
const updateCallback = o.arrowFn(
|
||||
[new o.FnParam(dataName)],
|
||||
o
|
||||
.variable(dataName)
|
||||
.prop('id')
|
||||
.identical(o.literal(id))
|
||||
.identical(o.variable(idName))
|
||||
.and(o.variable(importCallbackName).callFn([o.variable(dataName).prop('timestamp')])),
|
||||
);
|
||||
|
||||
@@ -139,6 +142,13 @@ export function compileHmrInitializer(meta: R3HmrMetadata): o.Expression {
|
||||
.arrowFn(
|
||||
[],
|
||||
[
|
||||
// const id = <id>;
|
||||
new o.DeclareVarStmt(
|
||||
idName,
|
||||
o.literal(encodeURIComponent(`${meta.filePath}@${meta.className}`)),
|
||||
null,
|
||||
o.StmtModifier.Final,
|
||||
),
|
||||
// function Cmp_HmrLoad() {...}.
|
||||
importCallback,
|
||||
// ngDevMode && Cmp_HmrLoad(Date.now());
|
||||
|
||||
@@ -51,6 +51,8 @@ import {NG_COMP_DEF} from './fields';
|
||||
* @param applyMetadata Callback that will apply a new set of metadata on the `type` when invoked.
|
||||
* @param environment Syntehtic namespace imports that need to be passed along to the callback.
|
||||
* @param locals Local symbols from the source location that have to be exposed to the callback.
|
||||
* @param id ID to the class being replaced. **Not** the same as the component definition ID.
|
||||
* Optional since the ID might not be available internally.
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵreplaceMetadata(
|
||||
@@ -58,6 +60,7 @@ export function ɵɵreplaceMetadata(
|
||||
applyMetadata: (...args: [Type<unknown>, unknown[], ...unknown[]]) => void,
|
||||
namespaces: unknown[],
|
||||
locals: unknown[],
|
||||
id: string | null = null,
|
||||
) {
|
||||
ngDevMode && assertComponentDef(type);
|
||||
const currentDef = getComponentDef(type)!;
|
||||
|
||||
@@ -2157,6 +2157,7 @@ describe('hot module replacement', () => {
|
||||
},
|
||||
[angularCoreEnv],
|
||||
[],
|
||||
'',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user