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
This commit is contained in:
Alan Agius 2021-01-26 11:41:50 +01:00
parent 36a28e5226
commit a86ea3f154
4 changed files with 39 additions and 8 deletions

View File

@ -249,7 +249,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
return prev; return prev;
}, []); }, []);
// Add a new asset for each entry. // Add a new asset for each entry.
for (const script of globalScriptsByBundleName) { for (const script of globalScriptsByBundleName) {
// Lazy scripts don't get a hash, otherwise they can't be loaded by name. // Lazy scripts don't get a hash, otherwise they can't be loaded by name.
const hash = script.inject ? hashFormat.script : ''; const hash = script.inject ? hashFormat.script : '';

View File

@ -17,7 +17,7 @@ import {
RemoveHashPlugin, RemoveHashPlugin,
SuppressExtractedTextChunksWebpackPlugin, SuppressExtractedTextChunksWebpackPlugin,
} from '../plugins'; } from '../plugins';
import { getOutputHashFormat, normalizeExtraEntryPoints } from '../utils/helpers'; import { assetNameTemplateFactory, getOutputHashFormat, normalizeExtraEntryPoints } from '../utils/helpers';
// tslint:disable-next-line:no-big-function // tslint:disable-next-line:no-big-function
export function getStylesConfig(wco: WebpackConfigOptions) { 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) => { const postcssOptionsCreator = (sourceMap: boolean, extracted: boolean | undefined) => {
return (loader: webpack.loader.LoaderContext) => ({ return (loader: webpack.loader.LoaderContext) => ({
map: sourceMap && { map: sourceMap && {
@ -183,7 +185,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
deployUrl: buildOptions.deployUrl, deployUrl: buildOptions.deployUrl,
resourcesOutputPath: buildOptions.resourcesOutputPath, resourcesOutputPath: buildOptions.resourcesOutputPath,
loader, loader,
filename: `[name]${hashFormat.file}.[ext]`, filename: assetNameTemplate,
emitFile: buildOptions.platform !== 'server', emitFile: buildOptions.platform !== 'server',
extracted, extracted,
}), }),

View File

@ -31,7 +31,7 @@ export interface PostcssCliResourcesOptions {
rebaseRootRelative?: boolean; rebaseRootRelative?: boolean;
/** CSS is extracted to a `.css` or is embedded in a `.js` file. */ /** CSS is extracted to a `.css` or is embedded in a `.js` file. */
extracted?: boolean; extracted?: boolean;
filename: string; filename: (resourcePath: string) => string;
loader: webpack.loader.LoaderContext; loader: webpack.loader.LoaderContext;
emitFile: boolean; emitFile: boolean;
} }
@ -113,10 +113,11 @@ export default function(options?: PostcssCliResourcesOptions): Plugin {
} }
let outputPath = interpolateName( let outputPath = interpolateName(
{ resourcePath: result } as webpack.loader.LoaderContext, { resourcePath: result } as webpack.loader.LoaderContext,
filename, filename(result),
{ content }, { content, context: loader.context || loader.rootContext },
); )
.replace(/\\|\//g, '-');
if (resourcesOutputPath) { if (resourcesOutputPath) {
outputPath = path.posix.join(resourcesOutputPath, outputPath); outputPath = path.posix.join(resourcesOutputPath, outputPath);

View File

@ -7,6 +7,7 @@
*/ */
import { basename, normalize } from '@angular-devkit/core'; import { basename, normalize } from '@angular-devkit/core';
import * as path from 'path';
import { ScriptTarget } from 'typescript'; import { ScriptTarget } from 'typescript';
import { Options, SourceMapDevToolPlugin } from 'webpack'; import { Options, SourceMapDevToolPlugin } from 'webpack';
import { ExtraEntryPoint, ExtraEntryPointClass } from '../../browser/schema'; 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/**'), ignored: poll === undefined ? undefined : withWebpackFourOrFive(/[\\\/]node_modules[\\\/]/, 'node_modules/**'),
}; };
} }
export function assetNameTemplateFactory(hashFormat: HashFormat): (resourcePath: string) => string {
const visitedFiles = new Map<string, string>();
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]';
};
}