Skip to content

Commit 9a12bd9

Browse files
committed
feat(@angular-devkit/build-angular): allow .svg files as templates
Components can now use .svg files as templates. To distinguish .svg files in templates from .svg files used for other purposes, a new webpack loader rule was added that tests for .component.svg and loads these files with raw-loader. All other .svg files are loaded as before with file-loader. For use cases and alternative solutions, see the discussion in angular#10567 Closes angular#10567
1 parent 0b7dd0e commit 9a12bd9

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,10 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
294294
},
295295
module: {
296296
rules: [
297-
{ test: /\.html$/, loader: 'raw-loader' },
297+
{ test: /\.(html|component.svg)$/, loader: 'raw-loader' },
298298
{
299299
test: /\.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
300+
exclude: /\.component.svg$/,
300301
loader: 'file-loader',
301302
options: {
302303
name: `[name]${hashFormat.file}.[ext]`,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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+
9+
import { runTargetSpec } from '@angular-devkit/architect/testing';
10+
import { join, normalize, virtualFs } from '@angular-devkit/core';
11+
import { tap } from 'rxjs/operators';
12+
import { browserTargetSpec, host, outputPath } from '../utils';
13+
14+
describe('Browser Builder allow svg', () => {
15+
16+
beforeEach(done => host.initialize().toPromise().then(done, done.fail));
17+
afterEach(done => host.restore().toPromise().then(done, done.fail));
18+
19+
it('can use .component.svg as templates (uses raw-loader and does not copy .svg to dist)',
20+
(done) => {
21+
22+
host.writeMultipleFiles({
23+
'./src/app.component.svg': `<svg></svg>`,
24+
'./src/main.ts': `declare var require: Function;
25+
const x = require('./app.component.svg');
26+
console.log(x);`,
27+
});
28+
29+
runTargetSpec(host, browserTargetSpec).pipe(
30+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
31+
tap(() => {
32+
const content = virtualFs.fileBufferToString(
33+
host.scopedSync().read(join(outputPath, 'main.js')),
34+
);
35+
36+
expect(content).toContain(
37+
`var x = __webpack_require__(/*! ./app.component.svg */ "./app.component.svg");`);
38+
expect(content).toContain('module.exports = "<svg></svg>"');
39+
expect(host.scopedSync().exists(normalize('dist/app.component.svg')))
40+
.toBe(false, 'should not copy app.component.svg to dist');
41+
}),
42+
).toPromise().then(done, done.fail);
43+
});
44+
45+
it('imports non-component .svg with file-loader and copies .svg to dist', (done) => {
46+
47+
host.writeMultipleFiles({
48+
'./src/other.svg': `<svg></svg>`,
49+
'./src/main.ts': `declare var require: Function;
50+
const x = require('./other.svg');
51+
console.log(x);`,
52+
});
53+
54+
runTargetSpec(host, browserTargetSpec).pipe(
55+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
56+
tap(() => {
57+
const content = virtualFs.fileBufferToString(
58+
host.scopedSync().read(join(outputPath, 'main.js')),
59+
);
60+
61+
expect(content).toContain(
62+
`var x = __webpack_require__(/*! ./other.svg */ "./other.svg");`);
63+
expect(content).toContain(
64+
'module.exports = __webpack_require__.p + "other.svg"');
65+
expect(host.scopedSync().exists(normalize('dist/other.svg')))
66+
.toBe(true, 'should copy other.svg to dist');
67+
}),
68+
).toPromise().then(done, done.fail);
69+
});
70+
71+
it('works with aot',
72+
(done) => {
73+
74+
host.writeMultipleFiles({
75+
'./src/app/app.component.svg': `<svg></svg>`,
76+
'./src/app/app.component.ts': `
77+
import { Component } from '@angular/core';
78+
79+
@Component({
80+
selector: 'app-root',
81+
templateUrl: './app.component.svg',
82+
styleUrls: []
83+
})
84+
export class AppComponent {
85+
title = 'app';
86+
}
87+
`,
88+
});
89+
90+
const overrides = { aot: true };
91+
92+
runTargetSpec(host, browserTargetSpec, overrides).pipe(
93+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
94+
tap(() => {
95+
const content = virtualFs.fileBufferToString(
96+
host.scopedSync().read(join(outputPath, 'main.js')),
97+
);
98+
99+
expect(content).toContain('":svg:svg"');
100+
expect(host.scopedSync().exists(normalize('dist/app.component.svg')))
101+
.toBe(false, 'should not copy app.component.svg to dist');
102+
}),
103+
).toPromise().then(done, done.fail);
104+
});
105+
106+
});

0 commit comments

Comments
 (0)