Skip to content

Commit 77a4fba

Browse files
alan-agius4vikerman
authored andcommitted
fix(@angular-devkit/build-angular): don't emit CSS resources during a server build
The server should serve the assets emitted by the browser builder. In fact the nguniversal schematics are configured to serve the assets from the browser folder https://github.com/angular/universal/blob/a0cc9ab97a70370eff872664ac46391a193aa45e/modules/express-engine/schematics/install/files/__serverFileName%40stripTsExtension__.ts#L26 Closes #12878
1 parent aa6aee1 commit 77a4fba

File tree

6 files changed

+93
-9
lines changed

6 files changed

+93
-9
lines changed

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
492492
loader: 'file-loader',
493493
options: {
494494
name: `[name]${hashFormat.file}.[ext]`,
495+
// Re-use emitted files from browser builder on the server.
496+
emitFile: wco.buildOptions.platform !== 'server',
495497
},
496498
},
497499
{

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/styles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
7272
loader,
7373
rebaseRootRelative: buildOptions.rebaseRootRelativeCssUrls,
7474
filename: `[name]${hashFormat.file}.[ext]`,
75+
emitFile: buildOptions.platform !== 'server',
7576
}),
7677
autoprefixer(),
7778
];

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface PostcssCliResourcesOptions {
3131
rebaseRootRelative?: boolean;
3232
filename: string;
3333
loader: webpack.loader.LoaderContext;
34+
emitFile: boolean;
3435
}
3536

