diff --git a/tools/lib/overrideRules.js b/tools/lib/overrideRules.js new file mode 100644 index 000000000..9f05b4617 --- /dev/null +++ b/tools/lib/overrideRules.js @@ -0,0 +1,23 @@ +/** + * React Starter Kit (https://www.reactstarterkit.com/) + * + * Copyright © 2014-present Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +function overrideRules(rules, patch) { + return rules.map((ruleToPatch) => { + let rule = patch(ruleToPatch); + if (rule.rules) { + rule = { ...rule, rules: overrideRules(rule.rules, patch) }; + } + if (rule.oneOf) { + rule = { ...rule, oneOf: overrideRules(rule.oneOf, patch) }; + } + return rule; + }); +} + +export default overrideRules; diff --git a/tools/webpack.config.js b/tools/webpack.config.js index b295ad629..f5cf8132a 100644 --- a/tools/webpack.config.js +++ b/tools/webpack.config.js @@ -12,13 +12,16 @@ import webpack from 'webpack'; import AssetsPlugin from 'assets-webpack-plugin'; import nodeExternals from 'webpack-node-externals'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import overrideRules from './lib/overrideRules'; import pkg from '../package.json'; const isDebug = !process.argv.includes('--release'); const isVerbose = process.argv.includes('--verbose'); const isAnalyze = process.argv.includes('--analyze') || process.argv.includes('--analyse'); -const stylesRegExp = /\.(css|less|scss|sss)$/; +const reScript = /\.jsx?$/; +const reStyle = /\.(css|less|scss|sss)$/; +const reImage = /\.(bmp|gif|jpe?g|png|svg)$/; const staticAssetName = isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]'; // @@ -49,8 +52,9 @@ const config = { strictExportPresence: true, rules: [ + // Rules for JS / JSX { - test: /\.jsx?$/, + test: reScript, include: path.resolve(__dirname, '../src'), loader: 'babel-loader', options: { @@ -92,15 +96,30 @@ const config = { }, }, - // Handle internal/project styles (from src folder) + // Rules for Style Sheets { - test: stylesRegExp, - include: path.resolve(__dirname, '../src'), - use: [ + test: reStyle, + rules: [ + // Convert CSS into JS module { - loader: 'isomorphic-style-loader', + issuer: { not: [reStyle] }, + use: 'isomorphic-style-loader', + }, + + // Process external/third-party styles + { + exclude: path.resolve(__dirname, '../src'), + loader: 'css-loader', + options: { + sourceMap: isDebug, + minimize: !isDebug, + discardComments: { removeAll: true }, + }, }, + + // Process internal/project styles (from src folder) { + include: path.resolve(__dirname, '../src'), loader: 'css-loader', options: { // CSS Loader https://github.com/webpack/css-loader @@ -114,6 +133,8 @@ const config = { discardComments: { removeAll: true }, }, }, + + // Apply PostCSS plugins including autoprefixer { loader: 'postcss-loader', options: { @@ -122,83 +143,71 @@ const config = { }, }, }, + + // Compile Less to CSS + // https://github.com/webpack-contrib/less-loader + // Install dependencies before uncommenting: yarn add --dev less-loader less + // { + // test: /\.less$/, + // loader: 'less-loader', + // }, + + // Compile Sass to CSS + // https://github.com/webpack-contrib/sass-loader + // Install dependencies before uncommenting: yarn add --dev sass-loader node-sass + // { + // test: /\.scss$/, + // loader: 'sass-loader', + // }, ], }, - // Handle external/third-party styles (from node_modules) + // Rules for images { - test: stylesRegExp, - exclude: path.resolve(__dirname, '../src'), - use: [ + test: reImage, + oneOf: [ + // Inline lightweight images into CSS { - loader: 'isomorphic-style-loader', + issuer: reStyle, + oneOf: [ + // Inline lightweight SVGs as UTF-8 encoded DataUrl string + { + test: /\.svg$/, + loader: 'svg-url-loader', + options: { + name: staticAssetName, + limit: 4096, // 4kb + }, + }, + + // Inline lightweight images as Base64 encoded DataUrl string + { + loader: 'url-loader', + options: { + name: staticAssetName, + limit: 4096, // 4kb + }, + }, + ], }, + + // Or return public URL to image resource { - loader: 'css-loader', + loader: 'file-loader', options: { - sourceMap: isDebug, - minimize: !isDebug, - discardComments: { removeAll: true }, + name: staticAssetName, }, }, ], }, - // Compile Less to CSS - // https://github.com/webpack-contrib/less-loader - // Install dependencies before uncommenting: yarn add --dev less-loader less - // { - // test: /\.less$/, - // loader: 'less-loader', - // }, - - // Compile Sass to CSS - // https://github.com/webpack-contrib/sass-loader - // Install dependencies before uncommenting: yarn add --dev sass-loader node-sass - // { - // test: /\.scss$/, - // loader: 'sass-loader', - // }, - - // Inline small images into CSS as Base64 encoded DataUrl string - { - test: /\.(bmp|gif|jpe?g|png)$/, - issuer: stylesRegExp, - loader: 'url-loader', - options: { - name: staticAssetName, - limit: 4096, // 4kb - }, - }, - - // Inline small SVGs into CSS as UTF-8 encoded DataUrl string - { - test: /\.svg$/, - issuer: stylesRegExp, - loader: 'svg-url-loader', - options: { - name: staticAssetName, - limit: 4096, // 4kb - }, - }, - - // Return public URL to large images otherwise - { - test: /\.(bmp|gif|jpe?g|png|svg)$/, - issuer: { not: [stylesRegExp] }, - loader: 'file-loader', - options: { - name: staticAssetName, - }, - }, - - // Convert plain text into module + // Convert plain text into JS module { test: /\.txt$/, loader: 'raw-loader', }, - // Convert markdown into html + // Convert Markdown into HTML { test: /\.md$/, loader: path.resolve(__dirname, './lib/markdown-loader.js'), @@ -208,10 +217,10 @@ const config = { // DO NOT FORGET to update `exclude` list when you adding a new loader { exclude: [ - /\.jsx?$/, + reScript, + reStyle, + reImage, /\.json$/, - stylesRegExp, - /\.(bmp|gif|jpe?g|png|svg)$/, /\.txt$/, /\.md$/, ], @@ -366,8 +375,8 @@ const serverConfig = { module: { ...config.module, - // Override babel-preset-env configuration for Node.js - rules: config.module.rules.map((rule) => { + rules: overrideRules(config.module.rules, (rule) => { + // Override babel-preset-env configuration for Node.js if (rule.loader === 'babel-loader') { return { ...rule, @@ -385,6 +394,7 @@ const serverConfig = { }; } + // Override paths to static assets if (rule.loader === 'file-loader' || rule.loader === 'url-loader' || rule.loader === 'svg-url-loader') { return { ...rule, @@ -404,7 +414,8 @@ const serverConfig = { './assets.json', nodeExternals({ whitelist: [ - stylesRegExp, + reStyle, + reImage, ], }), ], diff --git a/yarn.lock b/yarn.lock index aa04dbd9d..2c6154a02 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2055,13 +2055,13 @@ debug@2.6.4: dependencies: ms "0.7.3" -debug@2.6.7, debug@^2.1.1, debug@^2.2.0, debug@^2.6.0, debug@^2.6.3, debug@^2.6.6: +debug@2.6.7, debug@^2.1.1: version "2.6.7" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" dependencies: ms "2.0.0" -debug@^2.6.8: +debug@^2.2.0, debug@^2.6.0, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: @@ -4449,7 +4449,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@4.12.0, lodash@^4.0.0, lodash@^4.2.0: +lodash@4.12.0, lodash@^4.2.0: version "4.12.0" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.12.0.tgz#2bd6dc46a040f59e686c972ed21d93dc59053258" @@ -4461,7 +4461,7 @@ lodash@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.1.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.1.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4685,11 +4685,11 @@ minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.1.x, minimist@^1.1.3: +minimist@1.1.x: version "1.1.3" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" -minimist@^1.1.0, minimist@^1.2.0: +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -5818,15 +5818,7 @@ postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0. source-map "^0.5.6" supports-color "^3.2.3" -postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.2.tgz#5c4fea589f0ac3b00caa75b1cbc3a284195b7e5d" - dependencies: - chalk "^1.1.3" - source-map "^0.5.6" - supports-color "^3.2.3" - -postcss@^6.0.3: +postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.2, postcss@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.3.tgz#b7f565b3d956fbb8565ca7c1e239d0506e427d8b" dependencies: @@ -7062,7 +7054,7 @@ sugarss@^0.2.0: dependencies: postcss "^5.2.4" -supports-color@3.1.2: +supports-color@3.1.2, supports-color@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" dependencies: @@ -7072,7 +7064,7 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3: +supports-color@^3.1.2, supports-color@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: