Skip to content

Commit f53b638

Browse files
iansugaearon
authored andcommitted
Import SVGs as React components (facebook#1388) (facebook#3718)
* Import SVGs as React components (facebook#1388) * Updated webpack production config and fixed tests * Improved Jest SVG file transform * Improved SVG tests * Add a comment * Update webpack.config.prod.js
1 parent ffca5ab commit f53b638

File tree

6 files changed

+91
-1
lines changed

6 files changed

+91
-1
lines changed

config/jest/fileTransform.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ const path = require('path');
1515

1616
module.exports = {
1717
process(src, filename) {
18-
return `module.exports = ${JSON.stringify(path.basename(filename))};`;
18+
const assetFilename = JSON.stringify(path.basename(filename));
19+
20+
if (filename.match(/\.svg$/)) {
21+
return `module.exports = {
22+
__esModule: true,
23+
default: ${assetFilename},
24+
ReactComponent: () => ${assetFilename},
25+
};`;
26+
}
27+
28+
return `module.exports = ${assetFilename};`;
1929
},
2030
};

config/webpack.config.dev.js

+25
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,31 @@ module.exports = {
262262
},
263263
],
264264
},
265+
// Allows you to use two kinds of imports for SVG:
266+
// import logoUrl from './logo.svg'; gives you the URL.
267+
// import { ReactComponent as Logo } from './logo.svg'; gives you a component.
268+
{
269+
test: /\.svg$/,
270+
use: [
271+
{
272+
loader: require.resolve('babel-loader'),
273+
options: {
274+
// @remove-on-eject-begin
275+
babelrc: false,
276+
presets: [require.resolve('babel-preset-react-app')],
277+
// @remove-on-eject-end
278+
cacheDirectory: true,
279+
},
280+
},
281+
require.resolve('svgr/webpack'),
282+
{
283+
loader: require.resolve('file-loader'),
284+
options: {
285+
name: 'static/media/[name].[hash:8].[ext]',
286+
},
287+
},
288+
],
289+
},
265290
// "file" loader makes sure those assets get served by WebpackDevServer.
266291
// When you `import` an asset, you get its (virtual) filename.
267292
// In production, they would get copied to the `build` folder.

config/webpack.config.prod.js

+25
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,31 @@ module.exports = {
304304
),
305305
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
306306
},
307+
// Allows you to use two kinds of imports for SVG:
308+
// import logoUrl from './logo.svg'; gives you the URL.
309+
// import { ReactComponent as Logo } from './logo.svg'; gives you a component.
310+
{
311+
test: /\.svg$/,
312+
use: [
313+
{
314+
loader: require.resolve('babel-loader'),
315+
options: {
316+
// @remove-on-eject-begin
317+
babelrc: false,
318+
presets: [require.resolve('babel-preset-react-app')],
319+
// @remove-on-eject-end
320+
cacheDirectory: true,
321+
},
322+
},
323+
require.resolve('svgr/webpack'),
324+
{
325+
loader: require.resolve('file-loader'),
326+
options: {
327+
name: 'static/media/[name].[hash:8].[ext]',
328+
},
329+
},
330+
],
331+
},
307332
// "file" loader makes sure assets end up in the `build` folder.
308333
// When you `import` an asset, you get its filename.
309334
// This loader doesn't use a "test" so it will catch all modules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import React from 'react';
9+
import { ReactComponent as Logo } from './assets/logo.svg';
10+
11+
export default () => <Logo />;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import React from 'react';
9+
import ReactDOM from 'react-dom';
10+
import SvgComponent from './SvgComponent';
11+
12+
describe('svg component', () => {
13+
it('renders without crashing', () => {
14+
const div = document.createElement('div');
15+
ReactDOM.render(<SvgComponent />, div);
16+
expect(div.textContent).toBe('logo.svg');
17+
});
18+
});

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"raf": "3.4.0",
5555
"react-dev-utils": "^5.0.0",
5656
"style-loader": "0.19.1",
57+
"svgr": "1.6.0",
5758
"sw-precache-webpack-plugin": "0.11.4",
5859
"thread-loader": "1.1.2",
5960
"uglifyjs-webpack-plugin": "1.1.6",

0 commit comments

Comments
 (0)