diff --git a/src/material/schematics/ng-update/index.ts b/src/material/schematics/ng-update/index.ts
index 52ab85b84b7e..468a25c536f7 100644
--- a/src/material/schematics/ng-update/index.ts
+++ b/src/material/schematics/ng-update/index.ts
@@ -6,12 +6,17 @@
* found in the LICENSE file at https://angular.dev/license
*/
-import {Rule, SchematicContext} from '@angular-devkit/schematics';
+import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {
+ appendHtmlElementToHead,
createMigrationSchematicRule,
+ getProjectFromWorkspace,
+ getProjectIndexFiles,
+ getWorkspaceConfigGracefully,
NullableDevkitMigration,
TargetVersion,
} from '@angular/cdk/schematics';
+import {getWorkspace} from '@schematics/angular/utility/workspace';
import {materialUpgradeData} from './upgrade-data';
@@ -19,12 +24,54 @@ const materialMigrations: NullableDevkitMigration[] = [];
/** Entry point for the migration schematics with target of Angular Material v20 */
export function updateToV20(): Rule {
- return createMigrationSchematicRule(
- TargetVersion.V20,
- materialMigrations,
- materialUpgradeData,
- onMigrationComplete,
- );
+ return chain([
+ createMigrationSchematicRule(
+ TargetVersion.V20,
+ materialMigrations,
+ materialUpgradeData,
+ onMigrationComplete,
+ ),
+ // Updating to the new Material Symbols isn't a migration within materialMigrations since
+ // the index files are never visited within the migration schematic rule. The
+ // migrate() function within the update-tool only visits files referenced in
+ // typescript files which excludes the index template files:
+ // https://github.com/angular/components/blob/main/src/cdk/schematics/update-tool/index.ts#L71.
+ updateIconFontToMaterialSymbolsRule(),
+ ]);
+}
+
+/**
+ * Finds the index files and adds the import for Material Symbols font if needed. As of v20,
+ * Material Symbols becomes the default font icon since Material Icons is deprecated. This
+ * rule ensures the Material Symbols font is imported for existing applications.
+ * @returns Rule that adds the import for the Material Symbols icon font to the index files
+ */
+function updateIconFontToMaterialSymbolsRule(): Rule {
+ return async (tree: Tree, context: SchematicContext) => {
+ const workspace = await getWorkspaceConfigGracefully(tree);
+ const projectNames = workspace!.projects.keys();
+
+ let indexFiles: string[] = [];
+ for (const projectName of projectNames) {
+ const project = getProjectFromWorkspace(await getWorkspace(tree), projectName);
+ indexFiles = [...indexFiles, ...getProjectIndexFiles(project)];
+ }
+
+ const materialSymbolsFont =
+ 'https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined';
+ for (const indexFile of indexFiles) {
+ // Add Material Symbols font if not imported in index file. References to the deprecated
+ // Material Icons are not removed since some applications may have manual overrides in their
+ // component styles that still reference it.
+ if (!tree.read(indexFile)?.includes(materialSymbolsFont)) {
+ appendHtmlElementToHead(
+ tree,
+ indexFile,
+ ``,
+ );
+ }
+ }
+ };
}
/** Function that will be called when the migration completed. */
diff --git a/src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts b/src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts
new file mode 100644
index 000000000000..4ce196537d38
--- /dev/null
+++ b/src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts
@@ -0,0 +1,87 @@
+import {UnitTestTree} from '@angular-devkit/schematics/testing';
+import {createTestCaseSetup} from '@angular/cdk/schematics/testing';
+import {MIGRATION_PATH} from '../../paths';
+
+const INDEX_HTML_FILE_PATH = '/projects/cdk-testing/src/index.html';
+
+describe('v20 material symbols icon font migration', () => {
+ let tree: UnitTestTree;
+ let writeFile: (filename: string, content: string) => void;
+ let runMigration: () => Promise;
+
+ function stripWhitespace(content: string): string {
+ return content.replace(/\s/g, '');
+ }
+
+ beforeEach(async () => {
+ const testSetup = await createTestCaseSetup('migration-v20', MIGRATION_PATH, []);
+ tree = testSetup.appTree;
+ writeFile = testSetup.writeFile;
+ runMigration = testSetup.runFixers;
+ });
+
+ it('should add Material Symbols font to index html file', async () => {
+ writeFile(
+ INDEX_HTML_FILE_PATH,
+ `
+
+
+
+
+
+
+
+
+ `,
+ );
+
+ await runMigration();
+
+ expect(stripWhitespace(tree.readText(INDEX_HTML_FILE_PATH))).toBe(
+ stripWhitespace(`
+
+
+
+
+
+
+
+
+
+ `),
+ );
+ });
+
+ it('should not add Material Symbols font to index html file if it is already imported', async () => {
+ writeFile(
+ INDEX_HTML_FILE_PATH,
+ `
+
+
+
+
+
+
+
+
+
+ `,
+ );
+
+ await runMigration();
+
+ expect(stripWhitespace(tree.readText(INDEX_HTML_FILE_PATH))).toBe(
+ stripWhitespace(`
+
+
+
+
+
+
+
+
+
+ `),
+ );
+ });
+});