Skip to content

Commit a86ea3f

Browse files
committed
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
1 parent 36a28e5 commit a86ea3f

File tree

4 files changed

+39
-8
lines changed

4 files changed

+39
-8
lines changed

packages/angular_devkit/build_angular/src/webpack/configs/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
249249
return prev;
250250
}, []);
251251

252-
// Add a new asset for each entry.
252+
// Add a new asset for each entry.
253253
for (const script of globalScriptsByBundleName) {
254254
// Lazy scripts don't get a hash, otherwise they can't be loaded by name.
255255
const hash = script.inject ? hashFormat.script : '';

packages/angular_devkit/build_angular/src/webpack/configs/styles.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
RemoveHashPlugin,
1818
SuppressExtractedTextChunksWebpackPlugin,
1919
} from '../plugins';
20-
import { getOutputHashFormat, normalizeExtraEntryPoints } from '../utils/helpers';
20+
import { assetNameTemplateFactory, getOutputHashFormat, normalizeExtraEntryPoints } from '../utils/helpers';
2121

2222
// tslint:disable-next-line:no-big-function
2323
export function getStylesConfig(wco: WebpackConfigOptions) {
@@ -154,6 +154,8 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
154154
},
155155
];
156156

157+
const assetNameTemplate = assetNameTemplateFactory(hashFormat);
158+
157159
const postcssOptionsCreator = (sourceMap: boolean, extracted: boolean | undefined) => {
158160
return (loader: webpack.loader.LoaderContext) => ({
159161
map: sourceMap && {
@@ -183,7 +185,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
183185
deployUrl: buildOptions.deployUrl,
184186
resourcesOutputPath: buildOptions.resourcesOutputPath,
185187
loader,
186-
filename: `[name]${hashFormat.file}.[ext]`,
188+
filename: assetNameTemplate,
187189
emitFile: buildOptions.platform !== 'server',
188190
extracted,
189191
}),

packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export interface PostcssCliResourcesOptions {
3131
rebaseRootRelative?: boolean;
3232
/** CSS is extracted to a `.css` or is embedded in a `.js` file. */
3333
extracted?: boolean;
34-
filename: string;
34+
filename: (resourcePath: string) => string;
3535
loader: webpack.loader.LoaderContext;
3636
emitFile: boolean;
3737
}
@@ -113,10 +113,11 @@ export default function(options?: PostcssCliResourcesOptions): Plugin {
113113
}
114114

115115
let outputPath = interpolateName(
116-
{ resourcePath: result } as webpack.loader.LoaderContext,
117-
filename,
118-
{ content },
119-
);
116+
{ resourcePath: result } as webpack.loader.LoaderContext,
117+
filename(result),
118+
{ content, context: loader.context || loader.rootContext },
119+
)
120+
.replace(/\\|\//g, '-');
120121

121122
if (resourcesOutputPath) {
122123
outputPath = path.posix.join(resourcesOutputPath, outputPath);

packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import { basename, normalize } from '@angular-devkit/core';
10+
import * as path from 'path';
1011
import { ScriptTarget } from 'typescript';
1112
import { Options, SourceMapDevToolPlugin } from 'webpack';
1213
import { ExtraEntryPoint, ExtraEntryPointClass } from '../../browser/schema';
@@ -124,3 +125,30 @@ export function getWatchOptions(poll: number | undefined): Options.WatchOptions
124125
ignored: poll === undefined ? undefined : withWebpackFourOrFive(/[\\\/]node_modules[\\\/]/, 'node_modules/**'),
125126
};
126127
}
128+
129+
export function assetNameTemplateFactory(hashFormat: HashFormat): (resourcePath: string) => string {
130+
const visitedFiles = new Map<string, string>();
131+
132+
return (resourcePath: string) => {
133+
if (hashFormat.file) {
134+
// File names are hashed therefore we don't need to handle files with the same file name.
135+
return `[name]${hashFormat.file}.[ext]`;
136+
}
137+
138+
const filename = path.basename(resourcePath);
139+
// Check if the file with the same name has already been processed.
140+
const visited = visitedFiles.get(filename);
141+
if (!visited) {
142+
// Not visited.
143+
visitedFiles.set(filename, resourcePath);
144+
145+
return filename;
146+
} else if (visited === resourcePath) {
147+
// Same file.
148+
return filename;
149+
}
150+
151+
// File has the same name but it's in a different location.
152+
return '[path][name].[ext]';
153+
};
154+
}

0 commit comments

Comments
 (0)