diff --git a/packages/angular/build/src/utils/index-file/index-html-generator.ts b/packages/angular/build/src/utils/index-file/index-html-generator.ts index bf40e2e7acac..3e7cdb167ced 100644 --- a/packages/angular/build/src/utils/index-file/index-html-generator.ts +++ b/packages/angular/build/src/utils/index-file/index-html-generator.ts @@ -14,6 +14,7 @@ import { addEventDispatchContract } from './add-event-dispatch-contract'; import { CrossOriginValue, Entrypoint, FileInfo, augmentIndexHtml } from './augment-index-html'; import { InlineCriticalCssProcessor } from './inline-critical-css'; import { InlineFontsProcessor } from './inline-fonts'; +import { addNgcmAttribute } from './ngcm-attribute'; import { addNonce } from './nonce'; type IndexHtmlGeneratorPlugin = ( @@ -82,6 +83,7 @@ export class IndexHtmlGenerator { // SSR plugins if (options.generateDedicatedSSRContent) { + this.csrPlugins.push(addNgcmAttributePlugin()); this.ssrPlugins.push(addEventDispatchContractPlugin(), addNoncePlugin()); } } @@ -203,3 +205,7 @@ function postTransformPlugin({ options }: IndexHtmlGenerator): IndexHtmlGenerato function addEventDispatchContractPlugin(): IndexHtmlGeneratorPlugin { return (html) => addEventDispatchContract(html); } + +function addNgcmAttributePlugin(): IndexHtmlGeneratorPlugin { + return (html) => addNgcmAttribute(html); +} diff --git a/packages/angular/build/src/utils/index-file/ngcm-attribute.ts b/packages/angular/build/src/utils/index-file/ngcm-attribute.ts new file mode 100644 index 000000000000..af74778915e6 --- /dev/null +++ b/packages/angular/build/src/utils/index-file/ngcm-attribute.ts @@ -0,0 +1,42 @@ +/** + * @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 { htmlRewritingStream } from './html-rewriting-stream'; + +/** + * Defines a name of an attribute that is added to the `
` tag + * in the `index.html` file in case a given route was configured + * with `RenderMode.Client`. 'cm' is an abbreviation for "Client Mode". + * + * @see https://github.com/angular/angular/pull/58004 + */ +const CLIENT_RENDER_MODE_FLAG = 'ngcm'; + +/** + * Transforms the provided HTML by adding the `ngcm` attribute to the `` tag. + * This is used in the client-side rendered (CSR) version of `index.html` to prevent hydration warnings. + * + * @param html The HTML markup to be transformed. + * @returns A promise that resolves to the transformed HTML string with the necessary modifications. + */ +export async function addNgcmAttribute(html: string): Promisehello world!
+ + `); + + expect(result).toContain('hello world!
'); + }); + + it('should not override an existing ngcm attribute', async () => { + const result = await addNgcmAttribute(` + + +hello world!
+ + `); + + expect(result).toContain('hello world!
'); + }); +});