Skip to content

Commit 8e741e1

Browse files
committedMay 25, 2021
fix(@angular-devkit/build-angular): ensure latest inline stylesheet data is used during rebuilds
Fixes: #20904 (cherry picked from commit 9433bb6)
1 parent 2298562 commit 8e741e1

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed
 

‎packages/angular_devkit/build_angular/src/browser/tests/options/inline-style-language_spec.ts

+62
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import { concatMap, count, take, timeout } from 'rxjs/operators';
910
import { buildWebpackBrowser } from '../../index';
1011
import { InlineStyleLanguage } from '../../schema';
1112
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup';
@@ -106,6 +107,67 @@ describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
106107
harness.expectFile('dist/main.js').content.toContain('color: green');
107108
});
108109
});
110+
111+
it('updates produced stylesheet in watch mode', async () => {
112+
harness.useTarget('build', {
113+
...BASE_OPTIONS,
114+
main: 'src/main.ts',
115+
inlineStyleLanguage: InlineStyleLanguage.Scss,
116+
aot,
117+
watch: true,
118+
});
119+
120+
await harness.modifyFile('src/app/app.component.ts', (content) =>
121+
content.replace(
122+
'__STYLE_MARKER__',
123+
'$primary-color: green;\\nh1 { color: $primary-color; }',
124+
),
125+
);
126+
127+
const buildCount = await harness
128+
.execute()
129+
.pipe(
130+
timeout(30000),
131+
concatMap(async ({ result }, index) => {
132+
expect(result?.success).toBe(true);
133+
134+
switch (index) {
135+
case 0:
136+
harness.expectFile('dist/main.js').content.toContain('color: green');
137+
harness.expectFile('dist/main.js').content.not.toContain('color: aqua');
138+
139+
await harness.modifyFile('src/app/app.component.ts', (content) =>
140+
content.replace(
141+
'$primary-color: green;\\nh1 { color: $primary-color; }',
142+
'$primary-color: aqua;\\nh1 { color: $primary-color; }',
143+
),
144+
);
145+
break;
146+
case 1:
147+
harness.expectFile('dist/main.js').content.not.toContain('color: green');
148+
harness.expectFile('dist/main.js').content.toContain('color: aqua');
149+
150+
await harness.modifyFile('src/app/app.component.ts', (content) =>
151+
content.replace(
152+
'$primary-color: aqua;\\nh1 { color: $primary-color; }',
153+
'$primary-color: blue;\\nh1 { color: $primary-color; }',
154+
),
155+
);
156+
break;
157+
case 2:
158+
harness.expectFile('dist/main.js').content.not.toContain('color: green');
159+
harness.expectFile('dist/main.js').content.not.toContain('color: aqua');
160+
harness.expectFile('dist/main.js').content.toContain('color: blue');
161+
break;
162+
}
163+
}),
164+
take(3),
165+
count(),
166+
)
167+
.toPromise();
168+
169+
expect(buildCount).toBe(3);
170+
});
109171
}
110172
});
111173
});

‎packages/ngtools/webpack/src/ivy/host.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ export function augmentHostWithResources(
5858
}
5959

6060
if (options.inlineStyleMimeType) {
61-
const content = await resourceLoader.process(data, options.inlineStyleMimeType);
61+
const content = await resourceLoader.process(
62+
data,
63+
options.inlineStyleMimeType,
64+
context.type,
65+
context.containingFile,
66+
);
6267

6368
return { content };
6469
}

‎packages/ngtools/webpack/src/resource_loader.ts

+31-5
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,16 @@ export class WebpackResourceLoader {
9898
filePath?: string,
9999
data?: string,
100100
mimeType?: string,
101+
resourceType?: 'style' | 'template',
102+
hash?: string,
103+
containingFile?: string,
101104
): Promise<CompilationOutput> {
102105
if (!this._parentCompilation) {
103106
throw new Error('WebpackResourceLoader cannot be used without parentCompilation');
104107
}
105108

106109
// Create a special URL for reading the resource from memory
107-
const entry = data ? 'angular-resource://' : filePath;
110+
const entry = data ? `angular-resource:${resourceType},${hash}` : filePath;
108111
if (!entry) {
109112
throw new Error(`"filePath" or "data" must be specified.`);
110113
}
@@ -116,7 +119,11 @@ export class WebpackResourceLoader {
116119
);
117120
}
118121

119-
const outputFilePath = filePath || `angular-resource-output-${this.outputPathCounter++}.css`;
122+
const outputFilePath =
123+
filePath ||
124+
`${containingFile}-angular-inline--${this.outputPathCounter++}.${
125+
resourceType === 'template' ? 'html' : 'css'
126+
}`;
120127
const outputOptions = {
121128
filename: outputFilePath,
122129
library: {
@@ -215,7 +222,14 @@ export class WebpackResourceLoader {
215222
if (parent) {
216223
parent.children = parent.children.filter((child) => child !== childCompilation);
217224

218-
parent.fileDependencies.addAll(childCompilation.fileDependencies);
225+
for (const fileDependency of childCompilation.fileDependencies) {
226+
if (data && containingFile && fileDependency.endsWith(entry)) {
227+
// use containing file if the resource was inline
228+
parent.fileDependencies.add(containingFile);
229+
} else {
230+
parent.fileDependencies.add(fileDependency);
231+
}
232+
}
219233
parent.contextDependencies.addAll(childCompilation.contextDependencies);
220234
parent.missingDependencies.addAll(childCompilation.missingDependencies);
221235
parent.buildDependencies.addAll(childCompilation.buildDependencies);
@@ -298,7 +312,12 @@ export class WebpackResourceLoader {
298312
return compilationResult.content;
299313
}
300314

301-
async process(data: string, mimeType: string): Promise<string> {
315+
async process(
316+
data: string,
317+
mimeType: string,
318+
resourceType: 'template' | 'style',
319+
containingFile?: string,
320+
): Promise<string> {
302321
if (data.trim().length === 0) {
303322
return '';
304323
}
@@ -307,7 +326,14 @@ export class WebpackResourceLoader {
307326
let compilationResult = this.inlineCache?.get(cacheKey);
308327

309328
if (compilationResult === undefined) {
310-
compilationResult = await this._compile(undefined, data, mimeType);
329+
compilationResult = await this._compile(
330+
undefined,
331+
data,
332+
mimeType,
333+
resourceType,
334+
cacheKey,
335+
containingFile,
336+
);
311337

312338
if (this.inlineCache && compilationResult.success) {
313339
this.inlineCache.set(cacheKey, compilationResult);

0 commit comments

Comments
 (0)
Please sign in to comment.