From a86ea3f154bb9302228e7e29350065d36e5b7bac Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 26 Jan 2021 11:41:50 +0100 Subject: [PATCH] fix(@angular-devkit/build-angular): allow emitting multiple files with the same filename Previously when hashing of media was disabled, if 2 files had the same name. Only one files used to be emitted. With this change we change the behaviour so that both files are emitted. Closes #12186 --- .../src/webpack/configs/common.ts | 2 +- .../src/webpack/configs/styles.ts | 6 ++-- .../webpack/plugins/postcss-cli-resources.ts | 11 ++++---- .../src/webpack/utils/helpers.ts | 28 +++++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/webpack/configs/common.ts b/packages/angular_devkit/build_angular/src/webpack/configs/common.ts index c49979784f..25ebe82e82 100644 --- a/packages/angular_devkit/build_angular/src/webpack/configs/common.ts +++ b/packages/angular_devkit/build_angular/src/webpack/configs/common.ts @@ -249,7 +249,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration { return prev; }, []); - // Add a new asset for each entry. + // Add a new asset for each entry. for (const script of globalScriptsByBundleName) { // Lazy scripts don't get a hash, otherwise they can't be loaded by name. const hash = script.inject ? hashFormat.script : ''; diff --git a/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts b/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts index 822c73de41..4d4192a15b 100644 --- a/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts +++ b/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts @@ -17,7 +17,7 @@ import { RemoveHashPlugin, SuppressExtractedTextChunksWebpackPlugin, } from '../plugins'; -import { getOutputHashFormat, normalizeExtraEntryPoints } from '../utils/helpers'; +import { assetNameTemplateFactory, getOutputHashFormat, normalizeExtraEntryPoints } from '../utils/helpers'; // tslint:disable-next-line:no-big-function export function getStylesConfig(wco: WebpackConfigOptions) { @@ -154,6 +154,8 @@ export function getStylesConfig(wco: WebpackConfigOptions) { }, ]; + const assetNameTemplate = assetNameTemplateFactory(hashFormat); + const postcssOptionsCreator = (sourceMap: boolean, extracted: boolean | undefined) => { return (loader: webpack.loader.LoaderContext) => ({ map: sourceMap && { @@ -183,7 +185,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) { deployUrl: buildOptions.deployUrl, resourcesOutputPath: buildOptions.resourcesOutputPath, loader, - filename: `[name]${hashFormat.file}.[ext]`, + filename: assetNameTemplate, emitFile: buildOptions.platform !== 'server', extracted, }), diff --git a/packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts b/packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts index ff8242b9ce..dd44f60573 100644 --- a/packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts +++ b/packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts @@ -31,7 +31,7 @@ export interface PostcssCliResourcesOptions { rebaseRootRelative?: boolean; /** CSS is extracted to a `.css` or is embedded in a `.js` file. */ extracted?: boolean; - filename: string; + filename: (resourcePath: string) => string; loader: webpack.loader.LoaderContext; emitFile: boolean; } @@ -113,10 +113,11 @@ export default function(options?: PostcssCliResourcesOptions): Plugin { } let outputPath = interpolateName( - { resourcePath: result } as webpack.loader.LoaderContext, - filename, - { content }, - ); + { resourcePath: result } as webpack.loader.LoaderContext, + filename(result), + { content, context: loader.context || loader.rootContext }, + ) + .replace(/\\|\//g, '-'); if (resourcesOutputPath) { outputPath = path.posix.join(resourcesOutputPath, outputPath); diff --git a/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts b/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts index 92c5e002fd..a64dbe8048 100644 --- a/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts +++ b/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts @@ -7,6 +7,7 @@ */ import { basename, normalize } from '@angular-devkit/core'; +import * as path from 'path'; import { ScriptTarget } from 'typescript'; import { Options, SourceMapDevToolPlugin } from 'webpack'; import { ExtraEntryPoint, ExtraEntryPointClass } from '../../browser/schema'; @@ -124,3 +125,30 @@ export function getWatchOptions(poll: number | undefined): Options.WatchOptions ignored: poll === undefined ? undefined : withWebpackFourOrFive(/[\\\/]node_modules[\\\/]/, 'node_modules/**'), }; } + +export function assetNameTemplateFactory(hashFormat: HashFormat): (resourcePath: string) => string { + const visitedFiles = new Map(); + + return (resourcePath: string) => { + if (hashFormat.file) { + // File names are hashed therefore we don't need to handle files with the same file name. + return `[name]${hashFormat.file}.[ext]`; + } + + const filename = path.basename(resourcePath); + // Check if the file with the same name has already been processed. + const visited = visitedFiles.get(filename); + if (!visited) { + // Not visited. + visitedFiles.set(filename, resourcePath); + + return filename; + } else if (visited === resourcePath) { + // Same file. + return filename; + } + + // File has the same name but it's in a different location. + return '[path][name].[ext]'; + }; +}