mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
fix(core): make component id generation more stable between client and server builds (#58813)
For components with i18n in templates, the `consts` array is generated by the compiler as a function. If client and server bundles were produced with different minification configurations, the serializable contents of the function body would be different on the client and on the server. This might result in different ids generated. To avoid this issue, this commit updates the logic to not take the `consts` contents into account if it's a function. Resolves #58713. PR Close #58813
This commit is contained in:
parent
4f2df5bcb5
commit
834c7c3ccc
1 changed files with 25 additions and 4 deletions
|
|
@ -13,6 +13,7 @@ import {Type, Writable} from '../interface/type';
|
|||
import {NgModuleDef} from '../metadata/ng_module_def';
|
||||
import {SchemaMetadata} from '../metadata/schema';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {assertNotEqual} from '../util/assert';
|
||||
import {noSideEffects} from '../util/closure';
|
||||
import {EMPTY_ARRAY, EMPTY_OBJ} from '../util/empty';
|
||||
import {initNgDevMode} from '../util/ng_dev_mode';
|
||||
|
|
@ -688,6 +689,14 @@ export const GENERATED_COMP_IDS = new Map<string, Type<unknown>>();
|
|||
function getComponentId<T>(componentDef: ComponentDef<T>): string {
|
||||
let hash = 0;
|
||||
|
||||
// For components with i18n in templates, the `consts` array is generated by the compiler
|
||||
// as a function. If client and server bundles were produced with different minification
|
||||
// configurations, the serializable contents of the function body would be different on
|
||||
// the client and on the server. This might result in different ids generated. To avoid this
|
||||
// issue, we do not take the `consts` contents into account if it's a function.
|
||||
// See https://github.com/angular/angular/issues/58713.
|
||||
const componentDefConsts = typeof componentDef.consts === 'function' ? '' : componentDef.consts;
|
||||
|
||||
// We cannot rely solely on the component selector as the same selector can be used in different
|
||||
// modules.
|
||||
//
|
||||
|
|
@ -697,13 +706,12 @@ function getComponentId<T>(componentDef: ComponentDef<T>): string {
|
|||
// Example:
|
||||
// https://github.com/angular/components/blob/d9f82c8f95309e77a6d82fd574c65871e91354c2/src/material/core/option/option.ts#L248
|
||||
// https://github.com/angular/components/blob/285f46dc2b4c5b127d356cb7c4714b221f03ce50/src/material/legacy-core/option/option.ts#L32
|
||||
|
||||
const hashSelectors = [
|
||||
componentDef.selectors,
|
||||
componentDef.ngContentSelectors,
|
||||
componentDef.hostVars,
|
||||
componentDef.hostAttrs,
|
||||
componentDef.consts,
|
||||
componentDefConsts,
|
||||
componentDef.vars,
|
||||
componentDef.decls,
|
||||
componentDef.encapsulation,
|
||||
|
|
@ -717,9 +725,22 @@ function getComponentId<T>(componentDef: ComponentDef<T>): string {
|
|||
Object.getOwnPropertyNames(componentDef.type.prototype),
|
||||
!!componentDef.contentQueries,
|
||||
!!componentDef.viewQuery,
|
||||
].join('|');
|
||||
];
|
||||
|
||||
for (const char of hashSelectors) {
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
// If client and server bundles were produced with different minification configurations,
|
||||
// the serializable contents of the function body would be different on the client and on
|
||||
// the server. Ensure that we do not accidentally use functions in component id computation.
|
||||
for (const item of hashSelectors) {
|
||||
assertNotEqual(
|
||||
typeof item,
|
||||
'function',
|
||||
'Internal error: attempting to use a function in component id computation logic.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const char of hashSelectors.join('|')) {
|
||||
hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue