Skip to content
Closed
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
29 changes: 25 additions & 4 deletions packages/core/src/render3/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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.
//
Expand All @@ -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,
Expand All @@ -717,9 +725,22 @@ function getComponentId<T>(componentDef: ComponentDef<T>): string {
Object.getOwnPropertyNames(componentDef.type.prototype),
!!componentDef.contentQueries,
!!componentDef.viewQuery,
].join('|');
];

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) {
for (const char of hashSelectors.join('|')) {
hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0;
}

Expand Down