Skip to content

Commit a08eb3b

Browse files
Furizaagaearon
authored andcommitted
Use Rule.oneOf to resolve correct loader (#2747)
* Use oneOf to resolve correct loader * Add html and json fallthrough again * Use oneOf to resolve correct loader in dev * Document file-loaders `js` exclusion * Remove `jsx` from exclusion in prod config
1 parent bbbc15d commit a08eb3b

File tree

2 files changed

+171
-175
lines changed

2 files changed

+171
-175
lines changed

packages/react-scripts/config/webpack.config.dev.js

+76-78
Original file line numberDiff line numberDiff line change
@@ -150,97 +150,95 @@ module.exports = {
150150
],
151151
include: paths.appSrc,
152152
},
153-
// ** ADDING/UPDATING LOADERS **
154-
// The "file" loader handles all assets unless explicitly excluded.
155-
// The `exclude` list *must* be updated with every change to loader extensions.
156-
// When adding a new loader, you must add its `test`
157-
// as a new entry in the `exclude` list for "file" loader.
158-
159-
// "file" loader makes sure those assets get served by WebpackDevServer.
160-
// When you `import` an asset, you get its (virtual) filename.
161-
// In production, they would get copied to the `build` folder.
162-
{
163-
exclude: [
164-
/\.html$/,
165-
/\.(js|jsx)$/,
166-
/\.css$/,
167-
/\.json$/,
168-
/\.bmp$/,
169-
/\.gif$/,
170-
/\.jpe?g$/,
171-
/\.png$/,
172-
],
173-
loader: require.resolve('file-loader'),
174-
options: {
175-
name: 'static/media/[name].[hash:8].[ext]',
176-
},
177-
},
178-
// "url" loader works like "file" loader except that it embeds assets
179-
// smaller than specified limit in bytes as data URLs to avoid requests.
180-
// A missing `test` is equivalent to a match.
181-
{
182-
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
183-
loader: require.resolve('url-loader'),
184-
options: {
185-
limit: 10000,
186-
name: 'static/media/[name].[hash:8].[ext]',
187-
},
188-
},
189-
// Process JS with Babel.
190153
{
191-
test: /\.(js|jsx)$/,
192-
include: paths.appSrc,
193-
loader: require.resolve('babel-loader'),
194-
options: {
195-
// @remove-on-eject-begin
196-
babelrc: false,
197-
presets: [require.resolve('babel-preset-react-app')],
198-
// @remove-on-eject-end
199-
// This is a feature of `babel-loader` for webpack (not Babel itself).
200-
// It enables caching results in ./node_modules/.cache/babel-loader/
201-
// directory for faster rebuilds.
202-
cacheDirectory: true,
203-
},
204-
},
205-
// "postcss" loader applies autoprefixer to our CSS.
206-
// "css" loader resolves paths in CSS and adds assets as dependencies.
207-
// "style" loader turns CSS into JS modules that inject <style> tags.
208-
// In production, we use a plugin to extract that CSS to a file, but
209-
// in development "style" loader enables hot editing of CSS.
210-
{
211-
test: /\.css$/,
212-
use: [
213-
require.resolve('style-loader'),
154+
// "oneOf" will traverse all following loaders until one will
155+
// match the requirements. When no loader matches it will fall
156+
// back to the "file" loader at the end of the loader list.
157+
oneOf: [
158+
// "url" loader works like "file" loader except that it embeds assets
159+
// smaller than specified limit in bytes as data URLs to avoid requests.
160+
// A missing `test` is equivalent to a match.
214161
{
215-
loader: require.resolve('css-loader'),
162+
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
163+
loader: require.resolve('url-loader'),
216164
options: {
217-
importLoaders: 1,
165+
limit: 10000,
166+
name: 'static/media/[name].[hash:8].[ext]',
218167
},
219168
},
169+
// Process JS with Babel.
220170
{
221-
loader: require.resolve('postcss-loader'),
171+
test: /\.(js|jsx)$/,
172+
include: paths.appSrc,
173+
loader: require.resolve('babel-loader'),
222174
options: {
223-
// Necessary for external CSS imports to work
224-
// https://github.com/facebookincubator/create-react-app/issues/2677
225-
ident: 'postcss',
226-
plugins: () => [
227-
require('postcss-flexbugs-fixes'),
228-
autoprefixer({
229-
browsers: [
230-
'>1%',
231-
'last 4 versions',
232-
'Firefox ESR',
233-
'not ie < 9', // React doesn't support IE8 anyway
175+
// @remove-on-eject-begin
176+
babelrc: false,
177+
presets: [require.resolve('babel-preset-react-app')],
178+
// @remove-on-eject-end
179+
// This is a feature of `babel-loader` for webpack (not Babel itself).
180+
// It enables caching results in ./node_modules/.cache/babel-loader/
181+
// directory for faster rebuilds.
182+
cacheDirectory: true,
183+
},
184+
},
185+
// "postcss" loader applies autoprefixer to our CSS.
186+
// "css" loader resolves paths in CSS and adds assets as dependencies.
187+
// "style" loader turns CSS into JS modules that inject <style> tags.
188+
// In production, we use a plugin to extract that CSS to a file, but
189+
// in development "style" loader enables hot editing of CSS.
190+
{
191+
test: /\.css$/,
192+
use: [
193+
require.resolve('style-loader'),
194+
{
195+
loader: require.resolve('css-loader'),
196+
options: {
197+
importLoaders: 1,
198+
},
199+
},
200+
{
201+
loader: require.resolve('postcss-loader'),
202+
options: {
203+
// Necessary for external CSS imports to work
204+
// https://github.com/facebookincubator/create-react-app/issues/2677
205+
ident: 'postcss',
206+
plugins: () => [
207+
require('postcss-flexbugs-fixes'),
208+
autoprefixer({
209+
browsers: [
210+
'>1%',
211+
'last 4 versions',
212+
'Firefox ESR',
213+
'not ie < 9', // React doesn't support IE8 anyway
214+
],
215+
flexbox: 'no-2009',
216+
}),
234217
],
235-
flexbox: 'no-2009',
236-
}),
237-
],
218+
},
219+
},
220+
],
221+
},
222+
// "file" loader makes sure those assets get served by WebpackDevServer.
223+
// When you `import` an asset, you get its (virtual) filename.
224+
// In production, they would get copied to the `build` folder.
225+
// This loader don't uses a "test" so it will catch all modules
226+
// that fall through the other loaders.
227+
{
228+
// Exclude `js` files to keep "css" loader working as it injects
229+
// it's runtime that would otherwise processed through "file" loader.
230+
// Also exclude `html` and `json` extensions so they get processed
231+
// by webpacks internal loaders.
232+
exclude: [/\.js$/, /\.html$/, /\.json$/],
233+
loader: require.resolve('file-loader'),
234+
options: {
235+
name: 'static/media/[name].[hash:8].[ext]',
238236
},
239237
},
240238
],
241239
},
242240
// ** STOP ** Are you adding a new loader?
243-
// Remember to add the new extension(s) to the "file" loader exclusion list.
241+
// Make sure to add the new loader(s) before the "file" loader.
244242
],
245243
},
246244
plugins: [

packages/react-scripts/config/webpack.config.prod.js

+95-97
Original file line numberDiff line numberDiff line change
@@ -152,109 +152,107 @@ module.exports = {
152152
],
153153
include: paths.appSrc,
154154
},
155-
// ** ADDING/UPDATING LOADERS **
156-
// The "file" loader handles all assets unless explicitly excluded.
157-
// The `exclude` list *must* be updated with every change to loader extensions.
158-
// When adding a new loader, you must add its `test`
159-
// as a new entry in the `exclude` list in the "file" loader.
160-
161-
// "file" loader makes sure those assets end up in the `build` folder.
162-
// When you `import` an asset, you get its filename.
163-
{
164-
exclude: [
165-
/\.html$/,
166-
/\.(js|jsx)$/,
167-
/\.css$/,
168-
/\.json$/,
169-
/\.bmp$/,
170-
/\.gif$/,
171-
/\.jpe?g$/,
172-
/\.png$/,
173-
],
174-
loader: require.resolve('file-loader'),
175-
options: {
176-
name: 'static/media/[name].[hash:8].[ext]',
177-
},
178-
},
179-
// "url" loader works just like "file" loader but it also embeds
180-
// assets smaller than specified size as data URLs to avoid requests.
181-
{
182-
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
183-
loader: require.resolve('url-loader'),
184-
options: {
185-
limit: 10000,
186-
name: 'static/media/[name].[hash:8].[ext]',
187-
},
188-
},
189-
// Process JS with Babel.
190-
{
191-
test: /\.(js|jsx)$/,
192-
include: paths.appSrc,
193-
loader: require.resolve('babel-loader'),
194-
options: {
195-
// @remove-on-eject-begin
196-
babelrc: false,
197-
presets: [require.resolve('babel-preset-react-app')],
198-
// @remove-on-eject-end
199-
compact: true,
200-
},
201-
},
202-
// The notation here is somewhat confusing.
203-
// "postcss" loader applies autoprefixer to our CSS.
204-
// "css" loader resolves paths in CSS and adds assets as dependencies.
205-
// "style" loader normally turns CSS into JS modules injecting <style>,
206-
// but unlike in development configuration, we do something different.
207-
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
208-
// (second argument), then grabs the result CSS and puts it into a
209-
// separate file in our build process. This way we actually ship
210-
// a single CSS file in production instead of JS code injecting <style>
211-
// tags. If you use code splitting, however, any async bundles will still
212-
// use the "style" loader inside the async code so CSS from them won't be
213-
// in the main CSS file.
214155
{
215-
test: /\.css$/,
216-
loader: ExtractTextPlugin.extract(
217-
Object.assign(
218-
{
219-
fallback: require.resolve('style-loader'),
220-
use: [
221-
{
222-
loader: require.resolve('css-loader'),
223-
options: {
224-
importLoaders: 1,
225-
minimize: true,
226-
sourceMap: true,
227-
},
228-
},
156+
// "oneOf" will traverse all following loaders until one will
157+
// match the requirements. When no loader matches it will fall
158+
// back to the "file" loader at the end of the loader list.
159+
oneOf: [
160+
// "url" loader works just like "file" loader but it also embeds
161+
// assets smaller than specified size as data URLs to avoid requests.
162+
{
163+
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
164+
loader: require.resolve('url-loader'),
165+
options: {
166+
limit: 10000,
167+
name: 'static/media/[name].[hash:8].[ext]',
168+
},
169+
},
170+
// Process JS with Babel.
171+
{
172+
test: /\.(js|jsx)$/,
173+
include: paths.appSrc,
174+
loader: require.resolve('babel-loader'),
175+
options: {
176+
// @remove-on-eject-begin
177+
babelrc: false,
178+
presets: [require.resolve('babel-preset-react-app')],
179+
// @remove-on-eject-end
180+
compact: true,
181+
},
182+
},
183+
// The notation here is somewhat confusing.
184+
// "postcss" loader applies autoprefixer to our CSS.
185+
// "css" loader resolves paths in CSS and adds assets as dependencies.
186+
// "style" loader normally turns CSS into JS modules injecting <style>,
187+
// but unlike in development configuration, we do something different.
188+
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
189+
// (second argument), then grabs the result CSS and puts it into a
190+
// separate file in our build process. This way we actually ship
191+
// a single CSS file in production instead of JS code injecting <style>
192+
// tags. If you use code splitting, however, any async bundles will still
193+
// use the "style" loader inside the async code so CSS from them won't be
194+
// in the main CSS file.
195+
{
196+
test: /\.css$/,
197+
loader: ExtractTextPlugin.extract(
198+
Object.assign(
229199
{
230-
loader: require.resolve('postcss-loader'),
231-
options: {
232-
// Necessary for external CSS imports to work
233-
// https://github.com/facebookincubator/create-react-app/issues/2677
234-
ident: 'postcss',
235-
plugins: () => [
236-
require('postcss-flexbugs-fixes'),
237-
autoprefixer({
238-
browsers: [
239-
'>1%',
240-
'last 4 versions',
241-
'Firefox ESR',
242-
'not ie < 9', // React doesn't support IE8 anyway
200+
fallback: require.resolve('style-loader'),
201+
use: [
202+
{
203+
loader: require.resolve('css-loader'),
204+
options: {
205+
importLoaders: 1,
206+
minimize: true,
207+
sourceMap: true,
208+
},
209+
},
210+
{
211+
loader: require.resolve('postcss-loader'),
212+
options: {
213+
// Necessary for external CSS imports to work
214+
// https://github.com/facebookincubator/create-react-app/issues/2677
215+
ident: 'postcss',
216+
plugins: () => [
217+
require('postcss-flexbugs-fixes'),
218+
autoprefixer({
219+
browsers: [
220+
'>1%',
221+
'last 4 versions',
222+
'Firefox ESR',
223+
'not ie < 9', // React doesn't support IE8 anyway
224+
],
225+
flexbox: 'no-2009',
226+
}),
243227
],
244-
flexbox: 'no-2009',
245-
}),
246-
],
247-
},
228+
},
229+
},
230+
],
248231
},
249-
],
232+
extractTextPluginOptions
233+
)
234+
),
235+
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
236+
},
237+
// "file" loader makes sure assets end up in the `build` folder.
238+
// When you `import` an asset, you get its filename.
239+
// This loader don't uses a "test" so it will catch all modules
240+
// that fall through the other loaders.
241+
{
242+
loader: require.resolve('file-loader'),
243+
// Exclude `js` files to keep "css" loader working as it injects
244+
// it's runtime that would otherwise processed through "file" loader.
245+
// Also exclude `html` and `json` extensions so they get processed
246+
// by webpacks internal loaders.
247+
exclude: [/\.js$/, /\.html$/, /\.json$/],
248+
options: {
249+
name: 'static/media/[name].[hash:8].[ext]',
250250
},
251-
extractTextPluginOptions
252-
)
253-
),
254-
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
251+
},
252+
// ** STOP ** Are you adding a new loader?
253+
// Make sure to add the new loader(s) before the "file" loader.
254+
],
255255
},
256-
// ** STOP ** Are you adding a new loader?
257-
// Remember to add the new extension(s) to the "file" loader exclusion list.
258256
],
259257
},
260258
plugins: [

0 commit comments

Comments
 (0)