diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4ef50efcac3..d2612759e2f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -85,19 +85,18 @@ ### Environment + To help identify if a problem is specific to a platform, browser, or module version, information about your environment is required. + This enables the maintainers quickly reproduce the issue and give feedback. -1. `node -v`: -2. `npm -v`: -3. `yarn --version` (if you use Yarn): -4. `npm ls react-scripts` (if you haven’t ejected): + Run the following command in your React app's folder in terminal. + Note: The result is copied to your clipboard directly. -Then, specify: + `npx create-react-app --info` -1. Operating system: -2. Browser and version (if relevant): + Paste the output of the command in the section below. +--> +(paste the output of the command here) ### Steps to Reproduce diff --git a/CHANGELOG.md b/CHANGELOG.md index 796c6a1e56e..9c63d42f570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,85 @@ +## 1.1.4 (April 3, 2018) + +#### :bug: Bug Fix + +* `react-dev-utils` + + * [#4250](https://github.com/facebook/create-react-app/pull/4250) Upgrade `detect-port-alt` to fix [#4189](https://github.com/facebook/create-react-app/issues/4189). ([@Timer](https://github.com/Timer)) + +#### Committers: 1 +- Joe Haddad ([Timer](https://github.com/Timer)) + +### Migrating from 1.1.3 to 1.1.4 + +Inside any created project that has not been ejected, run: + +``` +npm install --save --save-exact react-scripts@1.1.4 +``` + +or + +``` +yarn add --exact react-scripts@1.1.4 +``` + +## 1.1.3 (April 3, 2018) + +#### :bug: Bug Fix + +* `react-scripts` + + * [#4247](https://github.com/facebook/create-react-app/pull/4247) Fix `environment.dispose is not a function` error caused by a Jest bug. ([@gaearon](https://github.com/gaearon)) + +#### Committers: 1 +- Dan Abramov ([gaearon](https://github.com/gaearon)) + +### Migrating from 1.1.2 to 1.1.3 + +Inside any created project that has not been ejected, run: + +``` +npm install --save --save-exact react-scripts@1.1.3 +``` + +or + +``` +yarn add --exact react-scripts@1.1.3 +``` + +## 1.1.2 (April 3, 2018) + +#### :bug: Bug Fix + +* `react-scripts` + + * [#4085](https://github.com/facebook/create-react-app/pull/4085) Resolve `.js` before `.mjs` files to unbreak dependencies with native ESM support. ([@leebyron](https://github.com/leebyron)) + +#### :memo: Documentation + +* `react-scripts` + + * [#4197](https://github.com/facebook/create-react-app/pull/4197) Add troubleshooting for Github Pages. ([@xnt](https://github.com/xnt)) + +#### Committers: 2 +- Lee Byron ([leebyron](https://github.com/leebyron)) +- Vicente Plata ([xnt](https://github.com/xnt)) + +### Migrating from 1.1.1 to 1.1.2 + +Inside any created project that has not been ejected, run: + +``` +npm install --save --save-exact react-scripts@1.1.2 +``` + +or + +``` +yarn add --exact react-scripts@1.1.2 +``` + ## 1.1.1 (February 2, 2018) #### :bug: Bug Fix diff --git a/README.md b/README.md index 698cf4fc3f2..655aeff4955 100644 --- a/README.md +++ b/README.md @@ -224,3 +224,7 @@ We are grateful to the authors of existing related projects for their ideas and * [@eanplatter](https://github.com/eanplatter) * [@insin](https://github.com/insin) * [@mxstbr](https://github.com/mxstbr) + +## License + +Create React App is open source software [licensed as MIT](https://github.com/facebook/create-react-app/blob/master/LICENSE). diff --git a/package.json b/package.json index 9a590471c3c..1084992025b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "husky": "^0.13.2", "lerna": "2.6.0", "lerna-changelog": "^0.6.0", - "lint-staged": "^3.3.1", + "lint-staged": "^7.0.5", "meow": "^4.0.0", "multimatch": "^2.1.0", "prettier": "1.6.1", diff --git a/packages/babel-plugin-named-asset-import/package.json b/packages/babel-plugin-named-asset-import/package.json index 2517156308c..eec4516f8ac 100644 --- a/packages/babel-plugin-named-asset-import/package.json +++ b/packages/babel-plugin-named-asset-import/package.json @@ -12,6 +12,6 @@ "index.js" ], "peerDependencies": { - "@babel/core": "7.0.0-beta.42" + "@babel/core": "7.0.0-beta.46" } } diff --git a/packages/babel-preset-react-app/index.js b/packages/babel-preset-react-app/index.js index 87b070070d9..72089b9b78b 100644 --- a/packages/babel-preset-react-app/index.js +++ b/packages/babel-preset-react-app/index.js @@ -92,7 +92,14 @@ module.exports = function(api, opts) { // don't work without it: https://github.com/babel/babel/issues/7215 require('@babel/plugin-transform-destructuring').default, // class { handleClick = () => { } } - require('@babel/plugin-proposal-class-properties').default, + // Enable loose mode to use assignment instead of defineProperty + // See discussion in https://github.com/facebook/create-react-app/issues/4263 + [ + require('@babel/plugin-proposal-class-properties').default, + { + loose: true, + }, + ], // The following two plugins use Object.assign directly, instead of Babel's // extends helper. Note that this assumes `Object.assign` is available. // { ...todo, completed: true } diff --git a/packages/babel-preset-react-app/package.json b/packages/babel-preset-react-app/package.json index 3c620b55be3..e251fa571a7 100644 --- a/packages/babel-preset-react-app/package.json +++ b/packages/babel-preset-react-app/package.json @@ -12,19 +12,19 @@ "dependencies.js" ], "dependencies": { - "@babel/core": "7.0.0-beta.42", - "@babel/plugin-proposal-class-properties": "7.0.0-beta.42", - "@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.42", - "@babel/plugin-syntax-dynamic-import": "7.0.0-beta.42", - "@babel/plugin-transform-classes": "7.0.0-beta.42", - "@babel/plugin-transform-destructuring": "7.0.0-beta.42", - "@babel/plugin-transform-react-constant-elements": "7.0.0-beta.42", - "@babel/plugin-transform-react-display-name": "7.0.0-beta.42", - "@babel/plugin-transform-regenerator": "7.0.0-beta.42", - "@babel/plugin-transform-runtime": "7.0.0-beta.42", - "@babel/preset-env": "7.0.0-beta.42", - "@babel/preset-flow": "7.0.0-beta.42", - "@babel/preset-react": "7.0.0-beta.42", + "@babel/core": "7.0.0-beta.46", + "@babel/plugin-proposal-class-properties": "7.0.0-beta.46", + "@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.46", + "@babel/plugin-syntax-dynamic-import": "7.0.0-beta.46", + "@babel/plugin-transform-classes": "7.0.0-beta.46", + "@babel/plugin-transform-destructuring": "7.0.0-beta.46", + "@babel/plugin-transform-react-constant-elements": "7.0.0-beta.46", + "@babel/plugin-transform-react-display-name": "7.0.0-beta.46", + "@babel/plugin-transform-regenerator": "7.0.0-beta.46", + "@babel/plugin-transform-runtime": "7.0.0-beta.46", + "@babel/preset-env": "7.0.0-beta.46", + "@babel/preset-flow": "7.0.0-beta.46", + "@babel/preset-react": "7.0.0-beta.46", "babel-plugin-macros": "2.0.0", "babel-plugin-transform-dynamic-import": "2.0.0", "babel-plugin-transform-react-remove-prop-types": "0.4.12" diff --git a/packages/confusing-browser-globals/package.json b/packages/confusing-browser-globals/package.json index b96cff9ef93..874bec0a52b 100644 --- a/packages/confusing-browser-globals/package.json +++ b/packages/confusing-browser-globals/package.json @@ -16,6 +16,6 @@ "index.js" ], "devDependencies": { - "jest": "22.1.2" + "jest": "22.4.1" } } diff --git a/packages/create-react-app/createReactApp.js b/packages/create-react-app/createReactApp.js index 1bf3bb0649d..b37086f0418 100755 --- a/packages/create-react-app/createReactApp.js +++ b/packages/create-react-app/createReactApp.js @@ -84,11 +84,17 @@ const program = new commander.Command(packageJson.name) ` A custom ${chalk.cyan('--scripts-version')} can be one of:` ); console.log(` - a specific npm version: ${chalk.green('0.8.2')}`); + console.log(` - a specific npm tag: ${chalk.green('@next')}`); console.log( ` - a custom fork published on npm: ${chalk.green( 'my-react-scripts' )}` ); + console.log( + ` - a local path relative to the current working directory: ${chalk.green( + 'file:../my-react-scripts' + )}` + ); console.log( ` - a .tgz archive: ${chalk.green( 'https://mysite.com/my-react-scripts-0.8.2.tgz' @@ -115,15 +121,28 @@ const program = new commander.Command(packageJson.name) }) .parse(process.argv); +if (program.info) { + console.log(chalk.bold('\nEnvironment Info:')); + return envinfo + .run( + { + System: ['OS', 'CPU'], + Binaries: ['Node', 'npm', 'Yarn'], + Browsers: ['Chrome', 'Edge', 'Internet Explorer', 'Firefox', 'Safari'], + npmPackages: ['react', 'react-dom', 'react-scripts'], + npmGlobalPackages: ['create-react-app'], + }, + { + clipboard: true, + duplicates: true, + showNotFound: true, + } + ) + .then(console.log) + .then(() => console.log(chalk.green('Copied To Clipboard!\n'))); +} + if (typeof projectName === 'undefined') { - if (program.info) { - envinfo.print({ - packages: ['react', 'react-dom', 'react-scripts'], - noNativeIDE: true, - duplicates: true, - }); - process.exit(0); - } console.error('Please specify the project directory:'); console.log( ` ${chalk.cyan(program.name())} ${chalk.green('')}` @@ -389,14 +408,18 @@ function getInstallPackage(version, originalDirectory) { const validSemver = semver.valid(version); if (validSemver) { packageToInstall += `@${validSemver}`; - } else if (version && version.match(/^file:/)) { - packageToInstall = `file:${path.resolve( - originalDirectory, - version.match(/^file:(.*)?$/)[1] - )}`; } else if (version) { - // for tar.gz or alternative paths - packageToInstall = version; + if (version[0] === '@') { + packageToInstall += version; + } else if (version.match(/^file:/)) { + packageToInstall = `file:${path.resolve( + originalDirectory, + version.match(/^file:(.*)?$/)[1] + )}`; + } else { + // for tar.gz or alternative paths + packageToInstall = version; + } } return packageToInstall; } diff --git a/packages/create-react-app/package.json b/packages/create-react-app/package.json index 86bd258f736..27f7fc74089 100644 --- a/packages/create-react-app/package.json +++ b/packages/create-react-app/package.json @@ -24,7 +24,7 @@ "chalk": "^1.1.3", "commander": "^2.9.0", "cross-spawn": "^4.0.0", - "envinfo": "3.4.2", + "envinfo": "5.4.0", "fs-extra": "^5.0.0", "hyperquest": "^2.1.2", "react-dev-utils": "^5.0.0", diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 8527793542c..7d2e716956a 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -131,7 +131,7 @@ module.exports = { 'no-unused-vars': [ 'warn', { - args: 'all', + args: 'none', ignoreRestSiblings: true, }, ], @@ -186,6 +186,7 @@ module.exports = { 'import/no-webpack-loader-syntax': 'error', // https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules + 'react/forbid-foreign-prop-types': ['warn', { allowInPropTypes: true }], 'react/jsx-no-comment-textnodes': 'warn', 'react/jsx-no-duplicate-props': ['warn', { ignoreCase: true }], 'react/jsx-no-target-blank': 'warn', diff --git a/packages/eslint-config-react-app/package.json b/packages/eslint-config-react-app/package.json index 45dfc42e76e..c4b51925e69 100644 --- a/packages/eslint-config-react-app/package.json +++ b/packages/eslint-config-react-app/package.json @@ -16,7 +16,7 @@ "eslint-plugin-flowtype": "^2.34.1", "eslint-plugin-import": "^2.6.0", "eslint-plugin-jsx-a11y": "^6.0.2", - "eslint-plugin-react": "^7.1.0" + "eslint-plugin-react": "^7.7.0" }, "dependencies": { "confusing-browser-globals": "^1.0.0" diff --git a/packages/react-dev-utils/ModuleScopePlugin.js b/packages/react-dev-utils/ModuleScopePlugin.js index 101a30a1fb9..695426331b9 100644 --- a/packages/react-dev-utils/ModuleScopePlugin.js +++ b/packages/react-dev-utils/ModuleScopePlugin.js @@ -12,12 +12,12 @@ const path = require('path'); class ModuleScopePlugin { constructor(appSrc, allowedFiles = []) { - this.appSrc = appSrc; + this.appSrcs = Array.isArray(appSrc) ? appSrc : [appSrc]; this.allowedFiles = new Set(allowedFiles); } apply(resolver) { - const { appSrc } = this; + const { appSrcs } = this; resolver.plugin('file', (request, callback) => { // Unknown issuer, probably webpack internals if (!request.context.issuer) { @@ -34,9 +34,13 @@ class ModuleScopePlugin { } // Resolve the issuer from our appSrc and make sure it's one of our files // Maybe an indexOf === 0 would be better? - const relative = path.relative(appSrc, request.context.issuer); - // If it's not in src/ or a subdirectory, not our request! - if (relative.startsWith('../') || relative.startsWith('..\\')) { + if ( + appSrcs.every(appSrc => { + const relative = path.relative(appSrc, request.context.issuer); + // If it's not in one of our app src or a subdirectory, not our request! + return relative.startsWith('../') || relative.startsWith('..\\'); + }) + ) { return callback(); } const requestFullPath = path.resolve( @@ -47,11 +51,15 @@ class ModuleScopePlugin { return callback(); } // Find path from src to the requested file - // Error if in a parent directory of src/ - const requestRelative = path.relative(appSrc, requestFullPath); + // Error if in a parent directory of all given appSrcs if ( - requestRelative.startsWith('../') || - requestRelative.startsWith('..\\') + appSrcs.every(appSrc => { + const requestRelative = path.relative(appSrc, requestFullPath); + return ( + requestRelative.startsWith('../') || + requestRelative.startsWith('..\\') + ); + }) ) { callback( new Error( diff --git a/packages/react-dev-utils/README.md b/packages/react-dev-utils/README.md index 5279ade8f41..f63febe7c65 100644 --- a/packages/react-dev-utils/README.md +++ b/packages/react-dev-utils/README.md @@ -57,9 +57,9 @@ module.exports = { ``` -#### `new ModuleScopePlugin(appSrc: string, allowedFiles?: string[])` +#### `new ModuleScopePlugin(appSrc: string | string[], allowedFiles?: string[])` -This Webpack plugin ensures that relative imports from app's source directory don't reach outside of it. +This Webpack plugin ensures that relative imports from app's source directories don't reach outside of it. ```js var path = require('path'); @@ -326,3 +326,40 @@ module.exports = { // ... } ``` + +#### `getCSSModuleLocalIdent(context: Object, localIdentName: String, localName: String, options: Object): string` + +Creates a class name for CSS Modules that uses either the filename or folder name if named `index.module.css`. + +For `MyFolder/MyComponent.module.css` and class `MyClass` the output will be `MyComponent.module_MyClass__[hash]` +For `MyFolder/index.module.css` and class `MyClass` the output will be `MyFolder_MyClass__[hash]` + +```js +const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); + +// In your webpack config: +// ... +module: { + rules: [ + { + test: /\.module\.css$/, + use: [ + require.resolve('style-loader'), + { + loader: require.resolve('css-loader'), + options: { + importLoaders: 1, + modules: true, + getLocalIdent: getCSSModuleLocalIdent, + }, + }, + { + loader: require.resolve('postcss-loader'), + options: postCSSLoaderOptions, + }, + ], + } + ] +} +``` + diff --git a/packages/react-dev-utils/getCSSModuleLocalIdent.js b/packages/react-dev-utils/getCSSModuleLocalIdent.js new file mode 100644 index 00000000000..d1cd22a4e05 --- /dev/null +++ b/packages/react-dev-utils/getCSSModuleLocalIdent.js @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const loaderUtils = require('loader-utils'); + +module.exports = function getLocalIdent( + context, + localIdentName, + localName, + options +) { + // Use the filename or folder name, based on some uses the index.js / index.module.css project style + const fileNameOrFolder = context.resourcePath.endsWith('index.module.css') + ? '[folder]' + : '[name]'; + // Create a hash based on a the file location and class name. Will be unique across a project, and close to globally unique. + const hash = loaderUtils.getHashDigest( + context.resourcePath + localName, + 'md5', + 'base64', + 5 + ); + // Use loaderUtils to find the file or folder name + const className = loaderUtils.interpolateName( + context, + fileNameOrFolder + '_' + localName + '__' + hash, + options + ); + // remove the .module that appears in every classname when based on the file. + return className.replace('.module_', '_'); +}; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index 96c17ddded4..a88af75e7c0 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -20,6 +20,7 @@ "eslintFormatter.js", "FileSizeReporter.js", "formatWebpackMessages.js", + "getCSSModuleLocalIdent.js", "getProcessForPort.js", "ignoredFiles.js", "inquirer.js", @@ -38,12 +39,12 @@ "workspaceUtils.js" ], "dependencies": { - "@babel/code-frame": "7.0.0-beta.42", + "@babel/code-frame": "7.0.0-beta.46", "address": "1.0.3", "browserslist": "2.11.3", "chalk": "2.3.0", "cross-spawn": "5.1.0", - "detect-port-alt": "1.1.5", + "detect-port-alt": "1.1.6", "escape-string-regexp": "1.0.5", "filesize": "3.5.11", "find-pkg": "1.0.0", @@ -62,7 +63,7 @@ "text-table": "0.2.0" }, "devDependencies": { - "jest": "22.1.2" + "jest": "22.4.1" }, "scripts": { "test": "jest" diff --git a/packages/react-error-overlay/package.json b/packages/react-error-overlay/package.json index 282cca890d0..f6b45a1d5e8 100644 --- a/packages/react-error-overlay/package.json +++ b/packages/react-error-overlay/package.json @@ -30,13 +30,13 @@ "lib/index.js" ], "devDependencies": { - "@babel/code-frame": "7.0.0-beta.42", - "@babel/core": "7.0.0-beta.42", - "@babel/runtime": "7.0.0-beta.42", + "@babel/code-frame": "7.0.0-beta.46", + "@babel/core": "7.0.0-beta.46", + "@babel/runtime": "7.0.0-beta.46", "anser": "1.4.6", "babel-core": "^7.0.0-bridge.0", "babel-eslint": "^8.2.2", - "babel-jest": "^22.1.0", + "babel-jest": "^22.4.1", "babel-loader": "^8.0.0-beta.0", "babel-preset-react-app": "^3.1.1", "chalk": "^2.1.0", @@ -47,10 +47,10 @@ "eslint-plugin-flowtype": "2.41.0", "eslint-plugin-import": "2.8.0", "eslint-plugin-jsx-a11y": "6.0.3", - "eslint-plugin-react": "7.5.1", + "eslint-plugin-react": "7.7.0", "flow-bin": "^0.63.1", "html-entities": "1.2.1", - "jest": "22.1.2", + "jest": "22.4.1", "jest-fetch-mock": "1.2.1", "object-assign": "4.1.1", "promise": "8.0.1", diff --git a/packages/react-error-overlay/src/components/CodeBlock.js b/packages/react-error-overlay/src/components/CodeBlock.js index 3165bb3b028..f2bda36342b 100644 --- a/packages/react-error-overlay/src/components/CodeBlock.js +++ b/packages/react-error-overlay/src/components/CodeBlock.js @@ -10,6 +10,7 @@ import React from 'react'; import { redTransparent, yellowTransparent } from '../styles'; const _preStyle = { + position: 'relative', display: 'block', padding: '0.5em', marginTop: '0.5em', diff --git a/packages/react-error-overlay/src/effects/proxyConsole.js b/packages/react-error-overlay/src/effects/proxyConsole.js index a1e8373a1bb..db270e9ddef 100644 --- a/packages/react-error-overlay/src/effects/proxyConsole.js +++ b/packages/react-error-overlay/src/effects/proxyConsole.js @@ -28,7 +28,7 @@ const registerReactStack = () => { // $FlowFixMe console.reactStack = frames => reactFrameStack.push(frames); // $FlowFixMe - console.reactStackEnd = () => reactFrameStack.pop(); + console.reactStackEnd = frames => reactFrameStack.pop(); } }; diff --git a/packages/react-error-overlay/src/utils/getStackFrames.js b/packages/react-error-overlay/src/utils/getStackFrames.js index b01c6ebaee5..9721e316c52 100644 --- a/packages/react-error-overlay/src/utils/getStackFrames.js +++ b/packages/react-error-overlay/src/utils/getStackFrames.js @@ -13,7 +13,7 @@ import { unmap } from './unmapper'; function getStackFrames( error: Error, - unhandledRejection: boolean = false, // eslint-disable-line + unhandledRejection: boolean = false, contextSize: number = 3 ): Promise { const parsedFrames = parse(error); diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index 4766fac4dcf..8bf6ea2bac5 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -18,6 +18,7 @@ const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); +const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const getClientEnvironment = require('./env'); const paths = require('./paths'); @@ -50,6 +51,31 @@ const postCSSLoaderOptions = { ], }; +// style files regexes +const cssRegex = /\.css$/; +const cssModuleRegex = /\.module\.css$/; +const sassRegex = /\.(scss|sass)$/; +const sassModuleRegex = /\.module\.(scss|sass)$/; + +// common function to get style loaders +const getStyleLoaders = (cssOptions, preProcessor) => { + const loaders = [ + require.resolve('style-loader'), + { + loader: require.resolve('css-loader'), + options: cssOptions, + }, + { + loader: require.resolve('postcss-loader'), + options: postCSSLoaderOptions, + }, + ]; + if (preProcessor) { + loaders.push(require.resolve(preProcessor)); + } + return loaders; +}; + // This is the development configuration. // It is focused on developer experience and fast rebuilds. // The production configuration is different and lives in a separate file. @@ -248,41 +274,44 @@ module.exports = { // in development "style" loader enables hot editing of CSS. // By default we support CSS Modules with the extension .module.css { - test: /\.css$/, - exclude: /\.module\.css$/, - use: [ - require.resolve('style-loader'), - { - loader: require.resolve('css-loader'), - options: { - importLoaders: 1, - }, - }, - { - loader: require.resolve('postcss-loader'), - options: postCSSLoaderOptions, - }, - ], + test: cssRegex, + exclude: cssModuleRegex, + use: getStyleLoaders({ + importLoaders: 1, + }), }, // Adds support for CSS Modules (https://github.com/css-modules/css-modules) // using the extension .module.css { - test: /\.module\.css$/, - use: [ - require.resolve('style-loader'), - { - loader: require.resolve('css-loader'), - options: { - importLoaders: 1, - modules: true, - localIdentName: '[path]__[name]___[local]', - }, - }, + test: cssModuleRegex, + use: getStyleLoaders({ + importLoaders: 1, + modules: true, + getLocalIdent: getCSSModuleLocalIdent, + }), + }, + // Opt-in support for SASS (using .scss or .sass extensions). + // Chains the sass-loader with the css-loader and the style-loader + // to immediately apply all styles to the DOM. + // By default we support SASS Modules with the + // extensions .module.scss or .module.sass + { + test: sassRegex, + exclude: sassModuleRegex, + use: getStyleLoaders({ importLoaders: 2 }, 'sass-loader'), + }, + // Adds support for CSS Modules, but using SASS + // using the extension .module.scss or .module.sass + { + test: sassModuleRegex, + use: getStyleLoaders( { - loader: require.resolve('postcss-loader'), - options: postCSSLoaderOptions, + importLoaders: 2, + modules: true, + getLocalIdent: getCSSModuleLocalIdent, }, - ], + 'sass-loader' + ), }, // The GraphQL loader preprocesses GraphQL queries in .graphql files. { diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index d631fc32a3b..c8d1f3b13d9 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -19,6 +19,7 @@ const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); +const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const paths = require('./paths'); const getClientEnvironment = require('./env'); @@ -68,6 +69,49 @@ const postCSSLoaderOptions = { flexbox: 'no-2009', }), ], + sourceMap: shouldUseSourceMap, +}; + +// style files regexes +const cssRegex = /\.css$/; +const cssModuleRegex = /\.module\.css$/; +const sassRegex = /\.(scss|sass)$/; +const sassModuleRegex = /\.module\.(scss|sass)$/; + +// common function to get style loaders +const getStyleLoaders = (cssOptions, preProcessor) => { + const loaders = [ + { + loader: require.resolve('css-loader'), + options: cssOptions, + }, + { + loader: require.resolve('postcss-loader'), + options: postCSSLoaderOptions, + }, + ]; + if (preProcessor) { + loaders.push({ + loader: require.resolve(preProcessor), + options: { + sourceMap: shouldUseSourceMap, + }, + }); + } + return ExtractTextPlugin.extract( + Object.assign( + { + fallback: { + loader: require.resolve('style-loader'), + options: { + hmr: false, + }, + }, + use: loaders, + }, + extractTextPluginOptions + ) + ); }; // This is the production configuration. @@ -254,69 +298,59 @@ module.exports = { // in the main CSS file. // By default we support CSS Modules with the extension .module.css { - test: /\.css$/, - exclude: /\.module\.css$/, - loader: ExtractTextPlugin.extract( - Object.assign( - { - fallback: { - loader: require.resolve('style-loader'), - options: { - hmr: false, - }, - }, - use: [ - { - loader: require.resolve('css-loader'), - options: { - importLoaders: 1, - minimize: true, - sourceMap: shouldUseSourceMap, - }, - }, - { - loader: require.resolve('postcss-loader'), - options: postCSSLoaderOptions, - }, - ], - }, - extractTextPluginOptions - ) - ), + test: cssRegex, + exclude: cssModuleRegex, + loader: getStyleLoaders({ + importLoaders: 1, + minimize: true, + sourceMap: shouldUseSourceMap, + }), // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, // Adds support for CSS Modules (https://github.com/css-modules/css-modules) // using the extension .module.css { - test: /\.module\.css$/, - loader: ExtractTextPlugin.extract( - Object.assign( - { - fallback: { - loader: require.resolve('style-loader'), - options: { - hmr: false, - }, - }, - use: [ - { - loader: require.resolve('css-loader'), - options: { - importLoaders: 1, - minimize: true, - sourceMap: shouldUseSourceMap, - modules: true, - localIdentName: '[path]__[name]___[local]', - }, - }, - { - loader: require.resolve('postcss-loader'), - options: postCSSLoaderOptions, - }, - ], - }, - extractTextPluginOptions - ) + test: cssModuleRegex, + loader: getStyleLoaders({ + importLoaders: 1, + minimize: true, + sourceMap: shouldUseSourceMap, + modules: true, + getLocalIdent: getCSSModuleLocalIdent, + }), + // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. + }, + // Opt-in support for SASS. The logic here is somewhat similar + // as in the CSS routine, except that "sass-loader" runs first + // to compile SASS files into CSS. + // By default we support SASS Modules with the + // extensions .module.scss or .module.sass + { + test: sassRegex, + exclude: sassModuleRegex, + loader: getStyleLoaders( + { + importLoaders: 2, + minimize: true, + sourceMap: shouldUseSourceMap, + }, + 'sass-loader' + ), + // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. + }, + // Adds support for CSS Modules, but using SASS + // using the extension .module.scss or .module.sass + { + test: sassModuleRegex, + loader: getStyleLoaders( + { + importLoaders: 2, + minimize: true, + sourceMap: shouldUseSourceMap, + modules: true, + getLocalIdent: getCSSModuleLocalIdent, + }, + 'sass-loader' ), // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, @@ -378,8 +412,16 @@ module.exports = { // Minify the code. new UglifyJsPlugin({ uglifyOptions: { - ecma: 8, + parse: { + // we want uglify-js to parse ecma 8 code. However, we don't want it + // to apply any minfication 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 @@ -391,6 +433,7 @@ module.exports = { safari10: true, }, 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 @@ -413,7 +456,7 @@ module.exports = { // having to parse `index.html`. new ManifestPlugin({ fileName: 'asset-manifest.json', - publicPath: publicPath + publicPath: publicPath, }), // Generate a service worker script that will precache, and keep up to date, // the HTML & assets that are part of the Webpack build. diff --git a/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json b/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json index e4d3bec84f2..92bd84171f8 100644 --- a/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json +++ b/packages/react-scripts/fixtures/kitchensink/.template.dependencies.json @@ -3,9 +3,11 @@ "@babel/plugin-transform-modules-commonjs": "7.0.0-beta.36", "@babel/polyfill": "7.0.0-beta.36", "@babel/register": "7.0.0-beta.36", + "bootstrap": "4.1.0", "chai": "3.5.0", "jsdom": "9.8.3", "mocha": "3.2.0", + "node-sass": "4.8.3", "normalize.css": "7.0.0", "prop-types": "15.5.6", "test-integrity": "1.0.0" diff --git a/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js b/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js index bba497c49f3..dc10c9a1b08 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js @@ -24,10 +24,49 @@ describe('Integration', () => { it('css modules inclusion', async () => { const doc = await initDOM('css-modules-inclusion'); + expect( + doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '') + ).to.match(/.+style_cssModulesInclusion__.+\{background:.+;color:.+}/); + expect( + doc.getElementsByTagName('style')[1].textContent.replace(/\s/g, '') + ).to.match( + /.+assets_cssModulesIndexInclusion__.+\{background:.+;color:.+}/ + ); + }); + + it('scss inclusion', async () => { + const doc = await initDOM('scss-inclusion'); + + expect( + doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '') + ).to.match(/#feature-scss-inclusion\{background:.+;color:.+}/); + }); + + it('scss modules inclusion', async () => { + const doc = await initDOM('scss-modules-inclusion'); + + expect( + doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '') + ).to.match( + /.+scss-styles_scssModulesInclusion.+\{background:.+;color:.+}/ + ); + }); + + it('sass inclusion', async () => { + const doc = await initDOM('sass-inclusion'); + + expect( + doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '') + ).to.match(/#feature-sass-inclusion\{background:.+;color:.+}/); + }); + + it('sass modules inclusion', async () => { + const doc = await initDOM('sass-modules-inclusion'); + expect( doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '') ).to.match( - /.+__style-module___cssModulesInclusion+\{background:.+;color:.+}/ + /.+sass-styles_sassModulesInclusion.+\{background:.+;color:.+}/ ); }); diff --git a/packages/react-scripts/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index c45ef2a38e8..f5e3d5911b1 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -86,6 +86,26 @@ class App extends Component { this.setFeature(f.default) ); break; + case 'scss-inclusion': + import('./features/webpack/ScssInclusion').then(f => + this.setFeature(f.default) + ); + break; + case 'scss-modules-inclusion': + import('./features/webpack/ScssModulesInclusion').then(f => + this.setFeature(f.default) + ); + break; + case 'sass-inclusion': + import('./features/webpack/SassInclusion').then(f => + this.setFeature(f.default) + ); + break; + case 'sass-modules-inclusion': + import('./features/webpack/SassModulesInclusion').then(f => + this.setFeature(f.default) + ); + break; case 'custom-interpolation': import('./features/syntax/CustomInterpolation').then(f => this.setFeature(f.default) diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js index 0f96ae161fb..05339e3fae1 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js @@ -7,7 +7,13 @@ import React from 'react'; import styles from './assets/style.module.css'; +import indexStyles from './assets/index.module.css'; export default () => ( -

