backpack-react-scripts
Advanced tools
Comparing version
# `backpack-react-scripts` Change Log | ||
## 8.0.0 | ||
### Breaking | ||
- Rebased onto `upstream/master` v3. | ||
- This release rebases `backpack-react-scripts` on top of `create-react-app` v3! The major changes have been summarised in the following blog post: | ||
[Create React App 3.0](https://github.com/facebook/create-react-app/blob/master/CHANGELOG.md#300-april-22-2019) | ||
- **Some of these changes are breaking. Please follow [this guide](./migrating-from-v7-to-v8.md) when upgrading.** | ||
## 7.0.5 - 2020-01-10 | ||
@@ -4,0 +13,0 @@ |
@@ -57,3 +57,3 @@ // @remove-on-eject-begin | ||
// 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. | ||
// 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 | ||
@@ -69,3 +69,3 @@ // We also resolve them to make sure all tools using them work consistently. | ||
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be | ||
// injected into the application via DefinePlugin in Webpack configuration. | ||
// injected into the application via DefinePlugin in webpack configuration. | ||
const REACT_APP = /^REACT_APP_/i; | ||
@@ -90,5 +90,13 @@ | ||
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 | ||
// Stringify all values so we can feed into webpack DefinePlugin | ||
const stringified = { | ||
@@ -95,0 +103,0 @@ 'process.env': Object.keys(raw).reduce((env, key) => { |
@@ -13,3 +13,3 @@ // @remove-on-eject-begin | ||
const fs = require('fs'); | ||
const url = require('url'); | ||
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath'); | ||
@@ -21,30 +21,13 @@ // Make sure any symlinks in the project folder are resolved: | ||
const envPublicUrl = process.env.PUBLIC_URL; | ||
function ensureSlash(inputPath, needsSlash) { | ||
const hasSlash = inputPath.endsWith('/'); | ||
if (hasSlash && !needsSlash) { | ||
return inputPath.substr(0, inputPath.length - 1); | ||
} else if (!hasSlash && needsSlash) { | ||
return `${inputPath}/`; | ||
} else { | ||
return inputPath; | ||
} | ||
} | ||
const getPublicUrl = appPackageJson => | ||
envPublicUrl || require(appPackageJson).homepage; | ||
// 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 | ||
// 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. | ||
function getServedPath(appPackageJson) { | ||
const publicUrl = getPublicUrl(appPackageJson); | ||
const servedUrl = | ||
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/'); | ||
return ensureSlash(servedUrl, true); | ||
} | ||
const publicUrlOrPath = getPublicUrlOrPath( | ||
process.env.NODE_ENV === 'development', | ||
require(resolveApp('package.json')).homepage, | ||
process.env.PUBLIC_URL | ||
); | ||
@@ -94,4 +77,3 @@ const moduleFileExtensions = [ | ||
appNodeModules: resolveApp('node_modules'), | ||
publicUrl: getPublicUrl(resolveApp('package.json')), | ||
servedPath: getServedPath(resolveApp('package.json')), | ||
publicUrlOrPath, | ||
appSsrJs: resolveApp('src/ssr.js'), | ||
@@ -119,5 +101,4 @@ }; | ||
appNodeModules: resolveApp('node_modules'), | ||
publicUrl: getPublicUrl(resolveApp('package.json')), | ||
servedPath: getServedPath(resolveApp('package.json')), | ||
appSsrJs: resolveOwn('src/ssr.js'), | ||
publicUrlOrPath, | ||
appSsrJs: resolveApp('src/ssr.js'), | ||
// These properties only exist before ejecting: | ||
@@ -157,4 +138,3 @@ ownPath: resolveOwn('.'), | ||
appNodeModules: resolveOwn('node_modules'), | ||
publicUrl: getPublicUrl(resolveOwn('package.json')), | ||
servedPath: getServedPath(resolveOwn('package.json')), | ||
publicUrlOrPath, | ||
appSsrJs: resolveOwn(`${templatePath}/src/ssr.js`), | ||
@@ -161,0 +141,0 @@ // These properties only exist before ejecting: |
@@ -24,2 +24,3 @@ // @remove-on-eject-begin | ||
const ManifestPlugin = require('webpack-manifest-plugin'); | ||
const SubresourceIntegrityPlugin = require('webpack-subresource-integrity'); | ||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); | ||
@@ -37,6 +38,6 @@ const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); | ||
// @remove-on-eject-begin | ||
// const eslint = require('eslint'); | ||
const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); | ||
// @remove-on-eject-end | ||
const postcssNormalize = require('postcss-normalize'); | ||
const appPackageJson = require(paths.appPackageJson); | ||
@@ -61,2 +62,4 @@ | ||
// const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true'; | ||
const imageInlineSizeLimit = parseInt( | ||
@@ -90,20 +93,7 @@ process.env.IMAGE_INLINE_SIZE_LIMIT || '10000' | ||
// 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. | ||
// In development, we always serve from the root. This makes config easier. | ||
const publicPath = isEnvProduction | ||
? paths.servedPath | ||
: isEnvDevelopment && '/'; | ||
// Some apps do not use client-side routing with pushState. | ||
// For these, "homepage" can be set to "." to enable relative asset paths. | ||
const shouldUseRelativeAssetPaths = publicPath === './'; | ||
// `publicUrl` is just like `publicPath`, but we will provide it to our app | ||
// 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. | ||
const publicUrl = isEnvProduction | ||
? publicPath.slice(0, -1) | ||
: isEnvDevelopment && ''; | ||
// Get environment variables to inject into our app. | ||
const env = getClientEnvironment(publicUrl); | ||
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1)); | ||
@@ -120,3 +110,7 @@ // common function to get style loaders | ||
loader: MiniCssExtractPlugin.loader, | ||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {}, | ||
// 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: '../../' } | ||
: {}, | ||
}, | ||
@@ -166,3 +160,3 @@ { | ||
...{ | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
sourceMap: true, | ||
}, | ||
@@ -207,6 +201,2 @@ }, | ||
output: { | ||
// Prevents conflicts when multiple Webpack runtimes (from different apps) | ||
// are used on the same page. | ||
//jsonpFunction: `webpackJsonp${appPackageJson.name}`, | ||
jsonpFunction: camelCase(appPackageJson.name + 'JsonpCallback'), | ||
crossOriginLoading, | ||
@@ -228,5 +218,6 @@ // The build folder. | ||
: 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. | ||
// We use "/" in development. | ||
publicPath: publicPath, | ||
publicPath: paths.publicUrlOrPath, | ||
// Point sourcemap entries to original disk location (format as URL on Windows) | ||
@@ -240,2 +231,6 @@ devtoolModuleFilenameTemplate: isEnvProduction | ||
(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}`, | ||
jsonpFunction: camelCase(appPackageJson.name + 'JsonpCallback'), | ||
// this defaults to 'window', but by setting it to 'this' then | ||
@@ -287,7 +282,2 @@ // module chunks which are built will work in web workers as well. | ||
}, | ||
// Use multi-process parallel running to improve the build speed | ||
// Default number of concurrent runs: os.cpus().length - 1 | ||
parallel: true, | ||
// Enable file caching | ||
cache: true, | ||
sourceMap: shouldUseSourceMap, | ||
@@ -310,2 +300,5 @@ }), | ||
}, | ||
cssProcessorPluginOptions: { | ||
preset: ['default', { minifyFontValues: { removeQuotes: false } }], | ||
}, | ||
}), | ||
@@ -339,7 +332,11 @@ ], | ||
// }, | ||
runtimeChunk: bpkReactScriptsConfig.enableAutomaticChunking, | ||
runtimeChunk: bpkReactScriptsConfig.enableAutomaticChunking | ||
? { | ||
name: entrypoint => `runtime-${entrypoint.name}`, | ||
} | ||
: false, | ||
}, | ||
externals: isEnvProduction ? bpkReactScriptsConfig.externals || {} : {}, | ||
resolve: { | ||
// This allows you to set a fallback for where Webpack should look for modules. | ||
// 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" | ||
@@ -385,3 +382,3 @@ // if there are any conflicts. This matches Node resolution mechanism. | ||
plugins: [ | ||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders | ||
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders | ||
// from the current package. | ||
@@ -410,24 +407,9 @@ PnpWebpackPlugin.moduleLoader(module), | ||
// // @remove-on-eject-begin | ||
// ignore: process.env.EXTEND_ESLINT === 'true', | ||
// baseConfig: (() => { | ||
// // We allow overriding the config only if the env variable is set | ||
// if (process.env.EXTEND_ESLINT === 'true') { | ||
// const eslintCli = new eslint.CLIEngine(); | ||
// let eslintConfig; | ||
// try { | ||
// eslintConfig = eslintCli.getConfigForFile( | ||
// paths.appIndexJs | ||
// ); | ||
// } catch (e) { | ||
// console.error(e); | ||
// process.exit(1); | ||
// } | ||
// return eslintConfig; | ||
// } else { | ||
// return { | ||
// ignore: isExtendingEslintConfig, | ||
// baseConfig: isExtendingEslintConfig | ||
// ? undefined | ||
// : { | ||
// extends: [require.resolve('eslint-config-react-app')], | ||
// }; | ||
// } | ||
// })(), | ||
// useEslintrc: false, | ||
// }, | ||
// useEslintrc: isExtendingEslintConfig, | ||
// // @remove-on-eject-end | ||
@@ -617,3 +599,3 @@ // }, | ||
{ | ||
importLoaders: 2, | ||
importLoaders: 3, | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
@@ -623,3 +605,3 @@ }, | ||
{ | ||
functions: sassFunctions, | ||
sassOptions: sassFunctions, | ||
} | ||
@@ -647,3 +629,3 @@ ), | ||
{ | ||
importLoaders: 2, | ||
importLoaders: 3, | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
@@ -656,3 +638,3 @@ modules: { | ||
{ | ||
functions: sassFunctions, | ||
sassOptions: sassFunctions, | ||
} | ||
@@ -739,5 +721,4 @@ ), | ||
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico"> | ||
// In production, it will be an empty string unless you specify "homepage" | ||
// It will be an empty string unless you specify "homepage" | ||
// in `package.json`, in which case it will be the pathname of that URL. | ||
// In development, this will be an empty string. | ||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), | ||
@@ -760,3 +741,3 @@ // This gives some necessary context to module not found errors, such as | ||
// 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 | ||
// to restart the development server for webpack to discover it. This plugin | ||
// makes the discovery automatic so you don't have to restart. | ||
@@ -781,3 +762,3 @@ // See https://github.com/facebook/create-react-app/issues/186 | ||
fileName: 'asset-manifest.json', | ||
publicPath: publicPath, | ||
publicPath: paths.publicUrlOrPath, | ||
generate: (seed, files, entrypoints) => { | ||
@@ -798,4 +779,12 @@ const manifestFiles = files.reduce((manifest, file) => { | ||
}), | ||
// Calculate and inject Subresource Integrity (SRI) hashes | ||
// https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity | ||
// This is a security feature that enables browsers to verify that resources | ||
// they fetch (for example, from a CDN) are delivered without unexpected manipulation. | ||
new SubresourceIntegrityPlugin({ | ||
enabled: true, | ||
hashFuncNames: ['sha384'], | ||
}), | ||
// 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 | ||
// by default due to how webpack interprets its code. This is a practical | ||
// solution that requires the user to opt into importing specific locales. | ||
@@ -806,3 +795,3 @@ // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack | ||
// Generate a service worker script that will precache, and keep up to date, | ||
// the HTML & assets that are part of the Webpack build. | ||
// the HTML & assets that are part of the webpack build. | ||
isEnvProduction && | ||
@@ -813,3 +802,3 @@ new WorkboxWebpackPlugin.GenerateSW({ | ||
importWorkboxFrom: 'cdn', | ||
navigateFallback: publicUrl + '/index.html', | ||
navigateFallback: paths.publicUrlOrPath + 'index.html', | ||
navigateFallbackBlacklist: [ | ||
@@ -854,3 +843,3 @@ // Exclude URLs starting with /_, as they're likely an API call | ||
// 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. | ||
// Tell webpack to provide empty mocks for them so importing them works. | ||
node: { | ||
@@ -857,0 +846,0 @@ module: 'empty', |
@@ -30,5 +30,6 @@ // @remove-on-eject-begin | ||
const paths = require('./paths'); | ||
const modules = require('./modules'); | ||
const getClientEnvironment = require('./env'); | ||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); | ||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt'); | ||
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); | ||
const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); | ||
@@ -38,9 +39,9 @@ // @remove-on-eject-begin | ||
// @remove-on-eject-end | ||
const postcssNormalize = require('postcss-normalize'); | ||
const appPackageJson = require(paths.appPackageJson); | ||
const sassFunctions = require('bpk-mixins/sass-functions'); | ||
// const camelCase = require('lodash/camelCase'); | ||
const pkgJson = require(paths.appPackageJson); | ||
const bpkReactScriptsConfig = pkgJson['backpack-react-scripts'] || {}; | ||
const bpkReactScriptsConfig = appPackageJson['backpack-react-scripts'] || {}; | ||
const customModuleRegexes = bpkReactScriptsConfig.babelIncludePrefixes | ||
@@ -51,3 +52,2 @@ ? bpkReactScriptsConfig.babelIncludePrefixes.map( | ||
: []; | ||
const cssModulesEnabled = bpkReactScriptsConfig.cssModules !== false; | ||
@@ -61,2 +61,8 @@ | ||
// const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true'; | ||
const imageInlineSizeLimit = parseInt( | ||
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000' | ||
); | ||
// Check if TypeScript is setup | ||
@@ -81,20 +87,12 @@ const useTypeScript = fs.existsSync(paths.appTsConfig); | ||
// 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. | ||
// In development, we always serve from the root. This makes config easier. | ||
const publicPath = isEnvProduction | ||
? paths.servedPath | ||
: isEnvDevelopment && '/'; | ||
// Some apps do not use client-side routing with pushState. | ||
// For these, "homepage" can be set to "." to enable relative asset paths. | ||
const shouldUseRelativeAssetPaths = publicPath === './'; | ||
// 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'); | ||
// `publicUrl` is just like `publicPath`, but we will provide it to our app | ||
// 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. | ||
const publicUrl = isEnvProduction | ||
? publicPath.slice(0, -1) | ||
: isEnvDevelopment && ''; | ||
// Get environment variables to inject into our app. | ||
const env = getClientEnvironment(publicUrl); | ||
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1)); | ||
@@ -111,6 +109,7 @@ // common function to get style loaders | ||
loader: MiniCssExtractPlugin.loader, | ||
options: Object.assign( | ||
{}, | ||
shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined | ||
), | ||
// 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: '../../' } | ||
: {}, | ||
}, | ||
@@ -138,2 +137,6 @@ { | ||
}), | ||
// 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(), | ||
], | ||
@@ -145,11 +148,19 @@ sourceMap: isEnvProduction && shouldUseSourceMap, | ||
if (preProcessor) { | ||
loaders.push({ | ||
loader: require.resolve(preProcessor), | ||
options: { | ||
...preProcessorOptions, | ||
...{ | ||
loaders.push( | ||
{ | ||
loader: require.resolve('resolve-url-loader'), | ||
options: { | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
}, | ||
}, | ||
}); | ||
{ | ||
loader: require.resolve(preProcessor), | ||
options: { | ||
...preProcessorOptions, | ||
...{ | ||
sourceMap: true, | ||
}, | ||
}, | ||
} | ||
); | ||
} | ||
@@ -199,4 +210,6 @@ return loaders; | ||
// filename: isEnvProduction | ||
// ? 'static/js/[name].[chunkhash:8].js' | ||
// ? 'static/js/[name].[contenthash:8].js' | ||
// : isEnvDevelopment && 'static/js/bundle.js', | ||
// TODO: remove this when upgrading to webpack 5 | ||
futureEmitAssets: true, | ||
filename: 'ssr.js', | ||
@@ -206,7 +219,8 @@ libraryTarget: 'commonjs2', | ||
chunkFilename: isEnvProduction | ||
? 'static/js/[name].[chunkhash:8].chunk.js' | ||
? '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. | ||
// We use "/" in development. | ||
publicPath: publicPath, | ||
publicPath: paths.publicUrlOrPath, | ||
// Point sourcemap entries to original disk location (format as URL on Windows) | ||
@@ -229,4 +243,4 @@ devtoolModuleFilenameTemplate: isEnvProduction | ||
// parse: { | ||
// // we want terser to parse ecma 8 code. However, we don't want it | ||
// // to apply any minfication steps that turns valid ecma 5 code | ||
// // 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' | ||
@@ -247,3 +261,3 @@ // // sections only apply transformations that are ecma 5 safe | ||
// // https://github.com/facebook/create-react-app/issues/5250 | ||
// // Pending futher investigation: | ||
// // Pending further investigation: | ||
// // https://github.com/terser-js/terser/issues/120 | ||
@@ -255,2 +269,5 @@ // inline: 2, | ||
// }, | ||
// // Added for profiling in devtools | ||
// keep_classnames: isEnvProductionProfile, | ||
// keep_fnames: isEnvProductionProfile, | ||
// output: { | ||
@@ -264,7 +281,2 @@ // ecma: 5, | ||
// }, | ||
// // Use multi-process parallel running to improve the build speed | ||
// // Default number of concurrent runs: os.cpus().length - 1 | ||
// parallel: true, | ||
// // Enable file caching | ||
// cache: true, | ||
// sourceMap: shouldUseSourceMap, | ||
@@ -287,2 +299,5 @@ // }), | ||
// }, | ||
// cssProcessorPluginOptions: { | ||
// preset: ['default', { minifyFontValues: { removeQuotes: false } }], | ||
// }, | ||
// }), | ||
@@ -297,21 +312,8 @@ // ], | ||
// }, | ||
// splitChunks:{ | ||
// cacheGroups: { | ||
// js: { | ||
// name: 'js', | ||
// test: /\.(js|mjs|jsx|ts|tsx)$/, | ||
// chunks: 'all', | ||
// enforce: true | ||
// }, | ||
// css: { | ||
// name: 'css', | ||
// test: /\.s?css$/, | ||
// chunks: 'all', | ||
// enforce: true | ||
// } | ||
// }, | ||
// 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}`, | ||
// }, | ||
// Keep the runtime chunk seperated to enable long term caching | ||
// https://twitter.com/wSokra/status/969679223278505985 | ||
// runtimeChunk: true, | ||
runtimeChunk: false, | ||
@@ -321,9 +323,8 @@ }, | ||
resolve: { | ||
// This allows you to set a fallback for where Webpack should look for modules. | ||
// 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) | ||
modules: ['node_modules', paths.appNodeModules].concat( | ||
modules.additionalModulePaths || [] | ||
), | ||
@@ -343,2 +344,8 @@ // These are the reasonable defaults supported by the Node ecosystem. | ||
'react-native': 'react-native-web', | ||
// Allows for better profiling with ReactDevTools | ||
...(isEnvProductionProfile && { | ||
'react-dom$': 'react-dom/profiling', | ||
'scheduler/tracing': 'scheduler/tracing-profiling', | ||
}), | ||
...(modules.webpackAliases || {}), | ||
}, | ||
@@ -359,3 +366,3 @@ plugins: [ | ||
plugins: [ | ||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders | ||
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders | ||
// from the current package. | ||
@@ -374,3 +381,3 @@ PnpWebpackPlugin.moduleLoader(module), | ||
// { | ||
// test: /\.(js|mjs|jsx)$/, | ||
// test: /\.(js|mjs|jsx|ts|tsx)$/, | ||
// enforce: 'pre', | ||
@@ -380,11 +387,14 @@ // use: [ | ||
// options: { | ||
// cache: true, | ||
// formatter: require.resolve('react-dev-utils/eslintFormatter'), | ||
// eslintPath: require.resolve('eslint'), | ||
// resolvePluginsRelativeTo: __dirname, | ||
// // @remove-on-eject-begin | ||
// baseConfig: { | ||
// extends: [require.resolve('eslint-config-react-app')], | ||
// settings: { react: { version: '999.999.999' } }, | ||
// }, | ||
// ignore: false, | ||
// useEslintrc: false, | ||
// ignore: isExtendingEslintConfig, | ||
// baseConfig: isExtendingEslintConfig | ||
// ? undefined | ||
// : { | ||
// extends: [require.resolve('eslint-config-react-app')], | ||
// }, | ||
// useEslintrc: isExtendingEslintConfig, | ||
// // @remove-on-eject-end | ||
@@ -419,3 +429,3 @@ // }, | ||
options: { | ||
limit: 10000, | ||
limit: imageInlineSizeLimit, | ||
name: 'static/media/[name].[hash:8].[ext]', | ||
@@ -467,3 +477,3 @@ }, | ||
ReactComponent: | ||
'@svgr/webpack?-prettier,-svgo![path]', | ||
'@svgr/webpack?-svgo,+titleProp,+ref![path]', | ||
}, | ||
@@ -478,3 +488,4 @@ }, | ||
cacheDirectory: true, | ||
cacheCompression: isEnvProduction, | ||
// See #6846 for context on why cacheCompression is disabled | ||
cacheCompression: false, | ||
compact: isEnvProduction, | ||
@@ -500,3 +511,4 @@ }, | ||
cacheDirectory: true, | ||
cacheCompression: isEnvProduction, | ||
// See #6846 for context on why cacheCompression is disabled | ||
cacheCompression: false, | ||
// @remove-on-eject-begin | ||
@@ -515,7 +527,7 @@ cacheIdentifier: getCacheIdentifier( | ||
// @remove-on-eject-end | ||
// 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. | ||
sourceMaps: 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, | ||
}, | ||
@@ -561,4 +573,5 @@ }, | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
modules: true, | ||
getLocalIdent: getCSSModuleLocalIdent, | ||
modules: { | ||
getLocalIdent: getCSSModuleLocalIdent, | ||
}, | ||
}), | ||
@@ -577,3 +590,3 @@ }, | ||
{ | ||
importLoaders: 2, | ||
importLoaders: 3, | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
@@ -583,3 +596,3 @@ }, | ||
{ | ||
functions: sassFunctions, | ||
sassOptions: sassFunctions, | ||
} | ||
@@ -607,10 +620,11 @@ ), | ||
{ | ||
importLoaders: 2, | ||
importLoaders: 3, | ||
sourceMap: isEnvProduction && shouldUseSourceMap, | ||
modules: true, | ||
getLocalIdent: getCSSModuleLocalIdent, | ||
modules: { | ||
getLocalIdent: getCSSModuleLocalIdent, | ||
}, | ||
}, | ||
'sass-loader', | ||
{ | ||
functions: sassFunctions, | ||
sassOptions: sassFunctions, | ||
} | ||
@@ -668,13 +682,33 @@ ), | ||
// ), | ||
// new HtmlWebpackPlugin( | ||
// Object.assign( | ||
// {}, | ||
// { | ||
// inject: false, | ||
// filename: 'css.html', | ||
// template: path.resolve(__dirname, './css.html'), | ||
// } | ||
// ) | ||
// ), | ||
// new HtmlWebpackPlugin( | ||
// Object.assign( | ||
// {}, | ||
// { | ||
// inject: false, | ||
// filename: 'js.html', | ||
// template: path.resolve(__dirname, './js.html'), | ||
// } | ||
// ) | ||
// ), | ||
// 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/]), | ||
// new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]), | ||
// Makes some environment variables available in index.html. | ||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.: | ||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> | ||
// In production, it will be an empty string unless you specify "homepage" | ||
// <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. | ||
// In development, this will be an empty string. | ||
// new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), | ||
@@ -697,3 +731,3 @@ // This gives some necessary context to module not found errors, such as | ||
// 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 | ||
// to restart the development server for webpack to discover it. This plugin | ||
// makes the discovery automatic so you don't have to restart. | ||
@@ -711,11 +745,28 @@ // See https://github.com/facebook/create-react-app/issues/186 | ||
}), | ||
// Generate a manifest file which contains a mapping of all asset filenames | ||
// to their corresponding output file so that tools can pick it up without | ||
// having to parse `index.html`. | ||
// 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: publicPath, | ||
// 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 | ||
// by default due to how webpack interprets its code. This is a practical | ||
// solution that requires the user to opt into importing specific locales. | ||
@@ -726,3 +777,3 @@ // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack | ||
// Generate a service worker script that will precache, and keep up to date, | ||
// the HTML & assets that are part of the Webpack build. | ||
// the HTML & assets that are part of the webpack build. | ||
// isEnvProduction && | ||
@@ -733,9 +784,11 @@ // new WorkboxWebpackPlugin.GenerateSW({ | ||
// importWorkboxFrom: 'cdn', | ||
// navigateFallback: publicUrl + '/index.html', | ||
// navigateFallback: paths.publicUrlOrPath + 'index.html', | ||
// navigateFallbackBlacklist: [ | ||
// // Exclude URLs starting with /_, as they're likely an API call | ||
// new RegExp('^/_'), | ||
// // Exclude URLs containing a dot, as they're likely a resource in | ||
// // public/ and not a SPA route | ||
// 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('/[^/?]+\\.[^/]+$'), | ||
// ], | ||
@@ -749,16 +802,14 @@ // }), | ||
}), | ||
async: false, | ||
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, | ||
compilerOptions: { | ||
module: 'esnext', | ||
moduleResolution: 'node', | ||
resolveJsonModule: true, | ||
isolatedModules: true, | ||
noEmit: true, | ||
jsx: 'preserve', | ||
}, | ||
reportFiles: [ | ||
'**', | ||
'!**/*.json', | ||
'!**/__tests__/**', | ||
@@ -769,12 +820,15 @@ '!**/?(*.)(spec|test).*', | ||
], | ||
watch: paths.appSrc, | ||
silent: true, | ||
formatter: typescriptFormatter, | ||
// 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. | ||
// 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', | ||
@@ -781,0 +835,0 @@ // tls: 'empty', |
@@ -11,2 +11,3 @@ // @remove-on-eject-begin | ||
const fs = require('fs'); | ||
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); | ||
@@ -16,7 +17,10 @@ const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); | ||
const ignoredFiles = require('react-dev-utils/ignoredFiles'); | ||
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware'); | ||
const paths = require('./paths'); | ||
const fs = require('fs'); | ||
const getHttpsConfig = require('./getHttpsConfig'); | ||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; | ||
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; | ||
@@ -60,16 +64,31 @@ module.exports = function(proxy, allowedHost) { | ||
// for files like `favicon.ico`, `manifest.json`, and libraries that are | ||
// for some reason broken when imported through Webpack. If you just want to | ||
// 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 /sockjs-node/ endpoint | ||
// 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 | ||
// in the webpack development configuration. Note that only changes | ||
// to CSS are currently hot reloaded. JS changes will refresh the browser. | ||
hot: true, | ||
// It is important to tell WebpackDevServer to use the same "root" path | ||
// as we specified in the config. In development, we always serve from /. | ||
publicPath: '/', | ||
// 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 | ||
@@ -85,4 +104,3 @@ // by listening to the compiler events with `compiler.hooks[...].tap` calls above. | ||
}, | ||
// Enable HTTPS if the HTTPS environment variable is set to 'true' | ||
https: protocol === 'https', | ||
https: getHttpsConfig(), | ||
host, | ||
@@ -94,6 +112,15 @@ overlay: false, | ||
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)) { | ||
@@ -103,8 +130,7 @@ // This registers user provided middleware for proxy reasons | ||
} | ||
}, | ||
after(app) { | ||
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match | ||
app.use(redirectServedPath(paths.publicUrlOrPath)); | ||
// 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()); | ||
// This service worker file is effectively a 'no-op' that will reset any | ||
@@ -115,5 +141,5 @@ // previous service worker registered for the same host:port combination. | ||
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432 | ||
app.use(noopServiceWorkerMiddleware()); | ||
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath)); | ||
}, | ||
}; | ||
}; |
@@ -45,3 +45,5 @@ /// <reference types="node" /> | ||
export const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>; | ||
export const ReactComponent: React.FunctionComponent<React.SVGProps< | ||
SVGSVGElement | ||
> & { title?: string }>; | ||
@@ -48,0 +50,0 @@ const src: string; |
{ | ||
"name": "backpack-react-scripts", | ||
"version": "8.0.0-alpha.f5763264", | ||
"version": "8.0.0-beta.64a23dc6", | ||
"description": "Backpack configuration and scripts for Create React App.", | ||
@@ -28,30 +28,29 @@ "repository": { | ||
"dependencies": { | ||
"@babel/core": "7.7.2", | ||
"@babel/core": "7.9.0", | ||
"@svgr/webpack": "4.3.3", | ||
"@typescript-eslint/eslint-plugin": "^2.6.1", | ||
"@typescript-eslint/parser": "^2.6.1", | ||
"@typescript-eslint/eslint-plugin": "^2.10.0", | ||
"@typescript-eslint/parser": "^2.10.0", | ||
"babel-jest": "^24.9.0", | ||
"babel-loader": "8.0.6", | ||
"babel-plugin-named-asset-import": "^0.3.4", | ||
"babel-preset-react-app": "^9.0.2", | ||
"babel-loader": "8.1.0", | ||
"babel-plugin-named-asset-import": "^0.3.6", | ||
"babel-preset-react-app": "^9.1.2", | ||
"bpk-mixins": "^19.1.8", | ||
"camelcase": "^5.2.0", | ||
"case-sensitive-paths-webpack-plugin": "2.2.0", | ||
"css-loader": "3.2.0", | ||
"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", | ||
"file-loader": "4.2.0", | ||
"fork-ts-checker-webpack-plugin-alt": "^0.4.14", | ||
"file-loader": "4.3.0", | ||
"fs-extra": "^8.1.0", | ||
"html-webpack-plugin": "4.0.0-beta.5", | ||
"html-webpack-plugin": "4.0.0-beta.11", | ||
"identity-obj-proxy": "3.0.0", | ||
"jest": "24.9.0", | ||
"jest-environment-jsdom-fourteen": "0.1.0", | ||
"jest-environment-jsdom-fourteen": "1.0.1", | ||
"jest-resolve": "24.9.0", | ||
"jest-watch-typeahead": "0.4.2", | ||
"lodash": "^4.17.15", | ||
"mini-css-extract-plugin": "0.8.0", | ||
"mini-css-extract-plugin": "0.9.0", | ||
"node-sass": "^4.12.0", | ||
"optimize-css-assets-webpack-plugin": "5.0.3", | ||
"pnp-webpack-plugin": "^1.5.0", | ||
"pnp-webpack-plugin": "1.6.4", | ||
"postcss-flexbugs-fixes": "4.1.0", | ||
@@ -62,29 +61,28 @@ "postcss-loader": "3.0.0", | ||
"postcss-safe-parser": "4.0.1", | ||
"react-app-polyfill": "^1.0.4", | ||
"react-dev-utils": "^9.1.0", | ||
"resolve": "1.12.0", | ||
"resolve-url-loader": "3.1.0", | ||
"sass-loader": "8.0.0", | ||
"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": "1.0.0", | ||
"terser-webpack-plugin": "2.2.1", | ||
"ts-pnp": "1.1.4", | ||
"url-loader": "2.2.0", | ||
"webpack": "4.41.2", | ||
"webpack-dev-server": "3.2.1", | ||
"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", | ||
"webpack-subresource-integrity": "^1.4.1", | ||
"workbox-webpack-plugin": "4.3.1" | ||
}, | ||
"devDependencies": { | ||
"bpk-component-button": "^3.2.18", | ||
"bpk-component-code": "^2.0.39", | ||
"bpk-component-text": "^3.0.7", | ||
"bpk-mixins": "^19.1.8", | ||
"bpk-stylesheets": "^6.0.6", | ||
"react": "16.4.2", | ||
"react-dom": "16.4.2" | ||
"react": "16.2.0", | ||
"react-dom": "16.2.0" | ||
}, | ||
"optionalDependencies": { | ||
"fsevents": "2.1.1" | ||
"fsevents": "2.1.2" | ||
}, | ||
"peerDependencies": { | ||
"typescript": "^3.2.1" | ||
}, | ||
"peerDependenciesMeta": { | ||
@@ -106,3 +104,7 @@ "typescript": { | ||
] | ||
} | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "293dccb0ce08d30685903f07fd042842e7c2c6b3" | ||
} |
# backpack-react-scripts | ||
### **Important:** The currently supported version of **CRA** by `backpack-react-scripts` is up to `v2.1.2`. Versions above this will not work. | ||
### **Important:** The currently supported version of **CRA** by `backpack-react-scripts` is up to `v3.4.1`. Versions above this will not work. | ||
@@ -9,3 +9,3 @@ This package is a fork of [Create React App](https://github.com/facebookincubator/create-react-app) (specifically the | ||
```sh | ||
npx create-react-app@2.1.2 my-app --scripts-version=backpack-react-scripts | ||
npx create-react-app@3.4.1 my-app --scripts-version=backpack-react-scripts --template @skyscanner/backpack --use-npm | ||
@@ -20,3 +20,3 @@ # start your app development like you normally would with `create-react-app` | ||
- Compilation of uncompiled Backpack components (specifically JSX). | ||
- Skyscanner specific template with Backpack components integrated out of the box. | ||
- Skyscanner specific template with Backpack components integrated out of the box. Published as `@skyscanner/cra-template-backpack` | ||
- CSS Modules enabled by default for all `.css` & `.scss` files. | ||
@@ -41,3 +41,3 @@ - Ability to create a bundle for server side rending. | ||
``` | ||
npm run publish -- --scope backpack-react-scripts | ||
npm run publish | ||
``` | ||
@@ -50,3 +50,3 @@ | ||
``` | ||
npm run publish -- --scope backpack-react-scripts --canary | ||
npm run publish -- --canary | ||
``` | ||
@@ -53,0 +53,0 @@ |
@@ -139,3 +139,3 @@ // @remove-on-eject-begin | ||
const appPackage = require(paths.appPackageJson); | ||
const publicUrl = paths.publicUrl; | ||
const publicUrl = paths.publicUrlOrPath; | ||
const publicPath = config.output.publicPath; | ||
@@ -142,0 +142,0 @@ const buildFolder = path.relative(process.cwd(), paths.appBuild); |
@@ -44,4 +44,3 @@ // @remove-file-on-eject | ||
function tryGitInit(appPath) { | ||
let didInit = false; | ||
function tryGitInit() { | ||
try { | ||
@@ -54,6 +53,13 @@ execSync('git --version', { stdio: 'ignore' }); | ||
execSync('git init', { stdio: 'ignore' }); | ||
didInit = true; | ||
return true; | ||
} catch (e) { | ||
console.warn('Git repo not initialized', e); | ||
return false; | ||
} | ||
} | ||
function tryGitCommit(appPath) { | ||
try { | ||
execSync('git add -A', { stdio: 'ignore' }); | ||
execSync('git commit -m "Initial commit from Create React App"', { | ||
execSync('git commit -m "Initialize project using Create React App"', { | ||
stdio: 'ignore', | ||
@@ -63,14 +69,14 @@ }); | ||
} catch (e) { | ||
if (didInit) { | ||
// If we successfully initialized but couldn't commit, | ||
// maybe the commit author config is not set. | ||
// In the future, we might supply our own committer | ||
// like Ember CLI does, but for now, let's just | ||
// remove the Git files to avoid a half-done state. | ||
try { | ||
// unlinkSync() doesn't work on directories. | ||
fs.removeSync(path.join(appPath, '.git')); | ||
} catch (removeErr) { | ||
// Ignore. | ||
} | ||
// We couldn't commit in already initialized git repo, | ||
// maybe the commit author config is not set. | ||
// In the future, we might supply our own committer | ||
// like Ember CLI does, but for now, let's just | ||
// remove the Git files to avoid a half-done state. | ||
console.warn('Git commit not created', e); | ||
console.warn('Removing .git directory...'); | ||
try { | ||
// unlinkSync() doesn't work on directories. | ||
fs.removeSync(path.join(appPath, '.git')); | ||
} catch (removeErr) { | ||
// Ignore. | ||
} | ||
@@ -111,2 +117,57 @@ return false; | ||
let templateJsonPath; | ||
if (templateName) { | ||
templateJsonPath = path.join(templatePath, 'template.json'); | ||
} else { | ||
// TODO: Remove support for this in v4. | ||
templateJsonPath = path.join(appPath, '.template.dependencies.json'); | ||
} | ||
let templateJson = {}; | ||
if (fs.existsSync(templateJsonPath)) { | ||
templateJson = require(templateJsonPath); | ||
} | ||
const templatePackage = templateJson.package || {}; | ||
// Keys to ignore in templatePackage | ||
const templatePackageBlacklist = [ | ||
'name', | ||
'version', | ||
'description', | ||
'keywords', | ||
'bugs', | ||
'license', | ||
'author', | ||
'contributors', | ||
'files', | ||
'browser', | ||
'bin', | ||
'man', | ||
'directories', | ||
'repository', | ||
'devDependencies', | ||
'peerDependencies', | ||
'bundledDependencies', | ||
'optionalDependencies', | ||
'engineStrict', | ||
'os', | ||
'cpu', | ||
'preferGlobal', | ||
'private', | ||
'publishConfig', | ||
]; | ||
// Keys from templatePackage that will be merged with appPackage | ||
const templatePackageToMerge = ['dependencies', 'scripts']; | ||
// Keys from templatePackage that will be added to appPackage, | ||
// replacing any existing entries. | ||
const templatePackageToReplace = Object.keys(templatePackage).filter(key => { | ||
return ( | ||
!templatePackageBlacklist.includes(key) && | ||
!templatePackageToMerge.includes(key) | ||
); | ||
}); | ||
// Copy over some of the devDependencies | ||
@@ -116,9 +177,25 @@ appPackage.dependencies = appPackage.dependencies || {}; | ||
// Setup the script rules | ||
appPackage.scripts = { | ||
start: 'react-scripts start', | ||
build: 'react-scripts build', | ||
test: 'react-scripts test', | ||
eject: 'react-scripts eject', | ||
}; | ||
// TODO: deprecate 'scripts' key directly on templateJson | ||
const templateScripts = templatePackage.scripts || templateJson.scripts || {}; | ||
appPackage.scripts = Object.assign( | ||
{ | ||
start: 'react-scripts start', | ||
build: 'react-scripts build', | ||
test: 'react-scripts test', | ||
eject: 'react-scripts eject', | ||
}, | ||
templateScripts | ||
); | ||
// Update scripts for Yarn users | ||
if (useYarn) { | ||
appPackage.scripts = Object.entries(appPackage.scripts).reduce( | ||
(acc, [key, value]) => ({ | ||
...acc, | ||
[key]: value.replace(/(npm run |npm )/, 'yarn '), | ||
}), | ||
{} | ||
); | ||
} | ||
// Setup the eslint config | ||
@@ -132,2 +209,7 @@ // appPackage.eslintConfig = { | ||
// Add templatePackage keys/values to appPackage, replacing existing entries | ||
templatePackageToReplace.forEach(key => { | ||
appPackage[key] = templatePackage[key]; | ||
}); | ||
fs.writeFileSync( | ||
@@ -171,5 +253,11 @@ path.join(appPath, 'package.json'), | ||
// Rename gitignore after the fact to prevent npm from renaming it to .npmignore | ||
// See: https://github.com/npm/npm/issues/1862 | ||
try { | ||
const gitignoreExists = fs.existsSync(path.join(appPath, '.gitignore')); | ||
if (gitignoreExists) { | ||
// Append if there's already a `.gitignore` file there | ||
const data = fs.readFileSync(path.join(appPath, 'gitignore')); | ||
fs.appendFileSync(path.join(appPath, '.gitignore'), data); | ||
fs.unlinkSync(path.join(appPath, 'gitignore')); | ||
} else { | ||
// Rename gitignore after the fact to prevent npm from renaming it to .npmignore | ||
// See: https://github.com/npm/npm/issues/1862 | ||
fs.moveSync( | ||
@@ -180,13 +268,13 @@ path.join(appPath, 'gitignore'), | ||
); | ||
} catch (err) { | ||
// Append if there's already a `.gitignore` file there | ||
if (err.code === 'EEXIST') { | ||
const data = fs.readFileSync(path.join(appPath, 'gitignore')); | ||
fs.appendFileSync(path.join(appPath, '.gitignore'), data); | ||
fs.unlinkSync(path.join(appPath, 'gitignore')); | ||
} else { | ||
throw err; | ||
} | ||
} | ||
// Initialize git repo | ||
let initializedGit = false; | ||
if (tryGitInit()) { | ||
initializedGit = true; | ||
console.log(); | ||
console.log('Initialized a git repository.'); | ||
} | ||
let command; | ||
@@ -207,11 +295,6 @@ let remove; | ||
// Install additional template dependencies, if present | ||
let templateJsonPath; | ||
if (templateName) { | ||
templateJsonPath = path.join(templatePath, 'template.json'); | ||
} else { | ||
templateJsonPath = path.join(appPath, '.template.dependencies.json'); | ||
} | ||
if (fs.existsSync(templateJsonPath)) { | ||
const templateDependencies = require(templateJsonPath).dependencies; | ||
// TODO: deprecate 'dependencies' key directly on templateJson | ||
const templateDependencies = | ||
templatePackage.dependencies || templateJson.dependencies; | ||
if (templateDependencies) { | ||
args = args.concat( | ||
@@ -222,3 +305,2 @@ Object.keys(templateDependencies).map(key => { | ||
); | ||
fs.unlinkSync(templateJsonPath); | ||
} | ||
@@ -229,3 +311,3 @@ | ||
if (!isReactInstalled(appPackage)) { | ||
args = args.concat(['react@16.4.2', 'react-dom@16.4.2']); | ||
args = args.concat(['react@16.2.0', 'react-dom@16.2.0']); | ||
} | ||
@@ -266,5 +348,6 @@ | ||
if (tryGitInit(appPath)) { | ||
// Create git commit if git repo was initialized | ||
if (initializedGit && tryGitCommit(appPath)) { | ||
console.log(); | ||
console.log('Initialized a git repository.'); | ||
console.log('Created git commit.'); | ||
} | ||
@@ -271,0 +354,0 @@ |
@@ -94,2 +94,3 @@ // @remove-on-eject-begin | ||
} | ||
const config = configFactory('development'); | ||
@@ -100,3 +101,8 @@ const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; | ||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true'; | ||
const urls = prepareUrls(protocol, HOST, port); | ||
const urls = prepareUrls( | ||
protocol, | ||
HOST, | ||
port, | ||
paths.publicUrlOrPath.slice(0, -1) | ||
); | ||
const devSocket = { | ||
@@ -121,3 +127,7 @@ warnings: warnings => | ||
const proxySetting = require(paths.appPackageJson).proxy; | ||
const proxyConfig = prepareProxy(proxySetting, paths.appPublic); | ||
const proxyConfig = prepareProxy( | ||
proxySetting, | ||
paths.appPublic, | ||
paths.publicUrlOrPath | ||
); | ||
// Serve webpack assets generated by the compiler over a web server. | ||
@@ -160,2 +170,11 @@ const serverConfig = createDevServerConfig( | ||
}); | ||
if (isInteractive || process.env.CI !== 'true') { | ||
// Gracefully exit when stdin ends | ||
process.stdin.on('end', function() { | ||
devServer.close(); | ||
process.exit(); | ||
}); | ||
process.stdin.resume(); | ||
} | ||
}) | ||
@@ -162,0 +181,0 @@ .catch(err => { |
@@ -1,1 +0,1 @@ | ||
This file has moved [here](https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/README.md) | ||
Learn about making a Progressive Web App [here](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
181921
4.86%2
-71.43%29
3.57%4123
5.56%49
2.08%82
12.33%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated