fix(adopt-a-pup): single file frontend build (#57)
* Ejected webpack build config
* Configure build in a single html file
12 files added
3 files modified
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const fs = require('fs'); |
| | | const path = require('path'); |
| | | const paths = require('./paths'); |
| | | |
| | | // Make sure that including paths.js after env.js will read .env variables. |
| | | delete require.cache[require.resolve('./paths')]; |
| | | |
| | | const NODE_ENV = process.env.NODE_ENV; |
| | | if (!NODE_ENV) { |
| | | throw new Error( |
| | | 'The NODE_ENV environment variable is required but was not specified.' |
| | | ); |
| | | } |
| | | |
| | | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use |
| | | const dotenvFiles = [ |
| | | `${paths.dotenv}.${NODE_ENV}.local`, |
| | | `${paths.dotenv}.${NODE_ENV}`, |
| | | // Don't include `.env.local` for `test` environment |
| | | // since normally you expect tests to produce the same |
| | | // results for everyone |
| | | NODE_ENV !== 'test' && `${paths.dotenv}.local`, |
| | | paths.dotenv, |
| | | ].filter(Boolean); |
| | | |
| | | // Load environment variables from .env* files. Suppress warnings using silent |
| | | // if this file is missing. dotenv will never modify any environment variables |
| | | // that have already been set. Variable expansion is supported in .env files. |
| | | // https://github.com/motdotla/dotenv |
| | | // https://github.com/motdotla/dotenv-expand |
| | | dotenvFiles.forEach(dotenvFile => { |
| | | if (fs.existsSync(dotenvFile)) { |
| | | require('dotenv-expand')( |
| | | require('dotenv').config({ |
| | | path: dotenvFile, |
| | | }) |
| | | ); |
| | | } |
| | | }); |
| | | |
| | | // We support resolving modules according to `NODE_PATH`. |
| | | // This lets you use absolute paths in imports inside large monorepos: |
| | | // https://github.com/facebook/create-react-app/issues/253. |
| | | // It works similar to `NODE_PATH` in Node itself: |
| | | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders |
| | | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. |
| | | // Otherwise, we risk importing Node.js core modules into an app instead of webpack shims. |
| | | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 |
| | | // We also resolve them to make sure all tools using them work consistently. |
| | | const appDirectory = fs.realpathSync(process.cwd()); |
| | | process.env.NODE_PATH = (process.env.NODE_PATH || '') |
| | | .split(path.delimiter) |
| | | .filter(folder => folder && !path.isAbsolute(folder)) |
| | | .map(folder => path.resolve(appDirectory, folder)) |
| | | .join(path.delimiter); |
| | | |
| | | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be |
| | | // injected into the application via DefinePlugin in webpack configuration. |
| | | const REACT_APP = /^REACT_APP_/i; |
| | | |
| | | function getClientEnvironment(publicUrl) { |
| | | const raw = Object.keys(process.env) |
| | | .filter(key => REACT_APP.test(key)) |
| | | .reduce( |
| | | (env, key) => { |
| | | env[key] = process.env[key]; |
| | | return env; |
| | | }, |
| | | { |
| | | // Useful for determining whether we’re running in production mode. |
| | | // Most importantly, it switches React into the correct mode. |
| | | NODE_ENV: process.env.NODE_ENV || 'development', |
| | | // Useful for resolving the correct path to static assets in `public`. |
| | | // For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />. |
| | | // 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, |
| | | // We support configuring the sockjs pathname during development. |
| | | // These settings let a developer run multiple simultaneous projects. |
| | | // They are used as the connection `hostname`, `pathname` and `port` |
| | | // in webpackHotDevClient. They are used as the `sockHost`, `sockPath` |
| | | // and `sockPort` options in webpack-dev-server. |
| | | WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST, |
| | | WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH, |
| | | WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT, |
| | | } |
| | | ); |
| | | // Stringify all values so we can feed into webpack DefinePlugin |
| | | const stringified = { |
| | | 'process.env': Object.keys(raw).reduce((env, key) => { |
| | | env[key] = JSON.stringify(raw[key]); |
| | | return env; |
| | | }, {}), |
| | | }; |
| | | |
| | | return { raw, stringified }; |
| | | } |
| | | |
| | | module.exports = getClientEnvironment; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const fs = require('fs'); |
| | | const path = require('path'); |
| | | const crypto = require('crypto'); |
| | | const chalk = require('react-dev-utils/chalk'); |
| | | const paths = require('./paths'); |
| | | |
| | | // Ensure the certificate and key provided are valid and if not |
| | | // throw an easy to debug error |
| | | function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { |
| | | let encrypted; |
| | | try { |
| | | // publicEncrypt will throw an error with an invalid cert |
| | | encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); |
| | | } catch (err) { |
| | | throw new Error( |
| | | `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}` |
| | | ); |
| | | } |
| | | |
| | | try { |
| | | // privateDecrypt will throw an error with an invalid key |
| | | crypto.privateDecrypt(key, encrypted); |
| | | } catch (err) { |
| | | throw new Error( |
| | | `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${ |
| | | err.message |
| | | }` |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // Read file and throw an error if it doesn't exist |
| | | function readEnvFile(file, type) { |
| | | if (!fs.existsSync(file)) { |
| | | throw new Error( |
| | | `You specified ${chalk.cyan( |
| | | type |
| | | )} in your env, but the file "${chalk.yellow(file)}" can't be found.` |
| | | ); |
| | | } |
| | | return fs.readFileSync(file); |
| | | } |
| | | |
| | | // Get the https config |
| | | // Return cert files if provided in env, otherwise just true or false |
| | | function getHttpsConfig() { |
| | | const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; |
| | | const isHttps = HTTPS === 'true'; |
| | | |
| | | if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { |
| | | const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE); |
| | | const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE); |
| | | const config = { |
| | | cert: readEnvFile(crtFile, 'SSL_CRT_FILE'), |
| | | key: readEnvFile(keyFile, 'SSL_KEY_FILE'), |
| | | }; |
| | | |
| | | validateKeyAndCerts({ ...config, keyFile, crtFile }); |
| | | return config; |
| | | } |
| | | return isHttps; |
| | | } |
| | | |
| | | module.exports = getHttpsConfig; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | // This is a custom Jest transformer turning style imports into empty objects. |
| | | // http://facebook.github.io/jest/docs/en/webpack.html |
| | | |
| | | module.exports = { |
| | | process() { |
| | | return 'module.exports = {};'; |
| | | }, |
| | | getCacheKey() { |
| | | // The output is always the same. |
| | | return 'cssTransform'; |
| | | }, |
| | | }; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const path = require('path'); |
| | | const camelcase = require('camelcase'); |
| | | |
| | | // This is a custom Jest transformer turning file imports into filenames. |
| | | // http://facebook.github.io/jest/docs/en/webpack.html |
| | | |
| | | module.exports = { |
| | | process(src, filename) { |
| | | const assetFilename = JSON.stringify(path.basename(filename)); |
| | | |
| | | if (filename.match(/\.svg$/)) { |
| | | // Based on how SVGR generates a component name: |
| | | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 |
| | | const pascalCaseFilename = camelcase(path.parse(filename).name, { |
| | | pascalCase: true, |
| | | }); |
| | | const componentName = `Svg${pascalCaseFilename}`; |
| | | return `const React = require('react'); |
| | | module.exports = { |
| | | __esModule: true, |
| | | default: ${assetFilename}, |
| | | ReactComponent: React.forwardRef(function ${componentName}(props, ref) { |
| | | return { |
| | | $$typeof: Symbol.for('react.element'), |
| | | type: 'svg', |
| | | ref: ref, |
| | | key: null, |
| | | props: Object.assign({}, props, { |
| | | children: ${assetFilename} |
| | | }) |
| | | }; |
| | | }), |
| | | };`; |
| | | } |
| | | |
| | | return `module.exports = ${assetFilename};`; |
| | | }, |
| | | }; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const fs = require('fs'); |
| | | const path = require('path'); |
| | | const paths = require('./paths'); |
| | | const chalk = require('react-dev-utils/chalk'); |
| | | const resolve = require('resolve'); |
| | | |
| | | /** |
| | | * Get additional module paths based on the baseUrl of a compilerOptions object. |
| | | * |
| | | * @param {Object} options |
| | | */ |
| | | function getAdditionalModulePaths(options = {}) { |
| | | const baseUrl = options.baseUrl; |
| | | |
| | | // We need to explicitly check for null and undefined (and not a falsy value) because |
| | | // TypeScript treats an empty string as `.`. |
| | | if (baseUrl == null) { |
| | | // If there's no baseUrl set we respect NODE_PATH |
| | | // Note that NODE_PATH is deprecated and will be removed |
| | | // in the next major release of create-react-app. |
| | | |
| | | const nodePath = process.env.NODE_PATH || ''; |
| | | return nodePath.split(path.delimiter).filter(Boolean); |
| | | } |
| | | |
| | | const baseUrlResolved = path.resolve(paths.appPath, baseUrl); |
| | | |
| | | // We don't need to do anything if `baseUrl` is set to `node_modules`. This is |
| | | // the default behavior. |
| | | if (path.relative(paths.appNodeModules, baseUrlResolved) === '') { |
| | | return null; |
| | | } |
| | | |
| | | // Allow the user set the `baseUrl` to `appSrc`. |
| | | if (path.relative(paths.appSrc, baseUrlResolved) === '') { |
| | | return [paths.appSrc]; |
| | | } |
| | | |
| | | // If the path is equal to the root directory we ignore it here. |
| | | // We don't want to allow importing from the root directly as source files are |
| | | // not transpiled outside of `src`. We do allow importing them with the |
| | | // absolute path (e.g. `src/Components/Button.js`) but we set that up with |
| | | // an alias. |
| | | if (path.relative(paths.appPath, baseUrlResolved) === '') { |
| | | return null; |
| | | } |
| | | |
| | | // Otherwise, throw an error. |
| | | throw new Error( |
| | | chalk.red.bold( |
| | | "Your project's `baseUrl` can only be set to `src` or `node_modules`." + |
| | | ' Create React App does not support other values at this time.' |
| | | ) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * Get webpack aliases based on the baseUrl of a compilerOptions object. |
| | | * |
| | | * @param {*} options |
| | | */ |
| | | function getWebpackAliases(options = {}) { |
| | | const baseUrl = options.baseUrl; |
| | | |
| | | if (!baseUrl) { |
| | | return {}; |
| | | } |
| | | |
| | | const baseUrlResolved = path.resolve(paths.appPath, baseUrl); |
| | | |
| | | if (path.relative(paths.appPath, baseUrlResolved) === '') { |
| | | return { |
| | | src: paths.appSrc, |
| | | }; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Get jest aliases based on the baseUrl of a compilerOptions object. |
| | | * |
| | | * @param {*} options |
| | | */ |
| | | function getJestAliases(options = {}) { |
| | | const baseUrl = options.baseUrl; |
| | | |
| | | if (!baseUrl) { |
| | | return {}; |
| | | } |
| | | |
| | | const baseUrlResolved = path.resolve(paths.appPath, baseUrl); |
| | | |
| | | if (path.relative(paths.appPath, baseUrlResolved) === '') { |
| | | return { |
| | | '^src/(.*)$': '<rootDir>/src/$1', |
| | | }; |
| | | } |
| | | } |
| | | |
| | | function getModules() { |
| | | // Check if TypeScript is setup |
| | | const hasTsConfig = fs.existsSync(paths.appTsConfig); |
| | | const hasJsConfig = fs.existsSync(paths.appJsConfig); |
| | | |
| | | if (hasTsConfig && hasJsConfig) { |
| | | throw new Error( |
| | | 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.' |
| | | ); |
| | | } |
| | | |
| | | let config; |
| | | |
| | | // If there's a tsconfig.json we assume it's a |
| | | // TypeScript project and set up the config |
| | | // based on tsconfig.json |
| | | if (hasTsConfig) { |
| | | const ts = require(resolve.sync('typescript', { |
| | | basedir: paths.appNodeModules, |
| | | })); |
| | | config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config; |
| | | // Otherwise we'll check if there is jsconfig.json |
| | | // for non TS projects. |
| | | } else if (hasJsConfig) { |
| | | config = require(paths.appJsConfig); |
| | | } |
| | | |
| | | config = config || {}; |
| | | const options = config.compilerOptions || {}; |
| | | |
| | | const additionalModulePaths = getAdditionalModulePaths(options); |
| | | |
| | | return { |
| | | additionalModulePaths: additionalModulePaths, |
| | | webpackAliases: getWebpackAliases(options), |
| | | jestAliases: getJestAliases(options), |
| | | hasTsConfig, |
| | | }; |
| | | } |
| | | |
| | | module.exports = getModules(); |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const path = require('path'); |
| | | const fs = require('fs'); |
| | | const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath'); |
| | | |
| | | // Make sure any symlinks in the project folder are resolved: |
| | | // https://github.com/facebook/create-react-app/issues/637 |
| | | const appDirectory = fs.realpathSync(process.cwd()); |
| | | const resolveApp = relativePath => path.resolve(appDirectory, relativePath); |
| | | |
| | | // We use `PUBLIC_URL` environment variable or "homepage" field to infer |
| | | // "public path" at which the app is served. |
| | | // webpack needs to know it to put the right <script> hrefs into HTML even in |
| | | // single-page apps that may serve index.html for nested URLs like /todos/42. |
| | | // We can't use a relative path in HTML because we don't want to load something |
| | | // like /todos/42/static/js/bundle.7289d.js. We have to know the root. |
| | | const publicUrlOrPath = getPublicUrlOrPath( |
| | | process.env.NODE_ENV === 'development', |
| | | require(resolveApp('package.json')).homepage, |
| | | process.env.PUBLIC_URL |
| | | ); |
| | | |
| | | const moduleFileExtensions = [ |
| | | 'web.mjs', |
| | | 'mjs', |
| | | 'web.js', |
| | | 'js', |
| | | 'web.ts', |
| | | 'ts', |
| | | 'web.tsx', |
| | | 'tsx', |
| | | 'json', |
| | | 'web.jsx', |
| | | 'jsx', |
| | | ]; |
| | | |
| | | // Resolve file paths in the same order as webpack |
| | | const resolveModule = (resolveFn, filePath) => { |
| | | const extension = moduleFileExtensions.find(extension => |
| | | fs.existsSync(resolveFn(`${filePath}.${extension}`)) |
| | | ); |
| | | |
| | | if (extension) { |
| | | return resolveFn(`${filePath}.${extension}`); |
| | | } |
| | | |
| | | return resolveFn(`${filePath}.js`); |
| | | }; |
| | | |
| | | // config after eject: we're in ./config/ |
| | | module.exports = { |
| | | dotenv: resolveApp('.env'), |
| | | appPath: resolveApp('.'), |
| | | appBuild: resolveApp('build'), |
| | | appPublic: resolveApp('public'), |
| | | appHtml: resolveApp('public/index.html'), |
| | | appIndexJs: resolveModule(resolveApp, 'src/index'), |
| | | appPackageJson: resolveApp('package.json'), |
| | | appSrc: resolveApp('src'), |
| | | appTsConfig: resolveApp('tsconfig.json'), |
| | | appJsConfig: resolveApp('jsconfig.json'), |
| | | yarnLockFile: resolveApp('yarn.lock'), |
| | | testsSetup: resolveModule(resolveApp, 'src/setupTests'), |
| | | proxySetup: resolveApp('src/setupProxy.js'), |
| | | appNodeModules: resolveApp('node_modules'), |
| | | publicUrlOrPath, |
| | | }; |
| | | |
| | | |
| | | |
| | | module.exports.moduleFileExtensions = moduleFileExtensions; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const { resolveModuleName } = require('ts-pnp'); |
| | | |
| | | exports.resolveModuleName = ( |
| | | typescript, |
| | | moduleName, |
| | | containingFile, |
| | | compilerOptions, |
| | | resolutionHost |
| | | ) => { |
| | | return resolveModuleName( |
| | | moduleName, |
| | | containingFile, |
| | | compilerOptions, |
| | | resolutionHost, |
| | | typescript.resolveModuleName |
| | | ); |
| | | }; |
| | | |
| | | exports.resolveTypeReferenceDirective = ( |
| | | typescript, |
| | | moduleName, |
| | | containingFile, |
| | | compilerOptions, |
| | | resolutionHost |
| | | ) => { |
| | | return resolveModuleName( |
| | | moduleName, |
| | | containingFile, |
| | | compilerOptions, |
| | | resolutionHost, |
| | | typescript.resolveTypeReferenceDirective |
| | | ); |
| | | }; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const fs = require('fs'); |
| | | const path = require('path'); |
| | | const webpack = require('webpack'); |
| | | const resolve = require('resolve'); |
| | | const PnpWebpackPlugin = require('pnp-webpack-plugin'); |
| | | const HtmlWebpackPlugin = require('html-webpack-plugin'); |
| | | const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); |
| | | const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); |
| | | const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); |
| | | const TerserPlugin = require('terser-webpack-plugin'); |
| | | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); |
| | | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); |
| | | const safePostCssParser = require('postcss-safe-parser'); |
| | | const ManifestPlugin = require('webpack-manifest-plugin'); |
| | | const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); |
| | | const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); |
| | | const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); |
| | | const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); |
| | | const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); |
| | | const paths = require('./paths'); |
| | | const modules = require('./modules'); |
| | | const getClientEnvironment = require('./env'); |
| | | const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); |
| | | const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); |
| | | const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); |
| | | |
| | | const postcssNormalize = require('postcss-normalize'); |
| | | |
| | | const appPackageJson = require(paths.appPackageJson); |
| | | |
| | | // Source maps are resource heavy and can cause out of memory issue for large source files. |
| | | const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; |
| | | // Some apps do not need the benefits of saving a web request, so not inlining the chunk |
| | | // makes for a smoother build process. |
| | | const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; |
| | | |
| | | const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true'; |
| | | |
| | | const imageInlineSizeLimit = parseInt( |
| | | process.env.IMAGE_INLINE_SIZE_LIMIT || '10000' |
| | | ); |
| | | |
| | | // Check if TypeScript is setup |
| | | const useTypeScript = fs.existsSync(paths.appTsConfig); |
| | | |
| | | // style files regexes |
| | | const cssRegex = /\.css$/; |
| | | const cssModuleRegex = /\.module\.css$/; |
| | | const sassRegex = /\.(scss|sass)$/; |
| | | const sassModuleRegex = /\.module\.(scss|sass)$/; |
| | | |
| | | // This is the production and development configuration. |
| | | // It is focused on developer experience, fast rebuilds, and a minimal bundle. |
| | | module.exports = function(webpackEnv) { |
| | | const isEnvDevelopment = webpackEnv === 'development'; |
| | | const isEnvProduction = webpackEnv === 'production'; |
| | | |
| | | // Variable used for enabling profiling in Production |
| | | // passed into alias object. Uses a flag if passed into the build command |
| | | const isEnvProductionProfile = |
| | | isEnvProduction && process.argv.includes('--profile'); |
| | | |
| | | // We will provide `paths.publicUrlOrPath` to our app |
| | | // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. |
| | | // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. |
| | | // Get environment variables to inject into our app. |
| | | const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1)); |
| | | |
| | | // common function to get style loaders |
| | | const getStyleLoaders = (cssOptions, preProcessor) => { |
| | | const loaders = [ |
| | | isEnvDevelopment && require.resolve('style-loader'), |
| | | isEnvProduction && { |
| | | loader: MiniCssExtractPlugin.loader, |
| | | // css is located in `static/css`, use '../../' to locate index.html folder |
| | | // in production `paths.publicUrlOrPath` can be a relative path |
| | | options: paths.publicUrlOrPath.startsWith('.') |
| | | ? { publicPath: '../../' } |
| | | : {}, |
| | | }, |
| | | { |
| | | loader: require.resolve('css-loader'), |
| | | options: cssOptions, |
| | | }, |
| | | { |
| | | // Options for PostCSS as we reference these options twice |
| | | // Adds vendor prefixing based on your specified browser support in |
| | | // package.json |
| | | loader: require.resolve('postcss-loader'), |
| | | options: { |
| | | // Necessary for external CSS imports to work |
| | | // https://github.com/facebook/create-react-app/issues/2677 |
| | | ident: 'postcss', |
| | | plugins: () => [ |
| | | require('postcss-flexbugs-fixes'), |
| | | require('postcss-preset-env')({ |
| | | autoprefixer: { |
| | | flexbox: 'no-2009', |
| | | }, |
| | | stage: 3, |
| | | }), |
| | | // Adds PostCSS Normalize as the reset css with default options, |
| | | // so that it honors browserslist config in package.json |
| | | // which in turn let's users customize the target behavior as per their needs. |
| | | postcssNormalize(), |
| | | ], |
| | | sourceMap: isEnvProduction && shouldUseSourceMap, |
| | | }, |
| | | }, |
| | | ].filter(Boolean); |
| | | if (preProcessor) { |
| | | loaders.push( |
| | | { |
| | | loader: require.resolve('resolve-url-loader'), |
| | | options: { |
| | | sourceMap: isEnvProduction && shouldUseSourceMap, |
| | | }, |
| | | }, |
| | | { |
| | | loader: require.resolve(preProcessor), |
| | | options: { |
| | | sourceMap: true, |
| | | }, |
| | | } |
| | | ); |
| | | } |
| | | return loaders; |
| | | }; |
| | | |
| | | return { |
| | | mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development', |
| | | // Stop compilation early in production |
| | | bail: isEnvProduction, |
| | | devtool: isEnvProduction |
| | | ? shouldUseSourceMap |
| | | ? 'source-map' |
| | | : false |
| | | : isEnvDevelopment && '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'), |
| | | isEnvDevelopment && |
| | | 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. |
| | | ].filter(Boolean), |
| | | output: { |
| | | // The build folder. |
| | | path: isEnvProduction ? paths.appBuild : undefined, |
| | | // Add /* filename */ comments to generated require()s in the output. |
| | | pathinfo: isEnvDevelopment, |
| | | // There will be one main bundle, and one file per asynchronous chunk. |
| | | // In development, it does not produce real files. |
| | | filename: isEnvProduction |
| | | ? 'static/js/[name].[contenthash:8].js' |
| | | : isEnvDevelopment && 'static/js/bundle.js', |
| | | // TODO: remove this when upgrading to webpack 5 |
| | | futureEmitAssets: true, |
| | | // There are also additional JS chunk files if you use code splitting. |
| | | chunkFilename: isEnvProduction |
| | | ? 'static/js/[name].[contenthash:8].chunk.js' |
| | | : isEnvDevelopment && 'static/js/[name].chunk.js', |
| | | // webpack uses `publicPath` to determine where the app is being served from. |
| | | // It requires a trailing slash, or the file assets will get an incorrect path. |
| | | // We inferred the "public path" (such as / or /my-project) from homepage. |
| | | publicPath: paths.publicUrlOrPath, |
| | | // Point sourcemap entries to original disk location (format as URL on Windows) |
| | | devtoolModuleFilenameTemplate: isEnvProduction |
| | | ? info => |
| | | path |
| | | .relative(paths.appSrc, info.absoluteResourcePath) |
| | | .replace(/\\/g, '/') |
| | | : isEnvDevelopment && |
| | | (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), |
| | | // Prevents conflicts when multiple webpack runtimes (from different apps) |
| | | // are used on the same page. |
| | | jsonpFunction: `webpackJsonp${appPackageJson.name}`, |
| | | // this defaults to 'window', but by setting it to 'this' then |
| | | // module chunks which are built will work in web workers as well. |
| | | globalObject: 'this', |
| | | }, |
| | | optimization: { |
| | | minimize: isEnvProduction, |
| | | minimizer: [ |
| | | // This is only used in production mode |
| | | new TerserPlugin({ |
| | | terserOptions: { |
| | | parse: { |
| | | // We want terser to parse ecma 8 code. However, we don't want it |
| | | // to apply any minification steps that turns valid ecma 5 code |
| | | // into invalid ecma 5 code. This is why the 'compress' and 'output' |
| | | // sections only apply transformations that are ecma 5 safe |
| | | // https://github.com/facebook/create-react-app/pull/4234 |
| | | ecma: 8, |
| | | }, |
| | | compress: { |
| | | ecma: 5, |
| | | warnings: false, |
| | | // Disabled because of an issue with Uglify breaking seemingly valid code: |
| | | // https://github.com/facebook/create-react-app/issues/2376 |
| | | // Pending further investigation: |
| | | // https://github.com/mishoo/UglifyJS2/issues/2011 |
| | | comparisons: false, |
| | | // Disabled because of an issue with Terser breaking valid code: |
| | | // https://github.com/facebook/create-react-app/issues/5250 |
| | | // Pending further investigation: |
| | | // https://github.com/terser-js/terser/issues/120 |
| | | inline: 2, |
| | | }, |
| | | mangle: { |
| | | safari10: true, |
| | | }, |
| | | // Added for profiling in devtools |
| | | keep_classnames: isEnvProductionProfile, |
| | | keep_fnames: isEnvProductionProfile, |
| | | output: { |
| | | ecma: 5, |
| | | comments: false, |
| | | // Turned on because emoji and regex is not minified properly using default |
| | | // https://github.com/facebook/create-react-app/issues/2488 |
| | | ascii_only: true, |
| | | }, |
| | | }, |
| | | sourceMap: shouldUseSourceMap, |
| | | }), |
| | | // This is only used in production mode |
| | | new OptimizeCSSAssetsPlugin({ |
| | | cssProcessorOptions: { |
| | | parser: safePostCssParser, |
| | | map: shouldUseSourceMap |
| | | ? { |
| | | // `inline: false` forces the sourcemap to be output into a |
| | | // separate file |
| | | inline: false, |
| | | // `annotation: true` appends the sourceMappingURL to the end of |
| | | // the css file, helping the browser find the sourcemap |
| | | annotation: true, |
| | | } |
| | | : false, |
| | | }, |
| | | cssProcessorPluginOptions: { |
| | | preset: ['default', { minifyFontValues: { removeQuotes: false } }], |
| | | }, |
| | | }), |
| | | ], |
| | | // 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: false, |
| | | }, |
| | | // Keep the runtime chunk separated to enable long term caching |
| | | // https://twitter.com/wSokra/status/969679223278505985 |
| | | // https://github.com/facebook/create-react-app/issues/5358 |
| | | runtimeChunk: { |
| | | name: entrypoint => `runtime-${entrypoint.name}`, |
| | | }, |
| | | }, |
| | | 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', paths.appNodeModules].concat( |
| | | modules.additionalModulePaths || [] |
| | | ), |
| | | // 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: { |
| | | // 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', |
| | | // Allows for better profiling with ReactDevTools |
| | | ...(isEnvProductionProfile && { |
| | | 'react-dom$': 'react-dom/profiling', |
| | | 'scheduler/tracing': 'scheduler/tracing-profiling', |
| | | }), |
| | | ...(modules.webpackAliases || {}), |
| | | }, |
| | | 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]), |
| | | ], |
| | | }, |
| | | 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 } }, |
| | | |
| | | // First, run the linter. |
| | | // It's important to do this before Babel processes the JS. |
| | | { |
| | | test: /\.(js|mjs|jsx|ts|tsx)$/, |
| | | enforce: 'pre', |
| | | use: [ |
| | | { |
| | | options: { |
| | | cache: true, |
| | | formatter: require.resolve('react-dev-utils/eslintFormatter'), |
| | | eslintPath: require.resolve('eslint'), |
| | | resolvePluginsRelativeTo: __dirname, |
| | | |
| | | }, |
| | | loader: require.resolve('eslint-loader'), |
| | | }, |
| | | ], |
| | | include: paths.appSrc, |
| | | }, |
| | | { |
| | | // "oneOf" will traverse all following loaders until one will |
| | | // match the requirements. When no loader matches it will fall |
| | | // back to the "file" loader at the end of the loader list. |
| | | oneOf: [ |
| | | // "url" loader works like "file" loader except that it embeds assets |
| | | // smaller than specified limit in bytes as data URLs to avoid requests. |
| | | // A missing `test` is equivalent to a match. |
| | | { |
| | | test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], |
| | | loader: require.resolve('url-loader'), |
| | | options: { |
| | | limit: imageInlineSizeLimit, |
| | | name: 'static/media/[name].[hash:8].[ext]', |
| | | }, |
| | | }, |
| | | // Process application JS with Babel. |
| | | // The preset includes JSX, Flow, TypeScript, and some ESnext features. |
| | | { |
| | | test: /\.(js|mjs|jsx|ts|tsx)$/, |
| | | include: paths.appSrc, |
| | | loader: require.resolve('babel-loader'), |
| | | options: { |
| | | customize: require.resolve( |
| | | 'babel-preset-react-app/webpack-overrides' |
| | | ), |
| | | |
| | | plugins: [ |
| | | [ |
| | | require.resolve('babel-plugin-named-asset-import'), |
| | | { |
| | | loaderMap: { |
| | | svg: { |
| | | ReactComponent: |
| | | '@svgr/webpack?-svgo,+titleProp,+ref![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, |
| | | // See #6846 for context on why cacheCompression is disabled |
| | | cacheCompression: false, |
| | | compact: isEnvProduction, |
| | | }, |
| | | }, |
| | | // 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, |
| | | // See #6846 for context on why cacheCompression is disabled |
| | | cacheCompression: false, |
| | | |
| | | // Babel sourcemaps are needed for debugging into node_modules |
| | | // code. Without the options below, debuggers like VSCode |
| | | // show incorrect code and set breakpoints on the wrong lines. |
| | | sourceMaps: shouldUseSourceMap, |
| | | inputSourceMap: shouldUseSourceMap, |
| | | }, |
| | | }, |
| | | // "postcss" loader applies autoprefixer to our CSS. |
| | | // "css" loader resolves paths in CSS and adds assets as dependencies. |
| | | // "style" loader turns CSS into JS modules that inject <style> tags. |
| | | // In production, we use MiniCSSExtractPlugin to extract that CSS |
| | | // to a file, but in development "style" loader enables hot editing |
| | | // of CSS. |
| | | // By default we support CSS Modules with the extension .module.css |
| | | { |
| | | test: cssRegex, |
| | | exclude: cssModuleRegex, |
| | | use: getStyleLoaders({ |
| | | importLoaders: 1, |
| | | sourceMap: isEnvProduction && shouldUseSourceMap, |
| | | }), |
| | | // Don't consider CSS imports dead code even if the |
| | | // containing package claims to have no side effects. |
| | | // Remove this when webpack adds a warning or an error for this. |
| | | // See https://github.com/webpack/webpack/issues/6571 |
| | | sideEffects: true, |
| | | }, |
| | | // Adds support for CSS Modules (https://github.com/css-modules/css-modules) |
| | | // using the extension .module.css |
| | | { |
| | | test: cssModuleRegex, |
| | | use: getStyleLoaders({ |
| | | importLoaders: 1, |
| | | sourceMap: isEnvProduction && shouldUseSourceMap, |
| | | modules: { |
| | | getLocalIdent: getCSSModuleLocalIdent, |
| | | }, |
| | | }), |
| | | }, |
| | | // Opt-in support for SASS (using .scss or .sass extensions). |
| | | // By default we support SASS Modules with the |
| | | // extensions .module.scss or .module.sass |
| | | { |
| | | test: sassRegex, |
| | | exclude: sassModuleRegex, |
| | | use: getStyleLoaders( |
| | | { |
| | | importLoaders: 3, |
| | | sourceMap: isEnvProduction && shouldUseSourceMap, |
| | | }, |
| | | 'sass-loader' |
| | | ), |
| | | // Don't consider CSS imports dead code even if the |
| | | // containing package claims to have no side effects. |
| | | // Remove this when webpack adds a warning or an error for this. |
| | | // See https://github.com/webpack/webpack/issues/6571 |
| | | sideEffects: true, |
| | | }, |
| | | // Adds support for CSS Modules, but using SASS |
| | | // using the extension .module.scss or .module.sass |
| | | { |
| | | test: sassModuleRegex, |
| | | use: getStyleLoaders( |
| | | { |
| | | importLoaders: 3, |
| | | sourceMap: isEnvProduction && shouldUseSourceMap, |
| | | modules: { |
| | | getLocalIdent: getCSSModuleLocalIdent, |
| | | }, |
| | | }, |
| | | 'sass-loader' |
| | | ), |
| | | }, |
| | | // "file" loader makes sure those assets get served by WebpackDevServer. |
| | | // When you `import` an asset, you get its (virtual) filename. |
| | | // In production, they would get copied to the `build` folder. |
| | | // 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` files to keep "css" loader working as it injects |
| | | // its 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|mjs|jsx|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. |
| | | ], |
| | | }, |
| | | ], |
| | | }, |
| | | plugins: [ |
| | | // Generates an `index.html` file with the <script> injected. |
| | | new HtmlWebpackPlugin( |
| | | Object.assign( |
| | | {}, |
| | | { |
| | | inject: true, |
| | | template: paths.appHtml, |
| | | inlineSource: '.(js|css)$' |
| | | }, |
| | | isEnvProduction |
| | | ? { |
| | | minify: { |
| | | removeComments: true, |
| | | collapseWhitespace: true, |
| | | removeRedundantAttributes: true, |
| | | useShortDoctype: true, |
| | | removeEmptyAttributes: true, |
| | | removeStyleLinkTypeAttributes: true, |
| | | keepClosingSlash: true, |
| | | minifyJS: true, |
| | | minifyCSS: true, |
| | | minifyURLs: true, |
| | | }, |
| | | } |
| | | : undefined |
| | | ) |
| | | ), |
| | | // Inlines the webpack runtime script. This script is too small to warrant |
| | | // a network request. |
| | | // https://github.com/facebook/create-react-app/issues/5358 |
| | | isEnvProduction && |
| | | shouldInlineRuntimeChunk && |
| | | new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]), |
| | | // Includes the whole bundle in index.html in production |
| | | // This is necessary for our canary lab to work. |
| | | // If we load js and css files, the canary feature could respond |
| | | // with a different version for each of these files |
| | | isEnvProduction && |
| | | new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin), |
| | | // Makes some environment variables available in index.html. |
| | | // The public URL is available as %PUBLIC_URL% in index.html, e.g.: |
| | | // <link rel="icon" href="%PUBLIC_URL%/favicon.ico"> |
| | | // It will be an empty string unless you specify "homepage" |
| | | // in `package.json`, in which case it will be the pathname of that URL. |
| | | new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), |
| | | // This gives some necessary context to module not found errors, such as |
| | | // the requesting resource. |
| | | new ModuleNotFoundPlugin(paths.appPath), |
| | | // Makes some environment variables available to the JS code, for example: |
| | | // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. |
| | | // It is absolutely essential that NODE_ENV is set to production |
| | | // during a production build. |
| | | // Otherwise React will be compiled in the very slow development mode. |
| | | new webpack.DefinePlugin(env.stringified), |
| | | // This is necessary to emit hot updates (currently CSS only): |
| | | isEnvDevelopment && new webpack.HotModuleReplacementPlugin(), |
| | | // Watcher doesn't work well if you mistype casing in a path so we use |
| | | // a plugin that prints an error when you attempt to do this. |
| | | // See https://github.com/facebook/create-react-app/issues/240 |
| | | isEnvDevelopment && new CaseSensitivePathsPlugin(), |
| | | // If you require a missing module and then `npm install` it, you still have |
| | | // to restart the development server for webpack to discover it. This plugin |
| | | // makes the discovery automatic so you don't have to restart. |
| | | // See https://github.com/facebook/create-react-app/issues/186 |
| | | isEnvDevelopment && |
| | | new WatchMissingNodeModulesPlugin(paths.appNodeModules), |
| | | isEnvProduction && |
| | | new MiniCssExtractPlugin({ |
| | | // Options similar to the same options in webpackOptions.output |
| | | // both options are optional |
| | | filename: 'static/css/[name].[contenthash:8].css', |
| | | chunkFilename: 'static/css/[name].[contenthash:8].chunk.css', |
| | | }), |
| | | // Generate an asset manifest file with the following content: |
| | | // - "files" key: Mapping of all asset filenames to their corresponding |
| | | // output file so that tools can pick it up without having to parse |
| | | // `index.html` |
| | | // - "entrypoints" key: Array of files which are included in `index.html`, |
| | | // can be used to reconstruct the HTML if necessary |
| | | new ManifestPlugin({ |
| | | fileName: 'asset-manifest.json', |
| | | publicPath: paths.publicUrlOrPath, |
| | | generate: (seed, files, entrypoints) => { |
| | | const manifestFiles = files.reduce((manifest, file) => { |
| | | manifest[file.name] = file.path; |
| | | return manifest; |
| | | }, seed); |
| | | const entrypointFiles = entrypoints.main.filter( |
| | | fileName => !fileName.endsWith('.map') |
| | | ); |
| | | |
| | | return { |
| | | files: manifestFiles, |
| | | entrypoints: entrypointFiles, |
| | | }; |
| | | }, |
| | | }), |
| | | // Moment.js is an extremely popular library that bundles large locale files |
| | | // by default due to how webpack interprets its code. This is a practical |
| | | // solution that requires the user to opt into importing specific locales. |
| | | // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack |
| | | // You can remove this if you don't use Moment.js: |
| | | new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), |
| | | // Generate a service worker script that will precache, and keep up to date, |
| | | // the HTML & assets that are part of the webpack build. |
| | | isEnvProduction && |
| | | new WorkboxWebpackPlugin.GenerateSW({ |
| | | clientsClaim: true, |
| | | exclude: [/\.map$/, /asset-manifest\.json$/], |
| | | importWorkboxFrom: 'cdn', |
| | | navigateFallback: paths.publicUrlOrPath + 'index.html', |
| | | navigateFallbackBlacklist: [ |
| | | // Exclude URLs starting with /_, as they're likely an API call |
| | | new RegExp('^/_'), |
| | | // Exclude any URLs whose last part seems to be a file extension |
| | | // as they're likely a resource and not a SPA route. |
| | | // URLs containing a "?" character won't be blacklisted as they're likely |
| | | // a route with query params (e.g. auth callbacks). |
| | | new RegExp('/[^/?]+\\.[^/]+$'), |
| | | ], |
| | | }), |
| | | // TypeScript type checking |
| | | useTypeScript && |
| | | new ForkTsCheckerWebpackPlugin({ |
| | | typescript: resolve.sync('typescript', { |
| | | basedir: paths.appNodeModules, |
| | | }), |
| | | async: isEnvDevelopment, |
| | | useTypescriptIncrementalApi: true, |
| | | checkSyntacticErrors: true, |
| | | resolveModuleNameModule: process.versions.pnp |
| | | ? `${__dirname}/pnpTs.js` |
| | | : undefined, |
| | | resolveTypeReferenceDirectiveModule: process.versions.pnp |
| | | ? `${__dirname}/pnpTs.js` |
| | | : undefined, |
| | | tsconfig: paths.appTsConfig, |
| | | reportFiles: [ |
| | | '**', |
| | | '!**/__tests__/**', |
| | | '!**/?(*.)(spec|test).*', |
| | | '!**/src/setupProxy.*', |
| | | '!**/src/setupTests.*', |
| | | ], |
| | | silent: true, |
| | | // The formatter is invoked directly in WebpackDevServerUtils during development |
| | | formatter: isEnvProduction ? typescriptFormatter : undefined, |
| | | }), |
| | | ].filter(Boolean), |
| | | // Some libraries import Node modules but don't use them in the browser. |
| | | // Tell webpack to provide empty mocks for them so importing them works. |
| | | node: { |
| | | module: 'empty', |
| | | dgram: 'empty', |
| | | dns: 'mock', |
| | | fs: 'empty', |
| | | http2: 'empty', |
| | | net: 'empty', |
| | | tls: 'empty', |
| | | child_process: 'empty', |
| | | }, |
| | | // Turn off performance processing because we utilize |
| | | // our own hints via the FileSizeReporter |
| | | performance: false, |
| | | }; |
| | | }; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | const fs = require('fs'); |
| | | const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); |
| | | const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); |
| | | const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); |
| | | const ignoredFiles = require('react-dev-utils/ignoredFiles'); |
| | | const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware'); |
| | | const paths = require('./paths'); |
| | | const getHttpsConfig = require('./getHttpsConfig'); |
| | | |
| | | const host = process.env.HOST || '0.0.0.0'; |
| | | const sockHost = process.env.WDS_SOCKET_HOST; |
| | | const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node' |
| | | const sockPort = process.env.WDS_SOCKET_PORT; |
| | | |
| | | module.exports = function(proxy, allowedHost) { |
| | | return { |
| | | // WebpackDevServer 2.4.3 introduced a security fix that prevents remote |
| | | // websites from potentially accessing local content through DNS rebinding: |
| | | // https://github.com/webpack/webpack-dev-server/issues/887 |
| | | // https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a |
| | | // However, it made several existing use cases such as development in cloud |
| | | // environment or subdomains in development significantly more complicated: |
| | | // https://github.com/facebook/create-react-app/issues/2271 |
| | | // https://github.com/facebook/create-react-app/issues/2233 |
| | | // While we're investigating better solutions, for now we will take a |
| | | // compromise. Since our WDS configuration only serves files in the `public` |
| | | // folder we won't consider accessing them a vulnerability. However, if you |
| | | // use the `proxy` feature, it gets more dangerous because it can expose |
| | | // remote code execution vulnerabilities in backends like Django and Rails. |
| | | // So we will disable the host check normally, but enable it if you have |
| | | // specified the `proxy` setting. Finally, we let you override it if you |
| | | // really know what you're doing with a special environment variable. |
| | | disableHostCheck: |
| | | !proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', |
| | | // Enable gzip compression of generated files. |
| | | compress: true, |
| | | // Silence WebpackDevServer's own logs since they're generally not useful. |
| | | // It will still show compile warnings and errors with this setting. |
| | | clientLogLevel: 'none', |
| | | // By default WebpackDevServer serves physical files from current directory |
| | | // in addition to all the virtual build products that it serves from memory. |
| | | // This is confusing because those files won’t automatically be available in |
| | | // production build folder unless we copy them. However, copying the whole |
| | | // project directory is dangerous because we may expose sensitive files. |
| | | // Instead, we establish a convention that only files in `public` directory |
| | | // get served. Our build script will copy `public` into the `build` folder. |
| | | // In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%: |
| | | // <link rel="icon" href="%PUBLIC_URL%/favicon.ico"> |
| | | // In JavaScript code, you can access it with `process.env.PUBLIC_URL`. |
| | | // Note that we only recommend to use `public` folder as an escape hatch |
| | | // for files like `favicon.ico`, `manifest.json`, and libraries that are |
| | | // for some reason broken when imported through webpack. If you just want to |
| | | // use an image, put it in `src` and `import` it from JavaScript instead. |
| | | contentBase: paths.appPublic, |
| | | contentBasePublicPath: paths.publicUrlOrPath, |
| | | // By default files from `contentBase` will not trigger a page reload. |
| | | watchContentBase: true, |
| | | // Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint |
| | | // for the WebpackDevServer client so it can learn when the files were |
| | | // updated. The WebpackDevServer client is included as an entry point |
| | | // in the webpack development configuration. Note that only changes |
| | | // to CSS are currently hot reloaded. JS changes will refresh the browser. |
| | | hot: true, |
| | | // Use 'ws' instead of 'sockjs-node' on server since we're using native |
| | | // websockets in `webpackHotDevClient`. |
| | | transportMode: 'ws', |
| | | // Prevent a WS client from getting injected as we're already including |
| | | // `webpackHotDevClient`. |
| | | injectClient: false, |
| | | // Enable custom sockjs pathname for websocket connection to hot reloading server. |
| | | // Enable custom sockjs hostname, pathname and port for websocket connection |
| | | // to hot reloading server. |
| | | sockHost, |
| | | sockPath, |
| | | sockPort, |
| | | // It is important to tell WebpackDevServer to use the same "publicPath" path as |
| | | // we specified in the webpack config. When homepage is '.', default to serving |
| | | // from the root. |
| | | // remove last slash so user can land on `/test` instead of `/test/` |
| | | publicPath: paths.publicUrlOrPath.slice(0, -1), |
| | | // WebpackDevServer is noisy by default so we emit custom message instead |
| | | // by listening to the compiler events with `compiler.hooks[...].tap` calls above. |
| | | quiet: true, |
| | | // Reportedly, this avoids CPU overload on some systems. |
| | | // https://github.com/facebook/create-react-app/issues/293 |
| | | // src/node_modules is not ignored to support absolute imports |
| | | // https://github.com/facebook/create-react-app/issues/1065 |
| | | watchOptions: { |
| | | ignored: ignoredFiles(paths.appSrc), |
| | | }, |
| | | https: getHttpsConfig(), |
| | | host, |
| | | overlay: false, |
| | | historyApiFallback: { |
| | | // Paths with dots should still use the history fallback. |
| | | // See https://github.com/facebook/create-react-app/issues/387. |
| | | disableDotRule: true, |
| | | index: paths.publicUrlOrPath, |
| | | }, |
| | | public: allowedHost, |
| | | // `proxy` is run between `before` and `after` `webpack-dev-server` hooks |
| | | proxy, |
| | | before(app, server) { |
| | | // Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware` |
| | | // middlewares before `redirectServedPath` otherwise will not have any effect |
| | | // This lets us fetch source contents from webpack for the error overlay |
| | | app.use(evalSourceMapMiddleware(server)); |
| | | // This lets us open files from the runtime error overlay. |
| | | app.use(errorOverlayMiddleware()); |
| | | |
| | | if (fs.existsSync(paths.proxySetup)) { |
| | | // This registers user provided middleware for proxy reasons |
| | | require(paths.proxySetup)(app); |
| | | } |
| | | }, |
| | | after(app) { |
| | | // Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match |
| | | app.use(redirectServedPath(paths.publicUrlOrPath)); |
| | | |
| | | // This service worker file is effectively a 'no-op' that will reset any |
| | | // previous service worker registered for the same host:port combination. |
| | | // We do this in development to avoid hitting the production cache if |
| | | // it used the same host and port. |
| | | // https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432 |
| | | app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath)); |
| | | }, |
| | | }; |
| | | }; |
| | |
| | | "requires": { |
| | | "esutils": "^2.0.2" |
| | | } |
| | | }, |
| | | "resolve": { |
| | | "version": "1.17.0", |
| | | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", |
| | | "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", |
| | | "dev": true, |
| | | "requires": { |
| | | "path-parse": "^1.0.6" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | |
| | | "minimist": "~1.2.5", |
| | | "readable-stream": "~1.0.27-1", |
| | | "through2": "~0.4.1" |
| | | } |
| | | }, |
| | | "html-webpack-inline-source-plugin": { |
| | | "version": "1.0.0-beta.2", |
| | | "resolved": "https://registry.npmjs.org/html-webpack-inline-source-plugin/-/html-webpack-inline-source-plugin-1.0.0-beta.2.tgz", |
| | | "integrity": "sha512-ydsEKdp0tnbmnqRAH2WSSMXerCNYhjes5b79uvP2BU3p6cyk+6ucNMsw5b5xD1QxphgvBBA3QqVmdcpu8QLlRQ==", |
| | | "dev": true, |
| | | "requires": { |
| | | "escape-string-regexp": "^1.0.5", |
| | | "slash": "^1.0.0", |
| | | "source-map-url": "^0.4.0" |
| | | }, |
| | | "dependencies": { |
| | | "slash": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", |
| | | "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", |
| | | "dev": true |
| | | } |
| | | } |
| | | }, |
| | | "html-webpack-plugin": { |
| | |
| | | "tiny-warning": "^1.0.0" |
| | | } |
| | | }, |
| | | "react-scripts": { |
| | | "version": "3.4.1", |
| | | "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.1.tgz", |
| | | "integrity": "sha512-JpTdi/0Sfd31mZA6Ukx+lq5j1JoKItX7qqEK4OiACjVQletM1P38g49d9/D0yTxp9FrSF+xpJFStkGgKEIRjlQ==", |
| | | "dev": true, |
| | | "requires": { |
| | | "@babel/core": "7.9.0", |
| | | "@svgr/webpack": "4.3.3", |
| | | "@typescript-eslint/eslint-plugin": "^2.10.0", |
| | | "@typescript-eslint/parser": "^2.10.0", |
| | | "babel-eslint": "10.1.0", |
| | | "babel-jest": "^24.9.0", |
| | | "babel-loader": "8.1.0", |
| | | "babel-plugin-named-asset-import": "^0.3.6", |
| | | "babel-preset-react-app": "^9.1.2", |
| | | "camelcase": "^5.3.1", |
| | | "case-sensitive-paths-webpack-plugin": "2.3.0", |
| | | "css-loader": "3.4.2", |
| | | "dotenv": "8.2.0", |
| | | "dotenv-expand": "5.1.0", |
| | | "eslint": "^6.6.0", |
| | | "eslint-config-react-app": "^5.2.1", |
| | | "eslint-loader": "3.0.3", |
| | | "eslint-plugin-flowtype": "4.6.0", |
| | | "eslint-plugin-import": "2.20.1", |
| | | "eslint-plugin-jsx-a11y": "6.2.3", |
| | | "eslint-plugin-react": "7.19.0", |
| | | "eslint-plugin-react-hooks": "^1.6.1", |
| | | "file-loader": "4.3.0", |
| | | "fs-extra": "^8.1.0", |
| | | "fsevents": "2.1.2", |
| | | "html-webpack-plugin": "4.0.0-beta.11", |
| | | "identity-obj-proxy": "3.0.0", |
| | | "jest": "24.9.0", |
| | | "jest-environment-jsdom-fourteen": "1.0.1", |
| | | "jest-resolve": "24.9.0", |
| | | "jest-watch-typeahead": "0.4.2", |
| | | "mini-css-extract-plugin": "0.9.0", |
| | | "optimize-css-assets-webpack-plugin": "5.0.3", |
| | | "pnp-webpack-plugin": "1.6.4", |
| | | "postcss-flexbugs-fixes": "4.1.0", |
| | | "postcss-loader": "3.0.0", |
| | | "postcss-normalize": "8.0.1", |
| | | "postcss-preset-env": "6.7.0", |
| | | "postcss-safe-parser": "4.0.1", |
| | | "react-app-polyfill": "^1.0.6", |
| | | "react-dev-utils": "^10.2.1", |
| | | "resolve": "1.15.0", |
| | | "resolve-url-loader": "3.1.1", |
| | | "sass-loader": "8.0.2", |
| | | "semver": "6.3.0", |
| | | "style-loader": "0.23.1", |
| | | "terser-webpack-plugin": "2.3.5", |
| | | "ts-pnp": "1.1.6", |
| | | "url-loader": "2.3.0", |
| | | "webpack": "4.42.0", |
| | | "webpack-dev-server": "3.10.3", |
| | | "webpack-manifest-plugin": "2.2.0", |
| | | "workbox-webpack-plugin": "4.3.1" |
| | | }, |
| | | "dependencies": { |
| | | "resolve": { |
| | | "version": "1.15.0", |
| | | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", |
| | | "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", |
| | | "dev": true, |
| | | "requires": { |
| | | "path-parse": "^1.0.6" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | "react-test-renderer": { |
| | | "version": "16.13.1", |
| | | "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.13.1.tgz", |
| | |
| | | "dev": true |
| | | }, |
| | | "resolve": { |
| | | "version": "1.17.0", |
| | | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", |
| | | "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", |
| | | "version": "1.15.0", |
| | | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", |
| | | "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", |
| | | "dev": true, |
| | | "requires": { |
| | | "path-parse": "^1.0.6" |
| | |
| | | "private": true, |
| | | "homepage": "/frontend", |
| | | "dependencies": { |
| | | "dotenv": "^8.2.0", |
| | | "dotenv": "8.2.0", |
| | | "express": "^4.17.1" |
| | | }, |
| | | "devDependencies": { |
| | | "@babel/core": "7.9.0", |
| | | "@patternfly/react-core": "^3.158.1", |
| | | "@patternfly/react-table": "^2.28.47", |
| | | "@svgr/webpack": "4.3.3", |
| | | "@testing-library/jest-dom": "^4.2.4", |
| | | "@testing-library/react": "^9.3.2", |
| | | "@testing-library/user-event": "^7.1.2", |
| | |
| | | "@types/react": "^16.9.0", |
| | | "@types/react-dom": "^16.9.0", |
| | | "@types/react-router-dom": "^5.1.5", |
| | | "@typescript-eslint/eslint-plugin": "^2.10.0", |
| | | "@typescript-eslint/parser": "^2.10.0", |
| | | "axios": "^0.19.2", |
| | | "babel-eslint": "10.1.0", |
| | | "babel-jest": "^24.9.0", |
| | | "babel-loader": "8.1.0", |
| | | "babel-plugin-named-asset-import": "^0.3.6", |
| | | "babel-preset-react-app": "^9.1.2", |
| | | "camelcase": "^5.3.1", |
| | | "case-sensitive-paths-webpack-plugin": "2.3.0", |
| | | "css-loader": "3.4.2", |
| | | "dockerfile-generator": "^4.0.3", |
| | | "dotenv-expand": "5.1.0", |
| | | "enzyme": "^3.11.0", |
| | | "enzyme-adapter-react-16": "^1.15.2", |
| | | "eslint": "^6.6.0", |
| | | "eslint-config-react-app": "^5.2.1", |
| | | "eslint-loader": "3.0.3", |
| | | "eslint-plugin-flowtype": "4.6.0", |
| | | "eslint-plugin-import": "2.20.1", |
| | | "eslint-plugin-jsx-a11y": "6.2.3", |
| | | "eslint-plugin-react": "7.19.0", |
| | | "eslint-plugin-react-hooks": "^1.6.1", |
| | | "file-loader": "4.3.0", |
| | | "fs-extra": "^8.1.0", |
| | | "html-webpack-inline-source-plugin": "1.0.0-beta.2", |
| | | "html-webpack-plugin": "4.0.0-beta.11", |
| | | "identity-obj-proxy": "3.0.0", |
| | | "install": "^0.13.0", |
| | | "jest": "24.9.0", |
| | | "jest-environment-jsdom-fourteen": "1.0.1", |
| | | "jest-resolve": "24.9.0", |
| | | "jest-watch-typeahead": "0.4.2", |
| | | "mini-css-extract-plugin": "0.9.0", |
| | | "optimize-css-assets-webpack-plugin": "5.0.3", |
| | | "pnp-webpack-plugin": "1.6.4", |
| | | "postcss-flexbugs-fixes": "4.1.0", |
| | | "postcss-loader": "3.0.0", |
| | | "postcss-normalize": "8.0.1", |
| | | "postcss-preset-env": "6.7.0", |
| | | "postcss-safe-parser": "4.0.1", |
| | | "react": "^16.13.1", |
| | | "react-app-polyfill": "^1.0.6", |
| | | "react-core": "0.0.0", |
| | | "react-dev-utils": "^10.2.1", |
| | | "react-dom": "^16.13.1", |
| | | "react-router-dom": "^5.1.2", |
| | | "react-scripts": "3.4.1", |
| | | "react-test-renderer": "^16.13.1", |
| | | "typescript": "^3.7.5" |
| | | "resolve": "1.15.0", |
| | | "resolve-url-loader": "3.1.1", |
| | | "sass-loader": "8.0.2", |
| | | "semver": "6.3.0", |
| | | "style-loader": "0.23.1", |
| | | "terser-webpack-plugin": "2.3.5", |
| | | "ts-pnp": "1.1.6", |
| | | "typescript": "^3.7.5", |
| | | "url-loader": "2.3.0", |
| | | "webpack": "4.42.0", |
| | | "webpack-dev-server": "3.10.3", |
| | | "webpack-manifest-plugin": "2.2.0", |
| | | "workbox-webpack-plugin": "4.3.1" |
| | | }, |
| | | "scripts": { |
| | | "start": "react-scripts start", |
| | | "start": "node scripts/start.js", |
| | | "start:prod": "node server.js", |
| | | "build": "react-scripts build", |
| | | "build": "node scripts/build.js", |
| | | "build:container": "npm run build && docker build -t quay.io/redhattraining/ossm-adopt-a-pup-webapp .", |
| | | "test": "react-scripts test", |
| | | "eject": "react-scripts eject", |
| | | "test": "node scripts/test.js", |
| | | "lint": "eslint --ext ts,tsx src", |
| | | "lint:fix": "eslint --ext ts,tsx src --fix" |
| | | }, |
| | |
| | | "last 1 firefox version", |
| | | "last 1 safari version" |
| | | ] |
| | | }, |
| | | "jest": { |
| | | "roots": [ |
| | | "<rootDir>/src" |
| | | ], |
| | | "collectCoverageFrom": [ |
| | | "src/**/*.{js,jsx,ts,tsx}", |
| | | "!src/**/*.d.ts" |
| | | ], |
| | | "setupFiles": [ |
| | | "react-app-polyfill/jsdom" |
| | | ], |
| | | "setupFilesAfterEnv": [ |
| | | "<rootDir>/src/setupTests.ts" |
| | | ], |
| | | "testMatch": [ |
| | | "<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}", |
| | | "<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}" |
| | | ], |
| | | "testEnvironment": "jest-environment-jsdom-fourteen", |
| | | "transform": { |
| | | "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest", |
| | | "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js", |
| | | "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js" |
| | | }, |
| | | "transformIgnorePatterns": [ |
| | | "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$", |
| | | "^.+\\.module\\.(css|sass|scss)$" |
| | | ], |
| | | "modulePaths": [], |
| | | "moduleNameMapper": { |
| | | "^react-native$": "react-native-web", |
| | | "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy" |
| | | }, |
| | | "moduleFileExtensions": [ |
| | | "web.js", |
| | | "js", |
| | | "web.ts", |
| | | "ts", |
| | | "web.tsx", |
| | | "tsx", |
| | | "json", |
| | | "web.jsx", |
| | | "jsx", |
| | | "node" |
| | | ], |
| | | "watchPlugins": [ |
| | | "jest-watch-typeahead/filename", |
| | | "jest-watch-typeahead/testname" |
| | | ] |
| | | }, |
| | | "babel": { |
| | | "presets": [ |
| | | "react-app" |
| | | ] |
| | | } |
| | | } |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | // Do this as the first thing so that any code reading it knows the right env. |
| | | process.env.BABEL_ENV = 'production'; |
| | | process.env.NODE_ENV = 'production'; |
| | | |
| | | // Makes the script crash on unhandled rejections instead of silently |
| | | // ignoring them. In the future, promise rejections that are not handled will |
| | | // terminate the Node.js process with a non-zero exit code. |
| | | process.on('unhandledRejection', err => { |
| | | throw err; |
| | | }); |
| | | |
| | | // Ensure environment variables are read. |
| | | require('../config/env'); |
| | | |
| | | |
| | | const path = require('path'); |
| | | const chalk = require('react-dev-utils/chalk'); |
| | | const fs = require('fs-extra'); |
| | | const webpack = require('webpack'); |
| | | const configFactory = require('../config/webpack.config'); |
| | | const paths = require('../config/paths'); |
| | | const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); |
| | | const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); |
| | | const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); |
| | | const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); |
| | | const printBuildError = require('react-dev-utils/printBuildError'); |
| | | |
| | | const measureFileSizesBeforeBuild = |
| | | FileSizeReporter.measureFileSizesBeforeBuild; |
| | | const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; |
| | | const useYarn = fs.existsSync(paths.yarnLockFile); |
| | | |
| | | // These sizes are pretty large. We'll warn for bundles exceeding them. |
| | | const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; |
| | | const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; |
| | | |
| | | const isInteractive = process.stdout.isTTY; |
| | | |
| | | // Warn and crash if required files are missing |
| | | if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { |
| | | process.exit(1); |
| | | } |
| | | |
| | | // Generate configuration |
| | | const config = configFactory('production'); |
| | | |
| | | // We require that you explicitly set browsers and do not fall back to |
| | | // browserslist defaults. |
| | | const { checkBrowsers } = require('react-dev-utils/browsersHelper'); |
| | | checkBrowsers(paths.appPath, isInteractive) |
| | | .then(() => { |
| | | // First, read the current file sizes in build directory. |
| | | // This lets us display how much they changed later. |
| | | return measureFileSizesBeforeBuild(paths.appBuild); |
| | | }) |
| | | .then(previousFileSizes => { |
| | | // Remove all content but keep the directory so that |
| | | // if you're in it, you don't end up in Trash |
| | | fs.emptyDirSync(paths.appBuild); |
| | | // Merge with the public folder |
| | | copyPublicFolder(); |
| | | // Start the webpack build |
| | | return build(previousFileSizes); |
| | | }) |
| | | .then( |
| | | ({ stats, previousFileSizes, warnings }) => { |
| | | if (warnings.length) { |
| | | console.log(chalk.yellow('Compiled with warnings.\n')); |
| | | console.log(warnings.join('\n\n')); |
| | | console.log( |
| | | '\nSearch for the ' + |
| | | chalk.underline(chalk.yellow('keywords')) + |
| | | ' to learn more about each warning.' |
| | | ); |
| | | console.log( |
| | | 'To ignore, add ' + |
| | | chalk.cyan('// eslint-disable-next-line') + |
| | | ' to the line before.\n' |
| | | ); |
| | | } else { |
| | | console.log(chalk.green('Compiled successfully.\n')); |
| | | } |
| | | |
| | | console.log('File sizes after gzip:\n'); |
| | | printFileSizesAfterBuild( |
| | | stats, |
| | | previousFileSizes, |
| | | paths.appBuild, |
| | | WARN_AFTER_BUNDLE_GZIP_SIZE, |
| | | WARN_AFTER_CHUNK_GZIP_SIZE |
| | | ); |
| | | console.log(); |
| | | |
| | | const appPackage = require(paths.appPackageJson); |
| | | const publicUrl = paths.publicUrlOrPath; |
| | | const publicPath = config.output.publicPath; |
| | | const buildFolder = path.relative(process.cwd(), paths.appBuild); |
| | | printHostingInstructions( |
| | | appPackage, |
| | | publicUrl, |
| | | publicPath, |
| | | buildFolder, |
| | | useYarn |
| | | ); |
| | | }, |
| | | err => { |
| | | const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true'; |
| | | if (tscCompileOnError) { |
| | | console.log( |
| | | chalk.yellow( |
| | | 'Compiled with the following type errors (you may want to check these before deploying your app):\n' |
| | | ) |
| | | ); |
| | | printBuildError(err); |
| | | } else { |
| | | console.log(chalk.red('Failed to compile.\n')); |
| | | printBuildError(err); |
| | | process.exit(1); |
| | | } |
| | | } |
| | | ) |
| | | .catch(err => { |
| | | if (err && err.message) { |
| | | console.log(err.message); |
| | | } |
| | | process.exit(1); |
| | | }); |
| | | |
| | | // Create the production build and print the deployment instructions. |
| | | function build(previousFileSizes) { |
| | | // We used to support resolving modules according to `NODE_PATH`. |
| | | // This now has been deprecated in favor of jsconfig/tsconfig.json |
| | | // This lets you use absolute paths in imports inside large monorepos: |
| | | if (process.env.NODE_PATH) { |
| | | console.log( |
| | | chalk.yellow( |
| | | 'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.' |
| | | ) |
| | | ); |
| | | console.log(); |
| | | } |
| | | |
| | | console.log('Creating an optimized production build...'); |
| | | |
| | | const compiler = webpack(config); |
| | | return new Promise((resolve, reject) => { |
| | | compiler.run((err, stats) => { |
| | | let messages; |
| | | if (err) { |
| | | if (!err.message) { |
| | | return reject(err); |
| | | } |
| | | |
| | | let errMessage = err.message; |
| | | |
| | | // Add additional information for postcss errors |
| | | if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) { |
| | | errMessage += |
| | | '\nCompileError: Begins at CSS selector ' + |
| | | err['postcssNode'].selector; |
| | | } |
| | | |
| | | messages = formatWebpackMessages({ |
| | | errors: [errMessage], |
| | | warnings: [], |
| | | }); |
| | | } else { |
| | | messages = formatWebpackMessages( |
| | | stats.toJson({ all: false, warnings: true, errors: true }) |
| | | ); |
| | | } |
| | | if (messages.errors.length) { |
| | | // Only keep the first error. Others are often indicative |
| | | // of the same problem, but confuse the reader with noise. |
| | | if (messages.errors.length > 1) { |
| | | messages.errors.length = 1; |
| | | } |
| | | return reject(new Error(messages.errors.join('\n\n'))); |
| | | } |
| | | if ( |
| | | process.env.CI && |
| | | (typeof process.env.CI !== 'string' || |
| | | process.env.CI.toLowerCase() !== 'false') && |
| | | messages.warnings.length |
| | | ) { |
| | | console.log( |
| | | chalk.yellow( |
| | | '\nTreating warnings as errors because process.env.CI = true.\n' + |
| | | 'Most CI servers set it automatically.\n' |
| | | ) |
| | | ); |
| | | return reject(new Error(messages.warnings.join('\n\n'))); |
| | | } |
| | | |
| | | return resolve({ |
| | | stats, |
| | | previousFileSizes, |
| | | warnings: messages.warnings, |
| | | }); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | function copyPublicFolder() { |
| | | fs.copySync(paths.appPublic, paths.appBuild, { |
| | | dereference: true, |
| | | filter: file => file !== paths.appHtml, |
| | | }); |
| | | } |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | // Do this as the first thing so that any code reading it knows the right env. |
| | | process.env.BABEL_ENV = 'development'; |
| | | process.env.NODE_ENV = 'development'; |
| | | |
| | | // Makes the script crash on unhandled rejections instead of silently |
| | | // ignoring them. In the future, promise rejections that are not handled will |
| | | // terminate the Node.js process with a non-zero exit code. |
| | | process.on('unhandledRejection', err => { |
| | | throw err; |
| | | }); |
| | | |
| | | // Ensure environment variables are read. |
| | | require('../config/env'); |
| | | |
| | | |
| | | const fs = require('fs'); |
| | | const chalk = require('react-dev-utils/chalk'); |
| | | const webpack = require('webpack'); |
| | | const WebpackDevServer = require('webpack-dev-server'); |
| | | const clearConsole = require('react-dev-utils/clearConsole'); |
| | | const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); |
| | | const { |
| | | choosePort, |
| | | createCompiler, |
| | | prepareProxy, |
| | | prepareUrls, |
| | | } = require('react-dev-utils/WebpackDevServerUtils'); |
| | | const openBrowser = require('react-dev-utils/openBrowser'); |
| | | const paths = require('../config/paths'); |
| | | const configFactory = require('../config/webpack.config'); |
| | | const createDevServerConfig = require('../config/webpackDevServer.config'); |
| | | |
| | | const useYarn = fs.existsSync(paths.yarnLockFile); |
| | | const isInteractive = process.stdout.isTTY; |
| | | |
| | | // Warn and crash if required files are missing |
| | | if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { |
| | | process.exit(1); |
| | | } |
| | | |
| | | // Tools like Cloud9 rely on this. |
| | | const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; |
| | | const HOST = process.env.HOST || '0.0.0.0'; |
| | | |
| | | if (process.env.HOST) { |
| | | console.log( |
| | | chalk.cyan( |
| | | `Attempting to bind to HOST environment variable: ${chalk.yellow( |
| | | chalk.bold(process.env.HOST) |
| | | )}` |
| | | ) |
| | | ); |
| | | console.log( |
| | | `If this was unintentional, check that you haven't mistakenly set it in your shell.` |
| | | ); |
| | | console.log( |
| | | `Learn more here: ${chalk.yellow('https://bit.ly/CRA-advanced-config')}` |
| | | ); |
| | | console.log(); |
| | | } |
| | | |
| | | // We require that you explicitly set browsers and do not fall back to |
| | | // browserslist defaults. |
| | | const { checkBrowsers } = require('react-dev-utils/browsersHelper'); |
| | | checkBrowsers(paths.appPath, isInteractive) |
| | | .then(() => { |
| | | // We attempt to use the default port but if it is busy, we offer the user to |
| | | // run on a different port. `choosePort()` Promise resolves to the next free port. |
| | | return choosePort(HOST, DEFAULT_PORT); |
| | | }) |
| | | .then(port => { |
| | | if (port == null) { |
| | | // We have not found a port. |
| | | return; |
| | | } |
| | | |
| | | const config = configFactory('development'); |
| | | const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; |
| | | const appName = require(paths.appPackageJson).name; |
| | | const useTypeScript = fs.existsSync(paths.appTsConfig); |
| | | const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true'; |
| | | const urls = prepareUrls( |
| | | protocol, |
| | | HOST, |
| | | port, |
| | | paths.publicUrlOrPath.slice(0, -1) |
| | | ); |
| | | const devSocket = { |
| | | warnings: warnings => |
| | | devServer.sockWrite(devServer.sockets, 'warnings', warnings), |
| | | errors: errors => |
| | | devServer.sockWrite(devServer.sockets, 'errors', errors), |
| | | }; |
| | | // Create a webpack compiler that is configured with custom messages. |
| | | const compiler = createCompiler({ |
| | | appName, |
| | | config, |
| | | devSocket, |
| | | urls, |
| | | useYarn, |
| | | useTypeScript, |
| | | tscCompileOnError, |
| | | webpack, |
| | | }); |
| | | // Load proxy config |
| | | const proxySetting = require(paths.appPackageJson).proxy; |
| | | const proxyConfig = prepareProxy( |
| | | proxySetting, |
| | | paths.appPublic, |
| | | paths.publicUrlOrPath |
| | | ); |
| | | // Serve webpack assets generated by the compiler over a web server. |
| | | const serverConfig = createDevServerConfig( |
| | | proxyConfig, |
| | | urls.lanUrlForConfig |
| | | ); |
| | | const devServer = new WebpackDevServer(compiler, serverConfig); |
| | | // Launch WebpackDevServer. |
| | | devServer.listen(port, HOST, err => { |
| | | if (err) { |
| | | return console.log(err); |
| | | } |
| | | if (isInteractive) { |
| | | clearConsole(); |
| | | } |
| | | |
| | | // We used to support resolving modules according to `NODE_PATH`. |
| | | // This now has been deprecated in favor of jsconfig/tsconfig.json |
| | | // This lets you use absolute paths in imports inside large monorepos: |
| | | if (process.env.NODE_PATH) { |
| | | console.log( |
| | | chalk.yellow( |
| | | 'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.' |
| | | ) |
| | | ); |
| | | console.log(); |
| | | } |
| | | |
| | | console.log(chalk.cyan('Starting the development server...\n')); |
| | | openBrowser(urls.localUrlForBrowser); |
| | | }); |
| | | |
| | | ['SIGINT', 'SIGTERM'].forEach(function(sig) { |
| | | process.on(sig, function() { |
| | | devServer.close(); |
| | | process.exit(); |
| | | }); |
| | | }); |
| | | |
| | | if (isInteractive || process.env.CI !== 'true') { |
| | | // Gracefully exit when stdin ends |
| | | process.stdin.on('end', function() { |
| | | devServer.close(); |
| | | process.exit(); |
| | | }); |
| | | process.stdin.resume(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | if (err && err.message) { |
| | | console.log(err.message); |
| | | } |
| | | process.exit(1); |
| | | }); |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | // Do this as the first thing so that any code reading it knows the right env. |
| | | process.env.BABEL_ENV = 'test'; |
| | | process.env.NODE_ENV = 'test'; |
| | | process.env.PUBLIC_URL = ''; |
| | | |
| | | // Makes the script crash on unhandled rejections instead of silently |
| | | // ignoring them. In the future, promise rejections that are not handled will |
| | | // terminate the Node.js process with a non-zero exit code. |
| | | process.on('unhandledRejection', err => { |
| | | throw err; |
| | | }); |
| | | |
| | | // Ensure environment variables are read. |
| | | require('../config/env'); |
| | | |
| | | |
| | | const jest = require('jest'); |
| | | const execSync = require('child_process').execSync; |
| | | let argv = process.argv.slice(2); |
| | | |
| | | function isInGitRepository() { |
| | | try { |
| | | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); |
| | | return true; |
| | | } catch (e) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | function isInMercurialRepository() { |
| | | try { |
| | | execSync('hg --cwd . root', { stdio: 'ignore' }); |
| | | return true; |
| | | } catch (e) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // Watch unless on CI or explicitly running all tests |
| | | if ( |
| | | !process.env.CI && |
| | | argv.indexOf('--watchAll') === -1 && |
| | | argv.indexOf('--watchAll=false') === -1 |
| | | ) { |
| | | // https://github.com/facebook/create-react-app/issues/5210 |
| | | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); |
| | | argv.push(hasSourceControl ? '--watch' : '--watchAll'); |
| | | } |
| | | |
| | | |
| | | jest.run(argv); |
| | |
| | | /// <reference types="react-scripts" /> |
| | | /// <reference types="node" /> |
| | | /// <reference types="react" /> |
| | | /// <reference types="react-dom" /> |
| | | |
| | | declare namespace NodeJS { |
| | | interface ProcessEnv { |
| | | readonly NODE_ENV: "development" | "production" | "test"; |
| | | readonly PUBLIC_URL: string; |
| | | } |
| | | } |
| | | |
| | | declare module "*.bmp" { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.gif" { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.jpg" { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.jpeg" { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.png" { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.webp" { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.svg" { |
| | | import * as React from "react"; |
| | | |
| | | export const ReactComponent: React.FunctionComponent<React.SVGProps< |
| | | SVGSVGElement |
| | | > & { title?: string }>; |
| | | |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module "*.module.css" { |
| | | const classes: { readonly [key: string]: string }; |
| | | export default classes; |
| | | } |
| | | |
| | | declare module "*.module.scss" { |
| | | const classes: { readonly [key: string]: string }; |
| | | export default classes; |
| | | } |
| | | |
| | | declare module "*.module.sass" { |
| | | const classes: { readonly [key: string]: string }; |
| | | export default classes; |
| | | } |