CSS Modules are working!

+
+

CSS Modules are working!

+

+ CSS Modules with index are working! +

+
); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassInclusion.js new file mode 100644 index 00000000000..c15f175dbfe --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassInclusion.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import './assets/sass-styles.sass'; + +export default () =>

We love useless text.

; diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassInclusion.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassInclusion.test.js new file mode 100644 index 00000000000..c58080ab5b1 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassInclusion.test.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import SassInclusion from './SassInclusion'; + +describe('sass inclusion', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassModulesInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassModulesInclusion.js new file mode 100644 index 00000000000..dd832eaea32 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassModulesInclusion.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import styles from './assets/sass-styles.module.sass'; + +export default () => ( +

SASS Modules are working!

+); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassModulesInclusion.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassModulesInclusion.test.js new file mode 100644 index 00000000000..373330a5fac --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/SassModulesInclusion.test.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import SassModulesInclusion from './SassModulesInclusion'; + +describe('sass modules inclusion', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssInclusion.js new file mode 100644 index 00000000000..b363f430ea8 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssInclusion.js @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import './assets/scss-styles.scss'; + +export default () =>

We love useless text.

; diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssInclusion.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssInclusion.test.js new file mode 100644 index 00000000000..81d49588cac --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssInclusion.test.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import ScssInclusion from './ScssInclusion'; + +describe('scss inclusion', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.js new file mode 100644 index 00000000000..ef0e2bf4c3c --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import styles from './assets/scss-styles.module.scss'; + +export default () => ( +

SCSS Modules are working!

+); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.test.js new file mode 100644 index 00000000000..5de52839666 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.test.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import ScssModulesInclusion from './ScssModulesInclusion'; + +describe('scss modules inclusion', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/index.module.css b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/index.module.css new file mode 100644 index 00000000000..f1c6d7d19be --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/index.module.css @@ -0,0 +1,4 @@ +.cssModulesIndexInclusion { + background: darkblue; + color: lightblue; +} diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/sass-styles.module.sass b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/sass-styles.module.sass new file mode 100644 index 00000000000..09773b05d85 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/sass-styles.module.sass @@ -0,0 +1,3 @@ +.sassModulesInclusion + background: darkblue + color: lightblue diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/sass-styles.sass b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/sass-styles.sass new file mode 100644 index 00000000000..28935fe49b1 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/sass-styles.sass @@ -0,0 +1,3 @@ +#feature-sass-inclusion + background: ghostwhite + color: crimson diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/scss-styles.module.scss b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/scss-styles.module.scss new file mode 100644 index 00000000000..5beb80ebabe --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/scss-styles.module.scss @@ -0,0 +1,4 @@ +.scssModulesInclusion { + background: darkblue; + color: lightblue; +} diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/scss-styles.scss b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/scss-styles.scss new file mode 100644 index 00000000000..8aac77fbf6e --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/scss-styles.scss @@ -0,0 +1,6 @@ +@import "~bootstrap/scss/bootstrap"; + +#feature-scss-inclusion { + background: ghostwhite; + color: crimson; +} diff --git a/packages/react-scripts/fixtures/monorepos/packages/comp1/index.js b/packages/react-scripts/fixtures/monorepos/packages/comp1/index.js index f3cb7964952..104989fe35a 100644 --- a/packages/react-scripts/fixtures/monorepos/packages/comp1/index.js +++ b/packages/react-scripts/fixtures/monorepos/packages/comp1/index.js @@ -1,5 +1,21 @@ import React from 'react'; -const Comp1 = () =>
Comp1
; +class Comp1 extends React.Component { + static parts = { + greeting: 'hello', + region: 'world', + }; + + render() { + const { greeting, region } = Comp1.parts; + + return ( +
+ Comp1 + {greeting} {region} +
+ ); + } +} export default Comp1; diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index fc25259a8de..f5fa5f01eaa 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -22,12 +22,12 @@ "react-scripts": "./bin/react-scripts.js" }, "dependencies": { - "@babel/core": "7.0.0-beta.42", - "@babel/runtime": "7.0.0-beta.42", + "@babel/core": "7.0.0-beta.46", + "@babel/runtime": "7.0.0-beta.46", "autoprefixer": "7.2.5", "babel-core": "7.0.0-bridge.0", "babel-eslint": "8.2.2", - "babel-jest": "22.1.0", + "babel-jest": "22.4.1", "babel-loader": "8.0.0-beta.0", "babel-plugin-named-asset-import": "^0.1.0", "babel-preset-react-app": "^3.1.1", @@ -42,7 +42,7 @@ "eslint-plugin-flowtype": "2.41.0", "eslint-plugin-import": "2.8.0", "eslint-plugin-jsx-a11y": "6.0.3", - "eslint-plugin-react": "7.5.1", + "eslint-plugin-react": "7.7.0", "extract-text-webpack-plugin": "3.0.2", "file-loader": "1.1.6", "fs-extra": "5.0.0", @@ -50,13 +50,16 @@ "graphql-tag": "2.6.1", "html-webpack-plugin": "2.30.1", "identity-obj-proxy": "3.0.0", - "jest": "22.1.2", + "jest": "22.4.1", + "loader-utils": "^1.1.0", "object-assign": "4.1.1", "postcss-flexbugs-fixes": "3.2.0", "postcss-loader": "2.0.10", "promise": "8.0.1", "raf": "3.4.0", "react-dev-utils": "^5.0.0", + "resolve": "1.6.0", + "sass-loader": "7.0.1", "style-loader": "0.19.1", "svgr": "1.8.1", "sw-precache-webpack-plugin": "0.11.4", @@ -73,7 +76,7 @@ "react-dom": "^16.0.0" }, "optionalDependencies": { - "fsevents": "1.1.3" + "fsevents": "1.2.0" }, "browserslist": { "development": [ diff --git a/packages/react-scripts/scripts/test.js b/packages/react-scripts/scripts/test.js index 7d2acf77ea2..b77db920625 100644 --- a/packages/react-scripts/scripts/test.js +++ b/packages/react-scripts/scripts/test.js @@ -31,7 +31,7 @@ if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') { // @remove-on-eject-end const jest = require('jest'); -const argv = process.argv.slice(2); +let argv = process.argv.slice(2); // Watch unless on CI, in coverage mode, or explicitly running all tests if ( @@ -57,5 +57,59 @@ argv.push( ) ) ); + +// This is a very dirty workaround for https://github.com/facebook/jest/issues/5913. +// We're trying to resolve the environment ourselves because Jest does it incorrectly. +// TODO: remove this (and the `resolve` dependency) as soon as it's fixed in Jest. +const resolve = require('resolve'); +function resolveJestDefaultEnvironment(name) { + const jestDir = path.dirname( + resolve.sync('jest', { + basedir: __dirname, + }) + ); + const jestCLIDir = path.dirname( + resolve.sync('jest-cli', { + basedir: jestDir, + }) + ); + const jestConfigDir = path.dirname( + resolve.sync('jest-config', { + basedir: jestCLIDir, + }) + ); + return resolve.sync(name, { + basedir: jestConfigDir, + }); +} +let cleanArgv = []; +let env = 'node'; +let next; +do { + next = argv.shift(); + if (next === '--env') { + env = argv.shift(); + } else if (next.indexOf('--env=') === 0) { + env = next.substring('--env='.length); + } else { + cleanArgv.push(next); + } +} while (argv.length > 0); +argv = cleanArgv; +let resolvedEnv; +try { + resolvedEnv = resolveJestDefaultEnvironment(`jest-environment-${env}`); +} catch (e) { + // ignore +} +if (!resolvedEnv) { + try { + resolvedEnv = resolveJestDefaultEnvironment(env); + } catch (e) { + // ignore + } +} +const testEnvironment = resolvedEnv || env; +argv.push('--env', testEnvironment); // @remove-on-eject-end jest.run(argv); diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index 800c0d0d775..c30d9031817 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -87,6 +87,7 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Serving Apps with Client-Side Routing](#serving-apps-with-client-side-routing) - [Service Worker Considerations](#service-worker-considerations) - [Building for Relative Paths](#building-for-relative-paths) + - [Customizing Environment Variables for Arbitrary Build Environments](#customizing-environment-variables-for-arbitrary-build-environments) - [Azure](#azure) - [Firebase](#firebase) - [GitHub Pages](#github-pages) @@ -509,7 +510,7 @@ class Button extends Component { } ``` -**This is not required for React** but many people find this feature convenient. You can read about the benefits of this approach [here](https://medium.com/seek-ui-engineering/block-element-modifying-your-javascript-components-d7f99fcab52b). However you should be aware that this makes your code less portable to other build tools and environments than Webpack. +**This is not required for React** but many people find this feature convenient. You can read about the benefits of this approach [here](https://medium.com/seek-blog/block-element-modifying-your-javascript-components-d7f99fcab52b). However you should be aware that this makes your code less portable to other build tools and environments than Webpack. In development, expressing dependencies this way allows your styles to be reloaded on the fly as you edit them. In production, all CSS files will be concatenated into a single minified `.css` file in the build output. @@ -518,23 +519,23 @@ If you are concerned about using Webpack-specific semantics, you can put all you +