Skip to content

Commit 834c7c3

Browse files
AndrewKushnirthePunderWoman
authored andcommitted
fix(core): make component id generation more stable between client and server builds (angular#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 angular#58713. PR Close angular#58813
1 parent 4f2df5b commit 834c7c3

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

packages/core/src/render3/definition.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {Type, Writable} from '../interface/type';
1313
import {NgModuleDef} from '../metadata/ng_module_def';
1414
import {SchemaMetadata} from '../metadata/schema';
1515
import {ViewEncapsulation} from '../metadata/view';
16+
import {assertNotEqual} from '../util/assert';
1617
import {noSideEffects} from '../util/closure';
1718
import {EMPTY_ARRAY, EMPTY_OBJ} from '../util/empty';
1819
import {initNgDevMode} from '../util/ng_dev_mode';
@@ -688,6 +689,14 @@ export const GENERATED_COMP_IDS = new Map<string, Type<unknown>>();
688689
function getComponentId<T>(componentDef: ComponentDef<T>): string {
689690
let hash = 0;
690691

692+
// For components with i18n in templates, the `consts` array is generated by the compiler
693+
// as a function. If client and server bundles were produced with different minification
694+
// configurations, the serializable contents of the function body would be different on
695+
// the client and on the server. This might result in different ids generated. To avoid this
696+
// issue, we do not take the `consts` contents into account if it's a function.
697+
// See https://github.com/angular/angular/issues/58713.
698+
const componentDefConsts = typeof componentDef.consts === 'function' ? '' : componentDef.consts;
699+
691700
// We cannot rely solely on the component selector as the same selector can be used in different
692701
// modules.
693702
//
@@ -697,13 +706,12 @@ function getComponentId<T>(componentDef: ComponentDef<T>): string {
697706
// Example:
698707
// https://github.com/angular/components/blob/d9f82c8f95309e77a6d82fd574c65871e91354c2/src/material/core/option/option.ts#L248
699708
// https://github.com/angular/components/blob/285f46dc2b4c5b127d356cb7c4714b221f03ce50/src/material/legacy-core/option/option.ts#L32
700-
701709
const hashSelectors = [
702710
componentDef.selectors,
703711
componentDef.ngContentSelectors,
704712
componentDef.hostVars,
705713
componentDef.hostAttrs,
706-
componentDef.consts,
714+
componentDefConsts,
707715
componentDef.vars,
708716
componentDef.decls,
709717
componentDef.encapsulation,
@@ -717,9 +725,22 @@ function getComponentId<T>(componentDef: ComponentDef<T>): string {
717725
Object.getOwnPropertyNames(componentDef.type.prototype),
718726
!!componentDef.contentQueries,
719727
!!componentDef.viewQuery,
720-
].join('|');
728+
];
729+
730+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
731+
// If client and server bundles were produced with different minification configurations,
732+
// the serializable contents of the function body would be different on the client and on
733+
// the server. Ensure that we do not accidentally use functions in component id computation.
734+
for (const item of hashSelectors) {
735+
assertNotEqual(
736+
typeof item,
737+
'function',
738+
'Internal error: attempting to use a function in component id computation logic.',
739+
);
740+
}
741+
}
721742

722-
for (const char of hashSelectors) {
743+
for (const char of hashSelectors.join('|')) {
723744
hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0;
724745
}
725746

0 commit comments

Comments
 (0)