3637
async function resolve(
@@ -53,6 +54,7 @@ export default postcss.plugin('postcss-cli-resources', (options: PostcssCliResou
5354
rebaseRootRelative = false,
5455
filename,
5556
loader,
57+
emitFile,
5658
} = options;
5759

5860
const dedupeSlashes = (url: string) => url.replace(/\/\/+/g, '/');
@@ -134,7 +136,9 @@ export default postcss.plugin('postcss-cli-resources', (options: PostcssCliResou
134136
}
135137

136138
loader.addDependency(result);
137-
loader.emitFile(outputPath, content, undefined);
139+
if (emitFile) {
140+
loader.emitFile(outputPath, content, undefined);
141+
}
138142

139143
let outputUrl = outputPath.replace(/\\/g, '/');
140144
if (hash || search) {

packages/angular_devkit/build_angular/test/server/base_spec_large.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { Architect } from '@angular-devkit/architect';
1010
import { getSystemPath, join, normalize, virtualFs } from '@angular-devkit/core';
1111
import { take, tap } from 'rxjs/operators';
12-
import { BrowserBuilderOutput } from '../../src/browser';
12+
import { ServerBuilderOutput } from '../../src';
1313
import { BundleDependencies } from '../../src/server/schema';
1414
import { createArchitect, host, veEnabled } from '../utils';
1515

@@ -28,7 +28,7 @@ describe('Server Builder', () => {
2828

2929
it('works (base)', async () => {
3030
const run = await architect.scheduleTarget(target);
31-
const output = await run.result as BrowserBuilderOutput;
31+
const output = await run.result as ServerBuilderOutput;
3232
expect(output.success).toBe(true);
3333

3434
const fileName = join(outputPath, 'main.js');
@@ -45,7 +45,7 @@ describe('Server Builder', () => {
4545

4646
it('should not emit polyfills', async () => {
4747
const run = await architect.scheduleTarget(target);
48-
const output = await run.result as BrowserBuilderOutput;
48+
const output = await run.result as ServerBuilderOutput;
4949
expect(output.success).toBe(true);
5050

5151
expect(host.fileMatchExists(getSystemPath(outputPath), /polyfills/)).not.toBeDefined();
@@ -62,7 +62,7 @@ describe('Server Builder', () => {
6262
});
6363

6464
const run = await architect.scheduleTarget(target);
65-
const output = await run.result as BrowserBuilderOutput;
65+
const output = await run.result as ServerBuilderOutput;
6666
expect(output.success).toBe(true);
6767

6868
expect(host.fileMatchExists(getSystemPath(outputPath), /polyfills/)).not.toBeDefined();
@@ -74,7 +74,7 @@ describe('Server Builder', () => {
7474
it('supports sourcemaps', async () => {
7575
const overrides = { sourceMap: true };
7676
const run = await architect.scheduleTarget(target, overrides);
77-
const output = await run.result as BrowserBuilderOutput;
77+
const output = await run.result as ServerBuilderOutput;
7878
expect(output.success).toBe(true);
7979
expect(host.scopedSync().exists(join(outputPath, 'main.js.map'))).toBeTruthy();
8080
await run.stop();
@@ -92,7 +92,7 @@ describe('Server Builder', () => {
9292
scripts: true,
9393
},
9494
});
95-
const output = await run.result as BrowserBuilderOutput;
95+
const output = await run.result as ServerBuilderOutput;
9696
expect(output.success).toBe(true);
9797

9898
expect(host.scopedSync().exists(join(outputPath, 'main.js.map'))).toBe(true);
@@ -120,7 +120,7 @@ describe('Server Builder', () => {
120120
});
121121

122122
const run = await architect.scheduleTarget(target, overrides);
123-
const output = await run.result as BrowserBuilderOutput;
123+
const output = await run.result as ServerBuilderOutput;
124124
expect(output.success).toBe(true);
125125

126126
expect(host.scopedSync().exists(join(outputPath, 'main.js.map'))).toBe(true);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
// tslint:disable:no-big-function
9+
import { Architect } from '@angular-devkit/architect';
10+
import { join, normalize, virtualFs } from '@angular-devkit/core';
11+
import { ServerBuilderOutput } from '../../src';
12+
import { createArchitect, host } from '../utils';
13+
14+
15+
describe('Server Builder styles resources output path (No emit assets)', () => {
16+
function writeFiles() {
17+
host.copyFile('src/spectrum.png', './src/assets/component-img-relative.png');
18+
host.copyFile('src/spectrum.png', './src/assets/component-img-absolute.png');
19+
host.writeMultipleFiles({
20+
'src/app/app.component.css': `
21+
h3 { background: url('/assets/component-img-absolute.png'); }
22+
h4 { background: url('../assets/component-img-relative.png'); }
23+
`,
24+
});
25+
}
26+
27+
const target = { project: 'app', target: 'server' };
28+
let architect: Architect;
29+
30+
const outputPath = normalize('dist-server');
31+
32+
beforeEach(async () => {
33+
await host.initialize().toPromise();
34+
architect = (await createArchitect(host.root())).architect;
35+
});
36+
afterEach(async () => host.restore().toPromise());
37+
38+
it(`supports resourcesOutputPath in resource urls`, async () => {
39+
writeFiles();
40+
const overrides = {
41+
resourcesOutputPath: 'out-assets',
42+
};
43+
44+
const run = await architect.scheduleTarget(target, overrides);
45+
const output = await run.result as ServerBuilderOutput;
46+
expect(output.success).toBe(true);
47+
48+
const fileName = join(outputPath, 'main.js');
49+
50+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
51+
52+
expect(content).toContain(`url('/assets/component-img-absolute.png')`);
53+
expect(content).toContain(`url('out-assets/component-img-relative.png')`);
54+
55+
expect(host.scopedSync().exists(normalize(`${outputPath}/out-assets/component-img-relative.png`)))
56+
.toBe(false);
57+
});
58+
59+
it(`supports blank resourcesOutputPath`, async () => {
60+
writeFiles();
61+
62+
const run = await architect.scheduleTarget(target);
63+
const output = await run.result as ServerBuilderOutput;
64+
expect(output.success).toBe(true);
65+
66+
const fileName = join(outputPath, 'main.js');
67+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
68+
69+
expect(content).toContain(`url('/assets/component-img-absolute.png')`);
70+
expect(content).toContain(`url('component-img-relative.png')`);
71+
72+
expect(host.scopedSync().exists(normalize(`${outputPath}/component-img-relative.png`)))
73+
.toBe(false);
74+
});
75+
});

packages/schematics/angular/utility/workspace-models.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ export interface BrowserBuilderBaseOptions {
4343
sourceMap?: boolean;
4444
}
4545

46+
export type OutputHashing = 'all' | 'media' | 'none' | 'bundles';
47+
4648
export interface BrowserBuilderOptions extends BrowserBuilderBaseOptions {
4749
serviceWorker?: boolean;
4850
optimization?: boolean;
49-
outputHashing?: 'all';
51+
outputHashing?: OutputHashing;
5052
resourcesOutputPath?: string;
5153
extractCss?: boolean;
5254
namedChunks?: boolean;

0 commit comments

Comments
 (0)