From 8184128d3c75061ef60fa9edf69b0986da3643b2 Mon Sep 17 00:00:00 2001 From: majunchen Date: Thu, 29 Nov 2018 22:17:55 +0800 Subject: [PATCH] sync Change-Id: Ie0b1149a7c29926a3adcda306df0c5c62c2dc637 --- packages/react-scripts/README.md | 26 +- packages/react-scripts/config/env.js | 8 +- .../config/getWebpackInjectOption.js | 12 + .../config/jest/babelTransform.js | 2 +- .../react-scripts/config/jest/cssTransform.js | 2 +- .../config/jest/fileTransform.js | 2 +- .../config/jest/graphqlTransform.js | 18 + .../config/jest/typescriptTransform.js | 7 + packages/react-scripts/config/paths.js | 19 +- .../config/ssr/DevRebuildPlugin.js | 52 +++ .../react-scripts/config/ssr/style-loader.js | 4 + packages/react-scripts/config/webpack.base.js | 255 ++++++++++++++ .../config/webpack.config.dev.js | 228 +++++++++++++ .../react-scripts/config/webpack.config.js | 274 +++++++-------- .../config/webpack.config.prod.js | 309 +++++++++++++++++ .../config/webpack.config.ssr.js | 315 ++++++++++++++++++ .../config/webpack.ts-transformers.js | 13 + .../config/webpackDevServer.config.js | 6 +- .../monorepos/packages/comp1/index.js | 21 ++ .../monorepos/packages/comp1/index.test.js | 8 + .../monorepos/packages/comp1/package.json | 10 + .../monorepos/packages/comp2/index.js | 11 + .../monorepos/packages/comp2/index.test.js | 8 + .../monorepos/packages/comp2/package.json | 13 + .../monorepos/packages/cra-app1/.gitignore | 21 ++ .../monorepos/packages/cra-app1/package.json | 32 ++ .../packages/cra-app1/public/favicon.ico | Bin 0 -> 3870 bytes .../packages/cra-app1/public/index.html | 40 +++ .../packages/cra-app1/public/manifest.json | 15 + .../monorepos/packages/cra-app1/src/App.css | 28 ++ .../monorepos/packages/cra-app1/src/App.js | 24 ++ .../packages/cra-app1/src/App.test.js | 9 + .../monorepos/packages/cra-app1/src/index.css | 5 + .../monorepos/packages/cra-app1/src/index.js | 6 + .../monorepos/packages/cra-app1/src/logo.svg | 7 + .../fixtures/monorepos/yarn-ws/package.json | 4 + packages/react-scripts/package.json | 40 ++- packages/react-scripts/scripts/build.js | 138 +++++--- packages/react-scripts/scripts/eject.js | 12 +- packages/react-scripts/scripts/init.js | 143 ++++++-- packages/react-scripts/scripts/start.js | 6 +- packages/react-scripts/scripts/test.js | 12 +- .../scripts/utils/createDotEnv.js | 41 +++ .../scripts/utils/createJestConfig.js | 24 +- .../scripts/utils/verifyPackageTree.js | 5 +- .../scripts/utils/verifyTypeScriptSetup.js | 42 ++- .../react-scripts/template/_js/eslintrc.json | 8 + .../react-scripts/template/_js/jsconfig.json | 14 + .../react-scripts/template/_js/src/App.css | 32 ++ .../react-scripts/template/_js/src/App.js | 28 ++ .../template/_js/src/App.test.js | 9 + .../react-scripts/template/_js/src/index.css | 14 + .../react-scripts/template/_js/src/index.js | 12 + .../react-scripts/template/_js/src/logo.svg | 7 + .../template/_js/src/serviceWorker.js | 127 +++++++ .../react-scripts/template/_ts/src/App.css | 32 ++ .../template/_ts/src/App.test.tsx | 9 + .../react-scripts/template/_ts/src/App.tsx | 28 ++ .../react-scripts/template/_ts/src/index.css | 14 + .../react-scripts/template/_ts/src/index.tsx | 12 + .../react-scripts/template/_ts/src/logo.svg | 7 + .../template/_ts/src/serviceWorker.ts | 143 ++++++++ .../react-scripts/template/_ts/tsconfig.json | 40 +++ .../template/_ts/tsconfig.prod.json | 3 + .../template/_ts/tsconfig.ssr.json | 9 + .../template/_ts/tsconfig.test.json | 7 + .../react-scripts/template/_ts/tslint.json | 13 + .../template/_ts/typings/index.d.ts | 60 ++++ .../template/_ts/typings/react.extend.d.ts | 17 + packages/react-scripts/template/build.sh.js | 12 + packages/react-scripts/template/gitignore | 250 +++++++++++++- .../react-scripts/template/scm_build.sh.js | 14 + 72 files changed, 2901 insertions(+), 297 deletions(-) create mode 100644 packages/react-scripts/config/getWebpackInjectOption.js create mode 100644 packages/react-scripts/config/jest/graphqlTransform.js create mode 100644 packages/react-scripts/config/jest/typescriptTransform.js create mode 100644 packages/react-scripts/config/ssr/DevRebuildPlugin.js create mode 100644 packages/react-scripts/config/ssr/style-loader.js create mode 100644 packages/react-scripts/config/webpack.base.js create mode 100644 packages/react-scripts/config/webpack.config.dev.js create mode 100644 packages/react-scripts/config/webpack.config.prod.js create mode 100644 packages/react-scripts/config/webpack.config.ssr.js create mode 100644 packages/react-scripts/config/webpack.ts-transformers.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/comp1/index.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/comp1/index.test.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/comp1/package.json create mode 100644 packages/react-scripts/fixtures/monorepos/packages/comp2/index.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/comp2/index.test.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/comp2/package.json create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/.gitignore create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/package.json create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/public/favicon.ico create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/public/index.html create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/public/manifest.json create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/src/App.css create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/src/App.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/src/App.test.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/src/index.css create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/src/index.js create mode 100644 packages/react-scripts/fixtures/monorepos/packages/cra-app1/src/logo.svg create mode 100644 packages/react-scripts/fixtures/monorepos/yarn-ws/package.json create mode 100644 packages/react-scripts/scripts/utils/createDotEnv.js create mode 100644 packages/react-scripts/template/_js/eslintrc.json create mode 100644 packages/react-scripts/template/_js/jsconfig.json create mode 100644 packages/react-scripts/template/_js/src/App.css create mode 100644 packages/react-scripts/template/_js/src/App.js create mode 100644 packages/react-scripts/template/_js/src/App.test.js create mode 100644 packages/react-scripts/template/_js/src/index.css create mode 100644 packages/react-scripts/template/_js/src/index.js create mode 100644 packages/react-scripts/template/_js/src/logo.svg create mode 100644 packages/react-scripts/template/_js/src/serviceWorker.js create mode 100644 packages/react-scripts/template/_ts/src/App.css create mode 100644 packages/react-scripts/template/_ts/src/App.test.tsx create mode 100644 packages/react-scripts/template/_ts/src/App.tsx create mode 100644 packages/react-scripts/template/_ts/src/index.css create mode 100644 packages/react-scripts/template/_ts/src/index.tsx create mode 100644 packages/react-scripts/template/_ts/src/logo.svg create mode 100644 packages/react-scripts/template/_ts/src/serviceWorker.ts create mode 100644 packages/react-scripts/template/_ts/tsconfig.json create mode 100644 packages/react-scripts/template/_ts/tsconfig.prod.json create mode 100644 packages/react-scripts/template/_ts/tsconfig.ssr.json create mode 100644 packages/react-scripts/template/_ts/tsconfig.test.json create mode 100644 packages/react-scripts/template/_ts/tslint.json create mode 100644 packages/react-scripts/template/_ts/typings/index.d.ts create mode 100644 packages/react-scripts/template/_ts/typings/react.extend.d.ts create mode 100644 packages/react-scripts/template/build.sh.js create mode 100644 packages/react-scripts/template/scm_build.sh.js diff --git a/packages/react-scripts/README.md b/packages/react-scripts/README.md index 357131f0e80..eb4dda1d05b 100644 --- a/packages/react-scripts/README.md +++ b/packages/react-scripts/README.md @@ -1,7 +1,25 @@ -# react-scripts +# byted-react-scripts -This package includes scripts and configuration used by [Create React App](https://github.com/facebook/create-react-app).
+__usage:__ + +```sh +create-react-app --scripts-version=byted-react-scripts +``` + + + +This package includes scripts and configuration forked from [Create React App](https://github.com/facebook/create-react-app).
Please refer to its documentation: -- [Getting Started](https://github.com/facebook/create-react-app/blob/master/README.md#getting-started) – How to create a new app. -- [User Guide](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md) – How to develop apps bootstrapped with Create React App. +* [Getting Started](https://github.com/facebook/create-react-app/blob/master/README.md#getting-started) – How to create a new app. +* [User Guide](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md) – How to develop apps bootstrapped with Create React App. + +## .env config + - REACT_APP_REM_UNIT={number} + use px2rem + +- REACT_APP_HTML_INJECT + + default: true + + inject webpack assets into HTML template \ No newline at end of file diff --git a/packages/react-scripts/config/env.js b/packages/react-scripts/config/env.js index 7565cecd001..1e9316d0ca8 100644 --- a/packages/react-scripts/config/env.js +++ b/packages/react-scripts/config/env.js @@ -30,7 +30,7 @@ var dotenvFiles = [ // since normally you expect tests to produce the same // results for everyone NODE_ENV !== 'test' && `${paths.dotenv}.local`, - paths.dotenv, + paths.dotenv ].filter(Boolean); // Load environment variables from .env* files. Suppress warnings using silent @@ -42,7 +42,7 @@ dotenvFiles.forEach(dotenvFile => { if (fs.existsSync(dotenvFile)) { require('dotenv-expand')( require('dotenv').config({ - path: dotenvFile, + path: dotenvFile }) ); } @@ -84,7 +84,7 @@ function getClientEnvironment(publicUrl) { // For example, . // This should only be used as an escape hatch. Normally you would put // images into the `src` and `import` them in code to get their paths. - PUBLIC_URL: publicUrl, + PUBLIC_URL: publicUrl } ); // Stringify all values so we can feed into Webpack DefinePlugin @@ -92,7 +92,7 @@ function getClientEnvironment(publicUrl) { 'process.env': Object.keys(raw).reduce((env, key) => { env[key] = JSON.stringify(raw[key]); return env; - }, {}), + }, {}) }; return { raw, stringified }; diff --git a/packages/react-scripts/config/getWebpackInjectOption.js b/packages/react-scripts/config/getWebpackInjectOption.js new file mode 100644 index 00000000000..732b37bcc76 --- /dev/null +++ b/packages/react-scripts/config/getWebpackInjectOption.js @@ -0,0 +1,12 @@ +'use strict'; +module.exports = function getHtmlWebpackPluginInjectOption(env) { + const v = env.raw.REACT_APP_HTML_INJECT; + switch (true) { + case v === 'head' || v === 'body': + return v; + case v === 'false': + return false; + default: + return true; + } +}; diff --git a/packages/react-scripts/config/jest/babelTransform.js b/packages/react-scripts/config/jest/babelTransform.js index 7feed94c59a..890f0a2f127 100644 --- a/packages/react-scripts/config/jest/babelTransform.js +++ b/packages/react-scripts/config/jest/babelTransform.js @@ -12,5 +12,5 @@ const babelJest = require('babel-jest'); module.exports = babelJest.createTransformer({ presets: [require.resolve('babel-preset-react-app')], babelrc: false, - configFile: false, + configFile: false }); diff --git a/packages/react-scripts/config/jest/cssTransform.js b/packages/react-scripts/config/jest/cssTransform.js index 59053068f61..303852977b7 100644 --- a/packages/react-scripts/config/jest/cssTransform.js +++ b/packages/react-scripts/config/jest/cssTransform.js @@ -18,5 +18,5 @@ module.exports = { getCacheKey() { // The output is always the same. return 'cssTransform'; - }, + } }; diff --git a/packages/react-scripts/config/jest/fileTransform.js b/packages/react-scripts/config/jest/fileTransform.js index f442f0bbd86..d24a2c53b94 100644 --- a/packages/react-scripts/config/jest/fileTransform.js +++ b/packages/react-scripts/config/jest/fileTransform.js @@ -34,5 +34,5 @@ module.exports = { } return `module.exports = ${assetFilename};`; - }, + } }; diff --git a/packages/react-scripts/config/jest/graphqlTransform.js b/packages/react-scripts/config/jest/graphqlTransform.js new file mode 100644 index 00000000000..5b70f07d6f2 --- /dev/null +++ b/packages/react-scripts/config/jest/graphqlTransform.js @@ -0,0 +1,18 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2018-present, Facebook, Inc. + * Copyright (c) 2016 Remind + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +// @remove-on-eject-end +'use strict'; + +const loader = require('graphql-tag/loader'); + +module.exports = { + process(src) { + return loader.call({ cacheable() {} }, src); + }, +}; diff --git a/packages/react-scripts/config/jest/typescriptTransform.js b/packages/react-scripts/config/jest/typescriptTransform.js new file mode 100644 index 00000000000..e1a53374f80 --- /dev/null +++ b/packages/react-scripts/config/jest/typescriptTransform.js @@ -0,0 +1,7 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +'use strict'; + +const tsJest = require('ts-jest'); + +module.exports = tsJest; diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index b719054583b..8a7f85b37eb 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -57,7 +57,7 @@ const moduleFileExtensions = [ 'tsx', 'json', 'web.jsx', - 'jsx', + 'jsx' ]; // Resolve file paths in the same order as webpack @@ -81,15 +81,19 @@ module.exports = { appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appIndexJs: resolveModule(resolveApp, 'src/index'), + appIndexJsSSR: resolveModule(resolveApp, 'src/ssr'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), + appTsProdConfig: resolveApp('tsconfig.prod.json'), + appTsSSRConfig: resolveApp('tsconfig.ssr.json'), + appTsLint: resolveApp('tslint.json'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveModule(resolveApp, 'src/setupTests'), proxySetup: resolveApp('src/setupProxy.js'), appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), - servedPath: getServedPath(resolveApp('package.json')), + servedPath: getServedPath(resolveApp('package.json')) }; // @remove-on-eject-begin @@ -103,9 +107,14 @@ module.exports = { appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appIndexJs: resolveModule(resolveApp, 'src/index'), + appIndexJsSSR: resolveModule(resolveApp, 'src/ssr'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), + appTsTestConfig: resolveApp('tsconfig.test.json'), + appTsProdConfig: resolveApp('tsconfig.prod.json'), + appTsSSRConfig: resolveApp('tsconfig.ssr.json'), + appTsLint: resolveApp('tslint.json'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveModule(resolveApp, 'src/setupTests'), proxySetup: resolveApp('src/setupProxy.js'), @@ -137,6 +146,7 @@ if ( appPublic: resolveOwn('template/public'), appHtml: resolveOwn('template/public/index.html'), appIndexJs: resolveModule(resolveOwn, 'template/src/index'), + appIndexJsSSR: resolveModule(resolveOwn, 'template/src/ssr'), appPackageJson: resolveOwn('package.json'), appSrc: resolveOwn('template/src'), appTsConfig: resolveOwn('template/tsconfig.json'), @@ -144,6 +154,11 @@ if ( testsSetup: resolveModule(resolveOwn, 'template/src/setupTests'), proxySetup: resolveOwn('template/src/setupProxy.js'), appNodeModules: resolveOwn('node_modules'), + appTsConfig: resolveOwn('template/tsconfig.json'), + appTsProdConfig: resolveOwn('template/tsconfig.prod.json'), + appTsLint: resolveOwn('template/tslint.json'), + appTsTestConfig: resolveOwn('template/tsconfig.test.json'), + appTsSSRConfig: resolveOwn('template/tsconfig.ssr.json'), publicUrl: getPublicUrl(resolveOwn('package.json')), servedPath: getServedPath(resolveOwn('package.json')), // These properties only exist before ejecting: diff --git a/packages/react-scripts/config/ssr/DevRebuildPlugin.js b/packages/react-scripts/config/ssr/DevRebuildPlugin.js new file mode 100644 index 00000000000..05d844b9ab8 --- /dev/null +++ b/packages/react-scripts/config/ssr/DevRebuildPlugin.js @@ -0,0 +1,52 @@ +/* eslint-disable */ +const fork = require('child_process').fork; +const path = require('path'); +const paths = require('../paths'); +const fs = require('fs'); + +module.exports = class SSRDevRebuilder { + apply(compiler) { + compiler.plugin('emit', (compilation, callback) => { + // var changedFiles = Object.keys( + // compilation.fileTimestamps + // ).filter(watchfile => { + // return ( + // (this.prevTimestamps[watchfile] || this.startTime) < + // (compilation.fileTimestamps[watchfile] || Infinity) + // ); + // }); + + let ssrDefer = { resolve: null, reject: null, promise: null }; + ssrDefer.promise = new Promise((r, j) => { + ssrDefer.resolve = r; + ssrDefer.reject = j; + }); + + if (fs.existsSync(paths.appIndexJsSSR)) { + console.log('Creating ssr bundle...'); + const ssrCP = fork( + path.resolve(__dirname, '../webpack.config.ssr'), + [], + { + stdio: 'inherit', + env: process.env + } + ); + + ssrCP.once('error', err => { + console.log(err); + ssrDefer.resolve(); + ssrCP.removeAllListeners('exit'); + }); + ssrCP.once('exit', () => { + ssrDefer.resolve(); + }); + } else { + ssrDefer.resolve(); + } + + this.prevTimestamps = compilation.fileTimestamps; + ssrDefer.promise.then(callback); + }); + } +}; diff --git a/packages/react-scripts/config/ssr/style-loader.js b/packages/react-scripts/config/ssr/style-loader.js new file mode 100644 index 00000000000..e2f02cbc585 --- /dev/null +++ b/packages/react-scripts/config/ssr/style-loader.js @@ -0,0 +1,4 @@ +/* eslint-disable */ +module.exports = function(_source, _map) { + return 'export default "";'; +}; diff --git a/packages/react-scripts/config/webpack.base.js b/packages/react-scripts/config/webpack.base.js new file mode 100644 index 00000000000..d11564bb99d --- /dev/null +++ b/packages/react-scripts/config/webpack.base.js @@ -0,0 +1,255 @@ +'use strict'; + +const paths = require('./paths'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); +const isProduction = process.env.NODE_ENV === 'production'; +const happyPack = process.env.HAPPY_PACK === 'true'; +const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; +const getClientEnvironment = require('./env'); +const env = getClientEnvironment(''); +// @remove-on-eject-begin +const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); +// @remove-on-eject-end + +let cssType = 'sass'; +// 因为目前项目大多用的 sass 预处理,所以优先判断 sass 兼容 +try { + require.resolve('less-loader'); + cssType = 'less'; +} catch (e) { + void 0; +} + +// const useTypeScript = fs.existsSync(paths.appTsConfig); + +function getStyleLoader(options) { + const isLess = options && options.cssType === 'less'; + const isSass = options && options.cssType === 'sass'; + const isModules = options && options.modules; + + let styleRegex = /\.css$/; + let styleModuleRegex = /\.module\.css$/; + if (isSass) { + styleRegex = /\.(scss|sass)$/; + styleModuleRegex = /\.module\.(scss|sass)$/; + } else if (isLess) { + styleRegex = /\.less$/; + styleModuleRegex = /\.module\.less$/; + } + + const styleLoader = require.resolve('style-loader'); + + const miniCss = MiniCssExtractPlugin.loader; + + const cssLoader = { + loader: require.resolve('css-loader'), + options: { + importLoaders: isLess || isSass ? 2 : 1 + } + }; + if (isModules) { + cssLoader.options.modules = true; + cssLoader.options.getLocalIdent = getCSSModuleLocalIdent; + } + + const postCssLoader = { + loader: require.resolve('postcss-loader'), + options: { + ident: 'postcss', + plugins: () => + [ + require('postcss-flexbugs-fixes'), + require('postcss-preset-env')({ + autoprefixer: { + flexbox: 'no-2009' + }, + stage: 3 + }), + env.raw.REACT_APP_REM_UNIT && + require('postcss-px2rem')({ + remUnit: env.raw.REACT_APP_REM_UNIT + }) + ].filter(Boolean), + sourceMap: shouldUseSourceMap + } + }; + + const loaders = [ + isProduction ? miniCss : styleLoader, + cssLoader, + postCssLoader + ]; + + if (isSass) { + loaders.push({ + loader: require.resolve('sass-loader'), + options: { + sourceMap: shouldUseSourceMap + } + }); + } else if (isLess) { + loaders.push({ + loader: require.resolve('less-loader'), + options: { + sourceMap: shouldUseSourceMap + } + }); + } + + return { + test: isModules ? styleModuleRegex : styleRegex, + exclude: isModules ? '//' : styleModuleRegex, + use: loaders + }; +} + +module.exports.loaders = [ + // "url" loader works just like "file" loader but it also embeds + // assets smaller than specified size as data URLs to avoid requests. + { + test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], + loader: require.resolve('url-loader'), + options: { + limit: 10000, + name: 'static/media/[name].[hash:8].[ext]' + } + }, + // Process JS + { + test: /\.(js|mjs|jsx)$/, + include: paths.appSrc, + loader: require.resolve('babel-loader'), + options: { + customize: require.resolve('babel-preset-react-app/webpack-overrides'), + // @remove-on-eject-begin + babelrc: false, + configFile: false, + presets: [require.resolve('babel-preset-react-app')], + // Make sure we have a unique cache identifier, erring on the + // side of caution. + // We remove this when the user ejects because the default + // is sane and uses Babel options. Instead of options, we use + // the react-scripts and babel-preset-react-app versions. + cacheIdentifier: getCacheIdentifier('development', [ + 'babel-plugin-named-asset-import', + 'babel-preset-react-app', + 'react-dev-utils', + 'react-scripts' + ]), + // @remove-on-eject-end + plugins: [ + [ + require.resolve('babel-plugin-named-asset-import'), + { + loaderMap: { + svg: { + ReactComponent: '@svgr/webpack?-prettier,-svgo![path]' + } + } + } + ] + ], + // This is a feature of `babel-loader` for webpack (not Babel itself). + // It enables caching results in ./node_modules/.cache/babel-loader/ + // directory for faster rebuilds. + cacheDirectory: true, + // Don't waste time on Gzipping the cache + cacheCompression: false + } + }, + // Process any JS outside of the app with Babel. + // Unlike the application JS, we only compile the standard ES features. + { + test: /\.(js|mjs)$/, + exclude: /@babel(?:\/|\\{1,2})runtime/, + loader: require.resolve('babel-loader'), + options: { + babelrc: false, + configFile: false, + compact: false, + presets: [ + [ + require.resolve('babel-preset-react-app/dependencies'), + { helpers: true } + ] + ], + cacheDirectory: true, + // Don't waste time on Gzipping the cache + cacheCompression: false, + // @remove-on-eject-begin + cacheIdentifier: getCacheIdentifier('development', [ + 'babel-plugin-named-asset-import', + 'babel-preset-react-app', + 'react-dev-utils', + 'react-scripts' + ]), + // If an error happens in a package, it's possible to be + // because it was compiled. Thus, we don't want the browser + // debugger to show the original code. Instead, the code + // being evaluated would be much more helpful. + // @remove-on-eject-end + sourceMaps: false + } + }, + // Process TypeScript + { + test: /\.tsx?$/, + include: paths.srcPaths, + exclude: /[\\/]node_modules[\\/]/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + plugins: [ + require.resolve('@babel/plugin-syntax-dynamic-import'), + [ + require.resolve('babel-plugin-named-asset-import'), + { + loaderMap: { + svg: { + ReactComponent: '@svgr/webpack?-prettier,-svgo![path]' + } + } + } + ] + ], + cacheDirectory: true, + cacheCompression: false + } + }, + { + loader: require.resolve('ts-loader'), + options: { + happyPackMode: happyPack, + getCustomTransformers: require.resolve('./webpack.ts-transformers.js') + } + } + ] + }, + // Process Css + getStyleLoader(), + // Process Less|Sass + getStyleLoader({ cssType }), + // Process Css Modules + getStyleLoader({ modules: true }), + // Process Less|Sass Modules + getStyleLoader({ cssType, modules: true }), + // "file" loader makes sure assets end up in the `build` folder. + // When you `import` an asset, you get its filename. + // This loader doesn't use a "test" so it will catch all modules + // that fall through the other loaders. + { + loader: require.resolve('file-loader'), + // Exclude `js` and `ts` files to keep "css" loader working as it injects + // it's runtime that would otherwise be processed through "file" loader. + // Also exclude `html` and `json` extensions so they get processed + // by webpacks internal loaders. + exclude: [/\.(js|jsx|mjs)$/, /\.(ts|tsx)$/, /\.html$/, /\.json$/], + options: { + name: 'static/media/[name].[hash:8].[ext]' + } + } + // ** STOP ** Are you adding a new loader? + // Make sure to add the new loader(s) before the "file" loader. +]; diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js new file mode 100644 index 00000000000..34773962cd3 --- /dev/null +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -0,0 +1,228 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +// @remove-on-eject-end +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const resolve = require('resolve'); +const webpack = require('webpack'); +const PnpWebpackPlugin = require('pnp-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); +const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); +const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); +const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); +const getClientEnvironment = require('./env'); +const paths = require('./paths'); +const ManifestPlugin = require('webpack-manifest-plugin'); +// const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt'); +const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const { loaders } = require('./webpack.base'); +const getWebpackInjectOption = require('./getWebpackInjectOption'); +// Webpack uses `publicPath` to determine where the app is being served from. +// In development, we always serve from the root. This makes config easier. +const publicPath = '/'; +// `publicUrl` is just like `publicPath`, but we will provide it to our app +// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. +// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. +const publicUrl = ''; +// Get environment variables to inject into our app. +const env = getClientEnvironment(publicUrl); +// When true reduce polyfill bundle size. +const modernBrowserOnly = process.env.MODERN_BROWSER_ONLY === 'true'; + +// Check if TypeScript is setup +const useTypeScript = fs.existsSync(paths.appTsConfig); +// This is the development configuration. +// It is focused on developer experience and fast rebuilds. +// The production configuration is different and lives in a separate file. +module.exports = { + mode: 'development', + // You may want 'eval' instead if you prefer to see the compiled output in DevTools. + // See the discussion in https://github.com/facebook/create-react-app/issues/343 + devtool: 'cheap-module-source-map', + // These are the "entry points" to our application. + // This means they will be the "root" imports that are included in JS bundle. + entry: [ + // Include an alternative client for WebpackDevServer. A client's job is to + // connect to WebpackDevServer by a socket and get notified about changes. + // When you save a file, the client will either apply hot updates (in case + // of CSS changes), or refresh the page (in case of JS changes). When you + // make a syntax error, this client will display a syntax error overlay. + // Note: instead of the default WebpackDevServer client, we use a custom one + // to bring better experience for Create React App users. You can replace + // the line below with these two lines if you prefer the stock client: + // require.resolve('webpack-dev-server/client') + '?/', + // require.resolve('webpack/hot/dev-server'), + require.resolve('react-dev-utils/webpackHotDevClient'), + // Finally, this is your app's code: + paths.appIndexJs + // We include the app code last so that if there is a runtime error during + // initialization, it doesn't blow up the WebpackDevServer client, and + // changing JS code would still trigger a refresh. + ], + output: { + // Add /* filename */ comments to generated require()s in the output. + pathinfo: true, + // This does not produce a real file. It's just the virtual path that is + // served by WebpackDevServer in development. This is the JS bundle + // containing code from all our entry points, and the Webpack runtime. + filename: 'static/js/bundle.js', + // There are also additional JS chunk files if you use code splitting. + chunkFilename: 'static/js/[name].chunk.js', + // This is the URL that app is served from. We use "/" in development. + publicPath: publicPath, + // Point sourcemap entries to original disk location (format as URL on Windows) + devtoolModuleFilenameTemplate: info => + path.resolve(info.absoluteResourcePath).replace(/\\/g, '/') + }, + optimization: { + // Automatically split vendor and commons + // https://twitter.com/wSokra/status/969633336732905474 + // https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 + splitChunks: { + chunks: 'all', + name: true + }, + // Keep the runtime chunk seperated to enable long term caching + // https://twitter.com/wSokra/status/969679223278505985 + runtimeChunk: false + }, + resolve: { + // This allows you to set a fallback for where Webpack should look for modules. + // We placed these paths second because we want `node_modules` to "win" + // if there are any conflicts. This matches Node resolution mechanism. + // https://github.com/facebook/create-react-app/issues/253 + modules: ['node_modules'].concat( + // It is guaranteed to exist because we tweak it in `env.js` + process.env.NODE_PATH.split(path.delimiter).filter(Boolean) + ), + // These are the reasonable defaults supported by the Node ecosystem. + // We also include JSX as a common component filename extension to support + // some tools, although we do not recommend using it, see: + // https://github.com/facebook/create-react-app/issues/290 + // `web` extension prefixes have been added for better support + // for React Native Web. + extensions: paths.moduleFileExtensions + .map(ext => `.${ext}`) + .filter(ext => useTypeScript || !ext.includes('ts')), + alias: Object.assign( + {}, + modernBrowserOnly + ? undefined + : { + '@babel/runtime': path.dirname( + require.resolve('@babel/runtime/package.json') + ) + }, + { + // Support React Native Web + // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ + 'react-native': 'react-native-web' + } + ), + plugins: [ + // Adds support for installing with Plug'n'Play, leading to faster installs and adding + // guards against forgotten dependencies and such. + PnpWebpackPlugin, + // Prevents users from importing files from outside of src/ (or node_modules/). + // This often causes confusion because we only process files within src/ with babel. + // To fix this, we prevent you from importing files out of src/ -- if you'd like to, + // please link the files into your node_modules/ and let module-resolution kick in. + // Make sure your source files are compiled, as they will not be processed in any way. + new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), + useTypeScript && + new TsconfigPathsPlugin({ configFile: paths.appTsConfig }) + ].filter(Boolean) + }, + resolveLoader: { + plugins: [ + // Also related to Plug'n'Play, but this time it tells Webpack to load its loaders + // from the current package. + PnpWebpackPlugin.moduleLoader(module) + ] + }, + module: { + strictExportPresence: true, + rules: [ + // Disable require.ensure as it's not a standard language feature. + { parser: { requireEnsure: false } }, + + { oneOf: loaders } + ] + }, + plugins: [ + // Generates an `index.html` file with the