├── .npmignore ├── fixtures └── kitchensink │ ├── src │ ├── features │ │ ├── webpack │ │ │ ├── assets │ │ │ │ ├── aFileWithExt.unknown │ │ │ │ ├── aFileWithoutExt │ │ │ │ ├── abstract.json │ │ │ │ ├── svg.css │ │ │ │ ├── sass-styles.sass │ │ │ │ ├── sass-styles.module.sass │ │ │ │ ├── index.module.sass │ │ │ │ ├── style.module.css │ │ │ │ ├── index.module.css │ │ │ │ ├── index.module.scss │ │ │ │ ├── scss-styles.module.scss │ │ │ │ ├── tiniest-cat.jpg │ │ │ │ ├── style.css │ │ │ │ ├── scss-styles.scss │ │ │ │ └── logo.svg │ │ │ ├── SvgInCss.js │ │ │ ├── SvgInCss.test.js │ │ │ ├── CssInclusion.js │ │ │ ├── SassInclusion.js │ │ │ ├── ScssInclusion.js │ │ │ ├── SvgComponent.js │ │ │ ├── SvgInclusion.js │ │ │ ├── JsonInclusion.js │ │ │ ├── ImageInclusion.js │ │ │ ├── CssInclusion.test.js │ │ │ ├── SvgInclusion.test.js │ │ │ ├── JsonInclusion.test.js │ │ │ ├── SassInclusion.test.js │ │ │ ├── ScssInclusion.test.js │ │ │ ├── ImageInclusion.test.js │ │ │ ├── NoExtInclusion.test.js │ │ │ ├── LinkedModules.js │ │ │ ├── NoExtInclusion.js │ │ │ ├── CssModulesInclusion.test.js │ │ │ ├── UnknownExtInclusion.test.js │ │ │ ├── SassModulesInclusion.test.js │ │ │ ├── ScssModulesInclusion.test.js │ │ │ ├── SvgComponent.test.js │ │ │ ├── UnknownExtInclusion.js │ │ │ ├── CssModulesInclusion.js │ │ │ ├── SassModulesInclusion.js │ │ │ ├── ScssModulesInclusion.js │ │ │ └── LinkedModules.test.js │ │ ├── env │ │ │ ├── PublicUrl.js │ │ │ ├── ShellEnvVariables.js │ │ │ ├── PublicUrl.test.js │ │ │ ├── FileEnvVariables.test.js │ │ │ ├── ShellEnvVariables.test.js │ │ │ ├── ExpandEnvVariables.test.js │ │ │ ├── NodePath.test.js │ │ │ ├── ExpandEnvVariables.js │ │ │ ├── FileEnvVariables.js │ │ │ └── NodePath.js │ │ └── syntax │ │ │ ├── AsyncAwait.test.js │ │ │ ├── Generators.test.js │ │ │ ├── ArraySpread.test.js │ │ │ ├── ObjectSpread.test.js │ │ │ ├── RestAndDefault.test.js │ │ │ ├── RestParameters.test.js │ │ │ ├── ClassProperties.test.js │ │ │ ├── DefaultParameters.test.js │ │ │ ├── ArrayDestructuring.test.js │ │ │ ├── ComputedProperties.test.js │ │ │ ├── Promises.test.js │ │ │ ├── CustomInterpolation.test.js │ │ │ ├── ObjectDestructuring.test.js │ │ │ ├── DestructuringAndAwait.test.js │ │ │ ├── TemplateInterpolation.test.js │ │ │ ├── ClassProperties.js │ │ │ ├── ArrayDestructuring.js │ │ │ ├── ArraySpread.js │ │ │ ├── Generators.js │ │ │ ├── Promises.js │ │ │ ├── DefaultParameters.js │ │ │ ├── TemplateInterpolation.js │ │ │ ├── RestAndDefault.js │ │ │ ├── RestParameters.js │ │ │ ├── DestructuringAndAwait.js │ │ │ ├── ComputedProperties.js │ │ │ ├── ObjectSpread.js │ │ │ ├── ObjectDestructuring.js │ │ │ ├── AsyncAwait.js │ │ │ └── CustomInterpolation.js │ ├── subfolder │ │ └── lol.js │ ├── absoluteLoad.js │ ├── index.js │ └── App.js │ ├── .env.development │ ├── .env.production │ ├── .env.local │ ├── .flowconfig │ ├── public │ ├── favicon.ico │ └── index.html │ ├── jest.transform.js │ ├── jest.integration.config.js │ ├── gitignore │ ├── .template.dependencies.json │ ├── .env │ ├── integration │ ├── initDOM.js │ ├── env.test.js │ ├── syntax.test.js │ └── webpack.test.js │ └── README.md ├── sponsor-logo.png ├── template ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── src │ ├── App.test.js │ ├── index.css │ ├── App.css │ ├── App.js │ ├── index.js │ ├── logo.svg │ ├── index.ssr.js │ └── serviceWorker.js ├── gitignore └── README.md ├── template-typescript ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── src │ ├── App.test.tsx │ ├── index.css │ ├── App.css │ ├── App.tsx │ ├── index.tsx │ ├── logo.svg │ ├── index.ssr.tsx │ └── serviceWorker.ts ├── gitignore └── README.md ├── .gitignore ├── config ├── jest │ ├── babelTransform.js │ ├── cssTransform.js │ └── fileTransform.js ├── webpack.ssr.config.js ├── webpackDevServer.ssr.config.js ├── env.js ├── webpackDevServer.config.js └── paths.js ├── scripts ├── serve.js ├── test.js ├── start.js ├── utils │ ├── createJestConfig.js │ ├── verifyPackageTree.js │ └── verifyTypeScriptSetup.js └── build.js ├── LICENSE ├── lib └── react-app.d.ts ├── .travis.yml ├── bin └── react-scripts.js ├── package.json └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | /fixtures 2 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/aFileWithExt.unknown: -------------------------------------------------------------------------------- 1 | Whoooo, spooky! 2 | -------------------------------------------------------------------------------- /sponsor-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joernb/react-scripts-with-ssr/HEAD/sponsor-logo.png -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/aFileWithoutExt: -------------------------------------------------------------------------------- 1 | This is just a file without an extension 2 | -------------------------------------------------------------------------------- /fixtures/kitchensink/.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_X = x-from-development-env 2 | REACT_APP_DEVELOPMENT = development 3 | -------------------------------------------------------------------------------- /fixtures/kitchensink/.env.production: -------------------------------------------------------------------------------- 1 | REACT_APP_X = x-from-production-env 2 | REACT_APP_PRODUCTION = production 3 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/abstract.json: -------------------------------------------------------------------------------- 1 | { 2 | "abstract": "This is an abstract." 3 | } 4 | -------------------------------------------------------------------------------- /template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joernb/react-scripts-with-ssr/HEAD/template/public/favicon.ico -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/svg.css: -------------------------------------------------------------------------------- 1 | #feature-svg-in-css { 2 | background-image: url("./logo.svg"); 3 | } 4 | -------------------------------------------------------------------------------- /fixtures/kitchensink/.env.local: -------------------------------------------------------------------------------- 1 | REACT_APP_X = x-from-original-local-env 2 | REACT_APP_ORIGINAL_2 = override-from-original-local-env-2 3 | -------------------------------------------------------------------------------- /fixtures/kitchensink/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | /node_modules/fbjs/.* 3 | 4 | [include] 5 | 6 | [libs] 7 | 8 | [options] 9 | -------------------------------------------------------------------------------- /fixtures/kitchensink/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joernb/react-scripts-with-ssr/HEAD/fixtures/kitchensink/public/favicon.ico -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/sass-styles.sass: -------------------------------------------------------------------------------- 1 | #feature-sass-inclusion 2 | background: ghostwhite 3 | color: crimson 4 | -------------------------------------------------------------------------------- /template-typescript/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joernb/react-scripts-with-ssr/HEAD/template-typescript/public/favicon.ico -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/sass-styles.module.sass: -------------------------------------------------------------------------------- 1 | .sassModulesInclusion 2 | background: darkblue 3 | color: lightblue 4 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/index.module.sass: -------------------------------------------------------------------------------- 1 | .sassModulesIndexInclusion 2 | background: darkblue 3 | color: lightblue 4 | 5 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/style.module.css: -------------------------------------------------------------------------------- 1 | .cssModulesInclusion { 2 | background: darkblue; 3 | color: lightblue; 4 | } 5 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/index.module.css: -------------------------------------------------------------------------------- 1 | .cssModulesIndexInclusion { 2 | background: darkblue; 3 | color: lightblue; 4 | } 5 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/index.module.scss: -------------------------------------------------------------------------------- 1 | .scssModulesIndexInclusion { 2 | background: darkblue; 3 | color: lightblue; 4 | } 5 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/scss-styles.module.scss: -------------------------------------------------------------------------------- 1 | .scssModulesInclusion { 2 | background: darkblue; 3 | color: lightblue; 4 | } 5 | -------------------------------------------------------------------------------- /fixtures/kitchensink/jest.transform.js: -------------------------------------------------------------------------------- 1 | const babelOptions = { presets: ['react-app'] }; 2 | 3 | module.exports = require('babel-jest').createTransformer(babelOptions); 4 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SvgInCss.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './assets/svg.css'; 3 | 4 | export default () =>
; 5 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/tiniest-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joernb/react-scripts-with-ssr/HEAD/fixtures/kitchensink/src/features/webpack/assets/tiniest-cat.jpg -------------------------------------------------------------------------------- /fixtures/kitchensink/jest.integration.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | testMatch: ['**/integration/*.test.js'], 4 | transform: { '^.+\\.js$': './jest.transform.js' }, 5 | }; 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | build 5 | .DS_Store 6 | *.tgz 7 | my-app* 8 | template/src/__tests__/__snapshots__/ 9 | lerna-debug.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | /.changelog 14 | .npm/ 15 | -------------------------------------------------------------------------------- /fixtures/kitchensink/gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | npm-debug.log 16 | -------------------------------------------------------------------------------- /fixtures/kitchensink/.template.dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "bootstrap": "4.1.1", 4 | "jest": "23.6.0", 5 | "node-sass": "4.8.3", 6 | "normalize.css": "7.0.0", 7 | "prop-types": "15.5.6", 8 | "test-integrity": "1.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /template/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/subfolder/lol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | module.exports = function() { 9 | return `haha`; 10 | }; 11 | -------------------------------------------------------------------------------- /template-typescript/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Ensure CSS inclusion doesn't regress 3 | * https://github.com/facebook/create-react-app/issues/2677 4 | */ 5 | @import '~normalize.css/normalize.css'; 6 | 7 | #feature-css-inclusion { 8 | background: palevioletred; 9 | color: papayawhip; 10 | } 11 | -------------------------------------------------------------------------------- /fixtures/kitchensink/.env: -------------------------------------------------------------------------------- 1 | REACT_APP_X = x-from-original-env 2 | REACT_APP_ORIGINAL_1 = from-original-env-1 3 | REACT_APP_ORIGINAL_2 = from-original-env-2 4 | REACT_APP_BASIC = basic 5 | REACT_APP_BASIC_EXPAND = ${REACT_APP_BASIC} 6 | REACT_APP_BASIC_EXPAND_SIMPLE = $REACT_APP_BASIC 7 | REACT_APP_EXPAND_EXISTING = $REACT_APP_SHELL_ENV_MESSAGE 8 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SvgInCss.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import SvgInCss from './SvgInCss'; 4 | 5 | describe('svg in css', () => { 6 | it('renders without crashing', () => { 7 | const div = document.createElement('div'); 8 | ReactDOM.render(, div); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /fixtures/kitchensink/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/absoluteLoad.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | export default () => [ 9 | { id: 1, name: '1' }, 10 | { id: 2, name: '2' }, 11 | { id: 3, name: '3' }, 12 | { id: 4, name: '4' }, 13 | ]; 14 | -------------------------------------------------------------------------------- /template/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/PublicUrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | 10 | export default () => ( 11 | {process.env.PUBLIC_URL}. 12 | ); 13 | -------------------------------------------------------------------------------- /template-typescript/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import App from './App'; 11 | 12 | ReactDOM.render(, document.getElementById('root')); 13 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/CssInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import './assets/style.css'; 10 | 11 | export default () =>

We love useless text.

; 12 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SassInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import './assets/sass-styles.sass'; 10 | 11 | export default () =>

We love useless text.

; 12 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/ScssInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import './assets/scss-styles.scss'; 10 | 11 | export default () =>

We love useless text.

; 12 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SvgComponent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import { ReactComponent as Logo } from './assets/logo.svg'; 10 | 11 | export default () => ; 12 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SvgInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import logo from './assets/logo.svg'; 10 | 11 | export default () => logo; 12 | -------------------------------------------------------------------------------- /template/gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/JsonInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import { abstract } from './assets/abstract.json'; 10 | 11 | export default () => {abstract}; 12 | -------------------------------------------------------------------------------- /template-typescript/gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/ShellEnvVariables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | 10 | export default () => ( 11 | 12 | {process.env.REACT_APP_SHELL_ENV_MESSAGE}. 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /template/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/scss-styles.scss: -------------------------------------------------------------------------------- 1 | @import "~bootstrap/scss/functions"; 2 | @import "~bootstrap/scss/variables"; 3 | @import "~bootstrap/scss/mixins"; 4 | 5 | @import "~bootstrap/scss/reboot"; 6 | @import "~bootstrap/scss/type"; 7 | @import "~bootstrap/scss/images"; 8 | @import "~bootstrap/scss/code"; 9 | @import "~bootstrap/scss/grid"; 10 | 11 | #feature-scss-inclusion { 12 | background: ghostwhite; 13 | color: crimson; 14 | } 15 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/ImageInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import tiniestCat from './assets/tiniest-cat.jpg'; 10 | 11 | export default () => ( 12 | tiniest cat 13 | ); 14 | -------------------------------------------------------------------------------- /template-typescript/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | // @remove-file-on-eject 2 | /** 3 | * Copyright (c) 2014-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 'use strict'; 9 | 10 | const babelJest = require('babel-jest'); 11 | 12 | module.exports = babelJest.createTransformer({ 13 | presets: [require.resolve('babel-preset-react-app')], 14 | babelrc: false, 15 | configFile: false, 16 | }); 17 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/PublicUrl.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import PublicUrl from './PublicUrl'; 11 | 12 | describe('PUBLIC_URL', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/CssInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import CssInclusion from './CssInclusion'; 11 | 12 | describe('css inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SvgInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import SvgInclusion from './SvgInclusion'; 11 | 12 | describe('svg inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/JsonInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import JsonInclusion from './JsonInclusion'; 11 | 12 | describe('JSON inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SassInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import SassInclusion from './SassInclusion'; 11 | 12 | describe('sass inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/ScssInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ScssInclusion from './ScssInclusion'; 11 | 12 | describe('scss inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/ImageInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ImageInclusion from './ImageInclusion'; 11 | 12 | describe('image inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/FileEnvVariables.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import FileEnvVariables from './FileEnvVariables'; 11 | 12 | describe('.env variables', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/NoExtInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import NoExtInclusion from './NoExtInclusion'; 11 | 12 | describe('no ext inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/LinkedModules.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import './assets/style.css'; 10 | import { test, version } from 'test-integrity'; 11 | 12 | export default () => { 13 | const v = version(); 14 | if (!test() || v !== '2.0.0') { 15 | throw new Error('Functionality test did not pass.'); 16 | } 17 | return

{v}

; 18 | }; 19 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/ShellEnvVariables.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ShellEnvVariables from './ShellEnvVariables'; 11 | 12 | describe('shell env variables', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/ExpandEnvVariables.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ExpandEnvVariables from './ExpandEnvVariables'; 11 | 12 | describe('expand .env variables', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/NoExtInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import aFileWithoutExt from './assets/aFileWithoutExt'; 10 | 11 | const text = aFileWithoutExt.includes('base64') 12 | ? atob(aFileWithoutExt.split('base64,')[1]).trim() 13 | : aFileWithoutExt; 14 | 15 | export default () => ( 16 | 17 | aFileWithoutExt 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/CssModulesInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import CssModulesInclusion from './CssModulesInclusion'; 11 | 12 | describe('css modules inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/UnknownExtInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import UnknownExtInclusion from './UnknownExtInclusion'; 11 | 12 | describe('unknown ext inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /template/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SassModulesInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import SassModulesInclusion from './SassModulesInclusion'; 11 | 12 | describe('sass modules inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ScssModulesInclusion from './ScssModulesInclusion'; 11 | 12 | describe('scss modules inclusion', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/NodePath.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import NodePath from './NodePath'; 11 | 12 | describe('NODE_PATH', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /template-typescript/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SvgComponent.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import SvgComponent from './SvgComponent'; 11 | 12 | describe('svg component', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | ReactDOM.render(, div); 16 | expect(div.textContent).toBe('logo.svg'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/AsyncAwait.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import AsyncAwait from './AsyncAwait'; 11 | 12 | describe('async/await', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/Generators.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import Generators from './Generators'; 11 | 12 | describe('generators', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ArraySpread.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ArraySpread from './ArraySpread'; 11 | 12 | describe('array spread', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/UnknownExtInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import aFileWithExtUnknown from './assets/aFileWithExt.unknown'; 10 | 11 | const text = aFileWithExtUnknown.includes('base64') 12 | ? atob(aFileWithExtUnknown.split('base64,')[1]).trim() 13 | : aFileWithExtUnknown; 14 | 15 | export default () => ( 16 | 17 | aFileWithExtUnknown 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2014-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | // This is a custom Jest transformer turning style imports into empty objects. 12 | // http://facebook.github.io/jest/docs/en/webpack.html 13 | 14 | module.exports = { 15 | process() { 16 | return 'module.exports = {};'; 17 | }, 18 | getCacheKey() { 19 | // The output is always the same. 20 | return 'cssTransform'; 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ObjectSpread.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ObjectSpread from './ObjectSpread'; 11 | 12 | describe('object spread', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/RestAndDefault.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import RestAndDefault from './RestAndDefault'; 11 | 12 | describe('rest + default', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/RestParameters.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import RestParameters from './RestParameters'; 11 | 12 | describe('rest parameters', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/CssModulesInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import styles from './assets/style.module.css'; 10 | import indexStyles from './assets/index.module.css'; 11 | 12 | export default () => ( 13 |
14 |

CSS Modules are working!

15 |

16 | CSS Modules with index are working! 17 |

18 |
19 | ); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ClassProperties.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ClassProperties from './ClassProperties'; 11 | 12 | describe('class properties', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/DefaultParameters.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import DefaultParameters from './DefaultParameters'; 11 | 12 | describe('default parameters', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/SassModulesInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import styles from './assets/sass-styles.module.sass'; 10 | import indexStyles from './assets/index.module.sass'; 11 | 12 | export default () => ( 13 |
14 |

SASS Modules are working!

15 |

16 | SASS Modules with index are working! 17 |

18 |
19 | ); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/ScssModulesInclusion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import styles from './assets/scss-styles.module.scss'; 10 | import indexStyles from './assets/index.module.scss'; 11 | 12 | export default () => ( 13 |
14 |

SCSS Modules are working!

15 |

16 | SCSS Modules with index are working! 17 |

18 |
19 | ); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ArrayDestructuring.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ArrayDestructuring from './ArrayDestructuring'; 11 | 12 | describe('array destructuring', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ComputedProperties.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ComputedProperties from './ComputedProperties'; 11 | 12 | describe('computed properties', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/Promises.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | 11 | describe('promises', () => { 12 | it('renders without crashing', () => { 13 | const div = document.createElement('div'); 14 | return import('./Promises').then(({ default: Promises }) => { 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/CustomInterpolation.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import CustomInterpolation from './CustomInterpolation'; 11 | 12 | describe('custom interpolation', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ObjectDestructuring.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import ObjectDestructuring from './ObjectDestructuring'; 11 | 12 | describe('object destructuring', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/DestructuringAndAwait.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import DestructuringAndAwait from './DestructuringAndAwait'; 11 | 12 | describe('destructuring and await', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/TemplateInterpolation.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import TemplateInterpolation from './TemplateInterpolation'; 11 | 12 | describe('template interpolation', () => { 13 | it('renders without crashing', () => { 14 | const div = document.createElement('div'); 15 | return new Promise(resolve => { 16 | ReactDOM.render(, div); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /template/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | 4 | class App extends Component { 5 | render() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.js and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /template/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import './App.css'; 6 | import * as serviceWorker from './serviceWorker'; 7 | 8 | // Use clientEnv to access environment variables from the server. 9 | 10 | // Get the server URL from the base tag if you need it. 11 | const baseHref = document.getElementsByTagName("base")[0].href; 12 | 13 | ReactDOM.render(, document.getElementById('root')); 14 | 15 | // If you want your app to work offline and load faster, you can change 16 | // unregister() to register() below. Note this comes with some pitfalls. 17 | // Learn more about service workers: http://bit.ly/CRA-PWA 18 | serviceWorker.unregister(); 19 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/ExpandEnvVariables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | 10 | export default () => ( 11 | 12 | {process.env.REACT_APP_BASIC} 13 | {process.env.REACT_APP_BASIC_EXPAND} 14 | 15 | {process.env.REACT_APP_BASIC_EXPAND_SIMPLE} 16 | 17 | 18 | {process.env.REACT_APP_EXPAND_EXISTING} 19 | 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/LinkedModules.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | import ReactDOM from 'react-dom'; 10 | import { test, version } from 'test-integrity'; 11 | import LinkedModules from './LinkedModules'; 12 | 13 | describe('linked modules', () => { 14 | it('has integrity', () => { 15 | expect(test()); 16 | expect(version() === '2.0.0'); 17 | }); 18 | 19 | it('renders without crashing', () => { 20 | const div = document.createElement('div'); 21 | ReactDOM.render(, div); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /template-typescript/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | 4 | class App extends Component { 5 | render() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.tsx and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/FileEnvVariables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React from 'react'; 9 | 10 | export default () => ( 11 | 12 | 13 | {process.env.REACT_APP_ORIGINAL_1} 14 | 15 | 16 | {process.env.REACT_APP_ORIGINAL_2} 17 | 18 | 19 | {process.env.REACT_APP_DEVELOPMENT} 20 | {process.env.REACT_APP_PRODUCTION} 21 | 22 | {process.env.REACT_APP_X} 23 | 24 | ); 25 | -------------------------------------------------------------------------------- /template-typescript/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import './App.css'; 6 | import * as serviceWorker from './serviceWorker'; 7 | 8 | // Declare global variable clientEnv 9 | declare const clientEnv: NodeJS.ProcessEnv; 10 | // Use clientEnv to access environment variables from the server. 11 | 12 | // Get the server URL from the base tag if you need it. 13 | const baseHref = document.getElementsByTagName("base")[0].href; 14 | 15 | ReactDOM.render(, document.getElementById('root')); 16 | 17 | // If you want your app to work offline and load faster, you can change 18 | // unregister() to register() below. Note this comes with some pitfalls. 19 | // Learn more about service workers: http://bit.ly/CRA-PWA 20 | serviceWorker.unregister(); 21 | -------------------------------------------------------------------------------- /scripts/serve.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const paths = require('../config/paths'); 4 | 5 | // read environment variables 6 | process.env.BABEL_ENV = 'production'; 7 | process.env.NODE_ENV = 'production'; 8 | require('../config/env'); 9 | 10 | const PORT = parseInt(process.env.PORT) || 3000; 11 | const PUBLIC_PATH = process.env.PUBLIC_PATH || '/'; 12 | 13 | // include compiled server-side request handler 14 | const ssrModuleFile = path.resolve(paths.appBuild, "ssr.js"); 15 | const ssrModule = require(ssrModuleFile); 16 | 17 | // start express server 18 | console.log(`Serving from '${process.cwd()}' with public path '${PUBLIC_PATH}'`); 19 | const app = express(); 20 | app.use(PUBLIC_PATH, ssrModule.default); 21 | app.listen(PORT, () => console.log(`Open http://localhost:${PORT}${PUBLIC_PATH} for testing!`)); 22 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ClassProperties.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | export default class extends Component { 12 | static propTypes = { 13 | onReady: PropTypes.func.isRequired, 14 | }; 15 | 16 | users = [ 17 | { id: 1, name: '1' }, 18 | { id: 2, name: '2' }, 19 | { id: 3, name: '3' }, 20 | { id: 4, name: '4' }, 21 | ]; 22 | 23 | componentDidMount() { 24 | this.props.onReady(); 25 | } 26 | 27 | render() { 28 | return ( 29 |
30 | {this.users.map(user => ( 31 |
{user.name}
32 | ))} 33 |
34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/env/NodePath.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | import load from 'absoluteLoad'; 11 | 12 | export default class extends Component { 13 | static propTypes = { 14 | onReady: PropTypes.func.isRequired, 15 | }; 16 | 17 | constructor(props) { 18 | super(props); 19 | this.state = { users: [] }; 20 | } 21 | 22 | async componentDidMount() { 23 | const users = load(); 24 | this.setState({ users }); 25 | } 26 | 27 | componentDidUpdate() { 28 | this.props.onReady(); 29 | } 30 | 31 | render() { 32 | return ( 33 |
34 | {this.state.users.map(user => ( 35 |
{user.name}
36 | ))} 37 |
38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ArrayDestructuring.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load() { 12 | return [[1, '1'], [2, '2'], [3, '3'], [4, '4']]; 13 | } 14 | 15 | export default class extends Component { 16 | static propTypes = { 17 | onReady: PropTypes.func.isRequired, 18 | }; 19 | 20 | constructor(props) { 21 | super(props); 22 | this.state = { users: [] }; 23 | } 24 | 25 | async componentDidMount() { 26 | const users = load(); 27 | this.setState({ users }); 28 | } 29 | 30 | componentDidUpdate() { 31 | this.props.onReady(); 32 | } 33 | 34 | render() { 35 | return ( 36 |
37 | {this.state.users.map(user => { 38 | const [id, name] = user; 39 | return
{name}
; 40 | })} 41 |
42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2014-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | const path = require('path'); 12 | 13 | // This is a custom Jest transformer turning file imports into filenames. 14 | // http://facebook.github.io/jest/docs/en/webpack.html 15 | 16 | module.exports = { 17 | process(src, filename) { 18 | const assetFilename = JSON.stringify(path.basename(filename)); 19 | 20 | if (filename.match(/\.svg$/)) { 21 | return `module.exports = { 22 | __esModule: true, 23 | default: ${assetFilename}, 24 | ReactComponent: (props) => ({ 25 | $$typeof: Symbol.for('react.element'), 26 | type: 'svg', 27 | ref: null, 28 | key: null, 29 | props: Object.assign({}, props, { 30 | children: ${assetFilename} 31 | }) 32 | }), 33 | };`; 34 | } 35 | 36 | return `module.exports = ${assetFilename};`; 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ArraySpread.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load(users) { 12 | return [ 13 | { id: 1, name: '1' }, 14 | { id: 2, name: '2' }, 15 | { id: 3, name: '3' }, 16 | ...users, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load([{ id: 42, name: '42' }]); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
{user.name}
44 | ))} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/Generators.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function* load(limit) { 12 | let i = 1; 13 | while (i <= limit) { 14 | yield { id: i, name: i }; 15 | i++; 16 | } 17 | } 18 | 19 | export default class extends Component { 20 | static propTypes = { 21 | onReady: PropTypes.func.isRequired, 22 | }; 23 | 24 | constructor(props) { 25 | super(props); 26 | this.state = { users: [] }; 27 | } 28 | 29 | componentDidMount() { 30 | const users = []; 31 | for (let user of load(4)) { 32 | users.push(user); 33 | } 34 | this.setState({ users }); 35 | } 36 | 37 | componentDidUpdate() { 38 | this.props.onReady(); 39 | } 40 | 41 | render() { 42 | return ( 43 |
44 | {this.state.users.map(user => ( 45 |
{user.name}
46 | ))} 47 |
48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/Promises.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load() { 12 | return Promise.resolve([ 13 | { id: 1, name: '1' }, 14 | { id: 2, name: '2' }, 15 | { id: 3, name: '3' }, 16 | { id: 4, name: '4' }, 17 | ]); 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | componentDidMount() { 31 | load().then(users => { 32 | this.setState({ users }); 33 | }); 34 | } 35 | 36 | componentDidUpdate() { 37 | this.props.onReady(); 38 | } 39 | 40 | render() { 41 | return ( 42 |
43 | {this.state.users.map(user => ( 44 |
{user.name}
45 | ))} 46 |
47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/DefaultParameters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load(id = 0) { 12 | return [ 13 | { id: id + 1, name: '1' }, 14 | { id: id + 2, name: '2' }, 15 | { id: id + 3, name: '3' }, 16 | { id: id + 4, name: '4' }, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load(); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
{user.name}
44 | ))} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/TemplateInterpolation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load(name) { 12 | return [ 13 | { id: 1, name: `${name}1` }, 14 | { id: 2, name: `${name}2` }, 15 | { id: 3, name: `${name}3` }, 16 | { id: 4, name: `${name}4` }, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load('user_'); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
{user.name}
44 | ))} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/RestAndDefault.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load({ id, ...rest } = { id: 0, user: { id: 42, name: '42' } }) { 12 | return [ 13 | { id: id + 1, name: '1' }, 14 | { id: id + 2, name: '2' }, 15 | { id: id + 3, name: '3' }, 16 | rest.user, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load(); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
{user.name}
44 | ))} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/RestParameters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load({ id = 0, ...rest }) { 12 | return [ 13 | { id: id + 1, name: '1' }, 14 | { id: id + 2, name: '2' }, 15 | { id: id + 3, name: '3' }, 16 | rest.user, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load({ id: 0, user: { id: 42, name: '42' } }); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
{user.name}
44 | ))} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/DestructuringAndAwait.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | async function load() { 12 | return { 13 | users: [ 14 | { id: 1, name: '1' }, 15 | { id: 2, name: '2' }, 16 | { id: 3, name: '3' }, 17 | { id: 4, name: '4' }, 18 | ], 19 | }; 20 | } 21 | 22 | export default class extends Component { 23 | static propTypes = { 24 | onReady: PropTypes.func.isRequired, 25 | }; 26 | 27 | constructor(props) { 28 | super(props); 29 | this.state = { users: [] }; 30 | } 31 | 32 | async componentDidMount() { 33 | const { users } = await load(); 34 | this.setState({ users }); 35 | } 36 | 37 | componentDidUpdate() { 38 | this.props.onReady(); 39 | } 40 | 41 | render() { 42 | return ( 43 |
44 | {this.state.users.map(user => ( 45 |
{user.name}
46 | ))} 47 |
48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ComputedProperties.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load(prefix) { 12 | return [ 13 | { id: 1, [`${prefix} name`]: '1' }, 14 | { id: 2, [`${prefix} name`]: '2' }, 15 | { id: 3, [`${prefix} name`]: '3' }, 16 | { id: 4, [`${prefix} name`]: '4' }, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load('user_'); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
{user.user_name}
44 | ))} 45 |
46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ObjectSpread.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load(baseUser) { 12 | return [ 13 | { id: 1, name: '1', ...baseUser }, 14 | { id: 2, name: '2', ...baseUser }, 15 | { id: 3, name: '3', ...baseUser }, 16 | { id: 4, name: '4', ...baseUser }, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load({ age: 42 }); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => ( 43 |
44 | {user.name}: {user.age} 45 |
46 | ))} 47 |
48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/ObjectDestructuring.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | function load() { 12 | return [ 13 | { id: 1, name: '1' }, 14 | { id: 2, name: '2' }, 15 | { id: 3, name: '3' }, 16 | { id: 4, name: '4' }, 17 | ]; 18 | } 19 | 20 | export default class extends Component { 21 | static propTypes = { 22 | onReady: PropTypes.func.isRequired, 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { users: [] }; 28 | } 29 | 30 | async componentDidMount() { 31 | const users = load(); 32 | this.setState({ users }); 33 | } 34 | 35 | componentDidUpdate() { 36 | this.props.onReady(); 37 | } 38 | 39 | render() { 40 | return ( 41 |
42 | {this.state.users.map(user => { 43 | const { id, ...rest } = user; 44 | // eslint-disable-next-line no-unused-vars 45 | const [{ name, ...innerRest }] = [{ ...rest }]; 46 | return
{name}
; 47 | })} 48 |
49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/AsyncAwait.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | async function load() { 12 | return [ 13 | { id: 1, name: '1' }, 14 | { id: 2, name: '2' }, 15 | { id: 3, name: '3' }, 16 | { id: 4, name: '4' }, 17 | ]; 18 | } 19 | 20 | /* eslint-disable */ 21 | // Regression test for https://github.com/facebook/create-react-app/issues/3055 22 | const x = async ( 23 | /* prettier-ignore */ 24 | y: void 25 | ) => { 26 | const z = await y; 27 | }; 28 | /* eslint-enable */ 29 | 30 | export default class extends Component { 31 | static propTypes = { 32 | onReady: PropTypes.func.isRequired, 33 | }; 34 | 35 | constructor(props) { 36 | super(props); 37 | this.state = { users: [] }; 38 | } 39 | 40 | async componentDidMount() { 41 | const users = await load(); 42 | this.setState({ users }); 43 | } 44 | 45 | componentDidUpdate() { 46 | this.props.onReady(); 47 | } 48 | 49 | render() { 50 | return ( 51 |
52 | {this.state.users.map(user => ( 53 |
{user.name}
54 | ))} 55 |
56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/react-app.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | declare namespace NodeJS { 6 | interface ProcessEnv { 7 | NODE_ENV: 'development' | 'production' | 'test' 8 | PUBLIC_URL: string 9 | } 10 | } 11 | 12 | declare module '*.bmp' { 13 | const src: string; 14 | export default src; 15 | } 16 | 17 | declare module '*.gif' { 18 | const src: string; 19 | export default src; 20 | } 21 | 22 | declare module '*.jpg' { 23 | const src: string; 24 | export default src; 25 | } 26 | 27 | declare module '*.jpeg' { 28 | const src: string; 29 | export default src; 30 | } 31 | 32 | declare module '*.png' { 33 | const src: string; 34 | export default src; 35 | } 36 | 37 | declare module '*.webp' { 38 | const src: string; 39 | export default src; 40 | } 41 | 42 | declare module '*.svg' { 43 | import * as React from 'react'; 44 | 45 | export const ReactComponent: React.SFC>; 46 | 47 | const src: string; 48 | export default src; 49 | } 50 | 51 | declare module '*.module.css' { 52 | const classes: { [key: string]: string }; 53 | export default classes; 54 | } 55 | 56 | declare module '*.module.scss' { 57 | const classes: { [key: string]: string }; 58 | export default classes; 59 | } 60 | 61 | declare module '*.module.sass' { 62 | const classes: { [key: string]: string }; 63 | export default classes; 64 | } 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | deploy: 3 | provider: npm 4 | email: 5 | secure: pZqLYn4+Ld0wimBAAZ7cyhlksLFGhfpsU7voTa8ssARKkqB31B4CFz4DQx475t/KM3kKv8m6UIfA5qByC4T+klLg7ytTQzOvtBklbgKowMlWEntQotafoAi6LW9Zy1bQFkzHaGO16WCE8ERqV6TlolWEuS2ADaEgOojiYDDKNalNwe+/Y6TxRcrxZ+m96NER3pdEFFVihr4O0m0kgQLRBiF/rcs9vCUTMrQppcuRwOt3KvLjwd9uOV6aRCJphLQnxqYUb1ZFPMjPXCUCPA+DBnhjdDU84J3q2r+g9zQcNwnXAWlM957HsVt6px0O911WLrLAo1cDxKGceTw4U4Yv9Ds7MfkwLznPiAjqDZFi/pyIfbmzW+uyp//Vd5zuujP5k1MoBO1NnFl5f32/sTJs3eDVoWUdz3NIMAevYKTQAmQ8WMToBdxqsb7sYGsLHLmiwgEAI9PhuFMRxsAT3ysAVrV6/YIqbrQ396/XurKE73Ra8xmgsMoSVqj9fZg4BXS8Qefnr76QxOpRKyAUsdpO5RC9157DMoKvinya3uKWLackVRSEgZjyw59jwQKCFeLlt3bJMHmpqwgXlPLBcgeooK3v0fNDs9MdYXH+Dfi0ekNpyNrzl8/bZcMIj42g6j/8JeUTBRy9COXgcXXIJHMejaV1XJckBbmxjWOaJ9OO9Ok= 6 | api_key: 7 | secure: lYprDc8NJlS91vQlvK7jlsdUI7APCTSTQdx/ogDokTOX36iiaNRDAe3iT7gW/bix4yTadvqx+sFRQJKJ9Pb4WzGp5HPf/88DST3N/RIW278Q0gvKcQ8LRPkeHxXlrz00qA+DdAxZhQuujbxI2eL1BtZ7b01/Fc+lK4W6WsKgotFOWT5KHnVDCjOs0tVkehtt0WLaCD6j0ntinVTHMzyqUNxPHh7nm6Xlna9zP6Cbw1TbE05g6asbJLPzhFB5b7KXjv2ggLGN4UgdPUb1Fvm/XB7S895UgrqgF+WJd5eM4sFy1E1z4qkzCP9YTJo//A80ZdJcLPF6g8gbY0GG6Q8uBvNY5GAQtSSCfooc5Zjrx+aTUgYL7ZHwxPKiY+XJiK50TxPXypGmm4x4gzxD3UiyDVB9WQckE7dSYxZYDmfrZJLYPAy0r++F97Lb4NoWGsHNE63DcwBlKVH/3ymXgy0XBsEENrpDcbHRNp0NxPldUnsygKrxl3TvDhBA5QpN4Hseq5+jqXXwaQH+i53l5UvRy4MGgavQQi4gVXOrIvzA1UN0Qs7ExU4eVwC9AuH+Wy//hbC7U8RYSA9k7EMKxNfFZ/V5J7FslRpnlL2Y/AWeqIDShJYwDMpDZf/DWPIn1LGM7/Ka5bBt4lsK82lRsVWHOgVuZULKwzWXHMeVCpb6uq8= 8 | on: 9 | tags: true 10 | repo: joernb/react-scripts-with-ssr 11 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/syntax/CustomInterpolation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import React, { Component } from 'react'; 9 | import PropTypes from 'prop-types'; 10 | 11 | const styled = ([style]) => 12 | style 13 | .trim() 14 | .split(/\s*;\s*/) 15 | .map(rule => rule.split(/\s*:\s*/)) 16 | .reduce((rules, rule) => ({ ...rules, [rule[0]]: rule[1] }), {}); 17 | 18 | function load() { 19 | return [ 20 | { id: 1, name: '1' }, 21 | { id: 2, name: '2' }, 22 | { id: 3, name: '3' }, 23 | { id: 4, name: '4' }, 24 | ]; 25 | } 26 | 27 | export default class extends Component { 28 | static propTypes = { 29 | onReady: PropTypes.func.isRequired, 30 | }; 31 | 32 | constructor(props) { 33 | super(props); 34 | this.state = { users: [] }; 35 | } 36 | 37 | async componentDidMount() { 38 | const users = load(); 39 | this.setState({ users }); 40 | } 41 | 42 | componentDidUpdate() { 43 | this.props.onReady(); 44 | } 45 | 46 | render() { 47 | const veryInlineStyle = styled` 48 | background: palevioletred; 49 | color: papayawhip; 50 | `; 51 | 52 | return ( 53 |
54 | {this.state.users.map(user => ( 55 |
56 | {user.name} 57 |
58 | ))} 59 |
60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /template/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | React App 27 | 28 | 29 | 30 | 31 |
%ROOT%
32 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /template-typescript/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | React App 27 | 28 | 29 | 30 | 31 |
%ROOT%
32 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /template-typescript/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | -------------------------------------------------------------------------------- /bin/react-scripts.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | // Makes the script crash on unhandled rejections instead of silently 12 | // ignoring them. In the future, promise rejections that are not handled will 13 | // terminate the Node.js process with a non-zero exit code. 14 | process.on('unhandledRejection', err => { 15 | throw err; 16 | }); 17 | 18 | const spawn = require('react-dev-utils/crossSpawn'); 19 | const args = process.argv.slice(2); 20 | 21 | const scriptIndex = args.findIndex( 22 | x => x === 'build' || x === 'eject' || x === 'start' || x === 'test' 23 | ); 24 | const script = scriptIndex === -1 ? args[0] : args[scriptIndex]; 25 | const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : []; 26 | 27 | switch (script) { 28 | case 'build': 29 | case 'eject': 30 | case 'start': 31 | case 'test': 32 | case 'serve': { 33 | const result = spawn.sync( 34 | 'node', 35 | nodeArgs 36 | .concat(require.resolve('../scripts/' + script)) 37 | .concat(args.slice(scriptIndex + 1)), 38 | { stdio: 'inherit' } 39 | ); 40 | if (result.signal) { 41 | if (result.signal === 'SIGKILL') { 42 | console.log( 43 | 'The build failed because the process exited too early. ' + 44 | 'This probably means the system ran out of memory or someone called ' + 45 | '`kill -9` on the process.' 46 | ); 47 | } else if (result.signal === 'SIGTERM') { 48 | console.log( 49 | 'The build failed because the process exited too early. ' + 50 | 'Someone might have called `kill` or `killall`, or the system could ' + 51 | 'be shutting down.' 52 | ); 53 | } 54 | process.exit(1); 55 | } 56 | process.exit(result.status); 57 | break; 58 | } 59 | default: 60 | console.log('Unknown script "' + script + '".'); 61 | console.log('Perhaps you need to update react-scripts?'); 62 | console.log( 63 | 'See: https://facebook.github.io/create-react-app/docs/updating-to-new-releases' 64 | ); 65 | break; 66 | } 67 | -------------------------------------------------------------------------------- /fixtures/kitchensink/integration/initDOM.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const fs = require('fs'); 9 | const http = require('http'); 10 | const jsdom = require('jsdom/lib/old-api.js'); 11 | const path = require('path'); 12 | 13 | let getMarkup; 14 | export let resourceLoader; 15 | 16 | if (process.env.E2E_FILE) { 17 | const file = path.isAbsolute(process.env.E2E_FILE) 18 | ? process.env.E2E_FILE 19 | : path.join(process.cwd(), process.env.E2E_FILE); 20 | 21 | const markup = fs.readFileSync(file, 'utf8'); 22 | getMarkup = () => markup; 23 | 24 | const pathPrefix = process.env.PUBLIC_URL.replace(/^https?:\/\/[^/]+\/?/, ''); 25 | 26 | resourceLoader = (resource, callback) => 27 | callback( 28 | null, 29 | fs.readFileSync( 30 | path.join( 31 | path.dirname(file), 32 | resource.url.pathname.replace(pathPrefix, '') 33 | ), 34 | 'utf8' 35 | ) 36 | ); 37 | } else if (process.env.E2E_URL) { 38 | getMarkup = () => 39 | new Promise(resolve => { 40 | http.get(process.env.E2E_URL, res => { 41 | let rawData = ''; 42 | res.on('data', chunk => (rawData += chunk)); 43 | res.on('end', () => resolve(rawData)); 44 | }); 45 | }); 46 | 47 | resourceLoader = (resource, callback) => resource.defaultFetch(callback); 48 | } else { 49 | it.only('can run jsdom (at least one of "E2E_FILE" or "E2E_URL" environment variables must be provided)', () => { 50 | expect( 51 | new Error("This isn't the error you are looking for.") 52 | ).toBeUndefined(); 53 | }); 54 | } 55 | 56 | export default feature => 57 | new Promise(async resolve => { 58 | const markup = await getMarkup(); 59 | const host = process.env.E2E_URL || 'http://www.example.org/spa:3000'; 60 | const doc = jsdom.jsdom(markup, { 61 | created: (_, win) => 62 | win.addEventListener('ReactFeatureDidMount', () => resolve(doc), true), 63 | deferClose: true, 64 | pretendToBeVisual: true, 65 | resourceLoader, 66 | url: `${host}#${feature}`, 67 | virtualConsole: jsdom.createVirtualConsole().sendTo(console), 68 | }); 69 | 70 | doc.close(); 71 | }); 72 | -------------------------------------------------------------------------------- /template/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /template-typescript/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /fixtures/kitchensink/README.md: -------------------------------------------------------------------------------- 1 | # Contributing to Create React App's E2E tests 2 | 3 | This is an end to end kitchensink test suite, but has multiple usages in it. 4 | 5 | ## Running the test suite 6 | 7 | Tests are automatically run by the CI tools. 8 | In order to run them locally, without having to manually install and configure everything, the `yarn e2e:docker` CLI command can be used. 9 | 10 | This is a simple script that runs a **Docker** container, where the node version, git branch to clone, test suite, and whether to run it with `yarn` or `npm` can be chosen. 11 | Simply run `yarn e2e:docker -- --help` to get additional info. 12 | 13 | If you need guidance installing **Docker**, you should follow their [official docs](https://docs.docker.com/engine/installation/). 14 | 15 | ## Writing tests 16 | 17 | Each time a new feature is added, it is advised to add at least one test covering it. 18 | 19 | Features are categorized by their scope: 20 | 21 | - _env_, all those which deal with environment variables (e.g. `NODE_PATH`) 22 | 23 | - _syntax_, all those which showcase a single EcmaScript syntax feature that is expected to be transpiled by **Babel** 24 | 25 | - _webpack_, all those which make use of webpack settings, loaders or plugins 26 | 27 | ### Using it as Unit Tests 28 | 29 | In it's most basic for this serve as a collection of unit tests on a single functionality. 30 | 31 | Unit tests are written in a `src/features/**/*.test.js` file located in the same folder as the feature they test, and usually consist of a simple `ReactDOM.render` call. 32 | 33 | These tests are run by **jest** and the environment is `test`, so that it resembles how a **Create React App** application is tested. 34 | 35 | ### Using it as Integration Tests 36 | 37 | This suite tests how the single features as before behave while development and in production. 38 | A local HTTP server is started, then every single feature is loaded, one by one, to be tested. 39 | 40 | Test are written in `integration/{env|syntax|webpack}.test.js`, depending on their scope. 41 | 42 | For every test case added there is just a little chore to do: 43 | 44 | - a `case` statement must be added in `src/App.js`, which simply perform a dynamic `import()` of the feature 45 | 46 | - add a test case in the appropriate integration test file, which calls and awaits `initDOM` with the previous `SwitchCase` string 47 | 48 | A usual flow for the test itself is something similar to: 49 | 50 | - add an `id` attribute in a target HTML tag in the feature itself 51 | 52 | - since `initDOM` returns a `Document` element, the previous `id` attribute is used to target the feature's DOM and `expect` accordingly 53 | -------------------------------------------------------------------------------- /fixtures/kitchensink/src/features/webpack/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /config/webpack.ssr.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); 6 | const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt'); 7 | const nodeExternals = require('webpack-node-externals'); 8 | const webpackConfigFactory = require('./webpack.config.js'); 9 | const paths = require('./paths'); 10 | const getClientEnvironment = require('./env'); 11 | const env = getClientEnvironment(''); 12 | 13 | // decorate original webpack config 14 | module.exports = function (webpackEnv) { 15 | const template = webpackConfigFactory(webpackEnv); 16 | // multi compiler config (client + server) 17 | return [ 18 | // ssr compiler config 19 | { 20 | ...template, 21 | name: 'ssr', 22 | target: 'node', 23 | entry: [ 24 | // ssr entry point, usually s.th. like `./src/index.ssr.tsx` with `export default (req,res) => {}` 25 | paths.appIndexSsrJs 26 | ], 27 | output: { 28 | ...template.output, 29 | filename: 'ssr.js', 30 | libraryTarget: 'commonjs2' 31 | }, 32 | optimization: { 33 | ...template.optimization, 34 | // disable chunk splitting 35 | splitChunks: {}, 36 | runtimeChunk: false 37 | }, 38 | // filter out some plugins 39 | plugins: template.plugins.filter(plugin => 40 | [ 41 | // do not generate an additional index.html for ssr 42 | HtmlWebpackPlugin, 43 | // avoid overriding process.env on the server, we will provide a customized DefinePlugin 44 | webpack.DefinePlugin 45 | ].every(pluginClass => !(plugin instanceof pluginClass)) 46 | ).concat([ 47 | // modified version of the DefinePlugin that does not override but extend process.env 48 | // this will preserve embedded env vars but also allow reading real env vars on the server 49 | new webpack.DefinePlugin( 50 | Object.keys(env.raw).reduce( 51 | (newEnv, key) => ({ 52 | ...newEnv, 53 | // this will result in s.th. like: process.env.FOO = process.env.FOO || "embedded default value" 54 | ['process.env.' + key]: 'process.env.' + key + '||' + JSON.stringify(env.raw[key]) 55 | }), 56 | {} 57 | ) 58 | ) 59 | ]), 60 | externals: [nodeExternals()] 61 | }, 62 | // client compiler config 63 | { 64 | // use original config 65 | ...template, 66 | name: 'client', 67 | output: { 68 | ...template.output, 69 | }, 70 | // filter out some plugins 71 | plugins: template.plugins.filter(plugin => 72 | [ 73 | // seems to break multicompiler dev server watch mode 74 | ForkTsCheckerWebpackPlugin, 75 | ].every(pluginClass => !(plugin instanceof pluginClass)) 76 | ) 77 | }, 78 | ]; 79 | }; 80 | -------------------------------------------------------------------------------- /config/webpackDevServer.ssr.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpackDevServerConfigFactory = require('./webpackDevServer.config.js'); 4 | const requireFromString = require('require-from-string'); 5 | const path = require('path'); 6 | const paths = require('./paths'); 7 | 8 | // decorate original webpack dev server config 9 | module.exports = function(proxy, allowedHost) { 10 | const template = webpackDevServerConfigFactory(proxy, allowedHost); 11 | 12 | return { 13 | ...template, 14 | serverSideRender: true, 15 | before(app, server) { 16 | const multiCompiler = server.middleware.context.compiler; 17 | const compiler = multiCompiler.compilers.filter(c => c.name === 'ssr')[0]; 18 | if(!compiler) { 19 | throw new Error("Webpack compiler with name 'ssr' not found."); 20 | } 21 | 22 | // stores current request handler, changes after every compilation, initially handles pending handler change 23 | let ssrHandler = (request, response, next) => { 24 | installHandler = handler => { 25 | installHandler = handler => ssrHandler = handler; 26 | ssrHandler = handler; 27 | ssrHandler(request, response, next); 28 | }; 29 | }; 30 | let installHandler = handler => ssrHandler = handler; 31 | 32 | // fetch ssr handler after every compilation 33 | multiCompiler.hooks.done.tap('webpackDevServer.ssr', multiCompilerStats => { 34 | // make errors inside hook visible 35 | try { 36 | const compilerStats = multiCompilerStats.stats.filter(stats => stats.compilation.name === 'ssr')[0]; 37 | 38 | if (compilerStats.compilation.errors.length === 0) { 39 | // fetch ssr entry point file name 40 | const filename = path.resolve(paths.appBuild, "..", "dist", "ssr.js"); 41 | // read code from in memory fs 42 | const code = compiler.outputFileSystem.readFileSync(filename).toString(); 43 | // compile code to node module 44 | const exports = requireFromString(code, filename); 45 | 46 | if (exports.devServerHandler) { 47 | // install dev server handler 48 | installHandler(exports.devServerHandler(compiler)); 49 | } else if (exports.default) { 50 | // install production handler 51 | installHandler(exports.default); 52 | } else { 53 | // no handler found 54 | throw new Error("SSR entry point does not export a handler."); 55 | } 56 | } 57 | } catch (error) { 58 | console.error(error); 59 | // install error handler 60 | installHandler((request, response, next) => { 61 | // response.send("ERROR HANDLER: " + error.toString()); 62 | next(error); 63 | }); 64 | } 65 | }); 66 | 67 | // install request handler in webpack dev server 68 | app.use((request, response, next) => ssrHandler(request, response, next)); 69 | } 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /fixtures/kitchensink/integration/env.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import initDOM from './initDOM'; 9 | 10 | describe('Integration', () => { 11 | describe('Environment variables', () => { 12 | it('file env variables', async () => { 13 | const doc = await initDOM('file-env-variables'); 14 | 15 | expect( 16 | doc.getElementById('feature-file-env-original-1').textContent 17 | ).toBe('from-original-env-1'); 18 | expect( 19 | doc.getElementById('feature-file-env-original-2').textContent 20 | ).toBe('override-from-original-local-env-2'); 21 | 22 | if (process.env.NODE_ENV === 'production') { 23 | expect(doc.getElementById('feature-file-env').textContent).toBe( 24 | 'production' 25 | ); 26 | expect(doc.getElementById('feature-file-env-x').textContent).toBe( 27 | 'x-from-production-env' 28 | ); 29 | } else { 30 | expect(doc.getElementById('feature-file-env').textContent).toBe( 31 | 'development' 32 | ); 33 | expect(doc.getElementById('feature-file-env-x').textContent).toBe( 34 | 'x-from-development-env' 35 | ); 36 | } 37 | doc.defaultView.close(); 38 | }); 39 | 40 | it('NODE_PATH', async () => { 41 | const doc = await initDOM('node-path'); 42 | 43 | expect(doc.getElementById('feature-node-path').childElementCount).toBe(4); 44 | doc.defaultView.close(); 45 | }); 46 | 47 | it('PUBLIC_URL', async () => { 48 | const doc = await initDOM('public-url'); 49 | 50 | const prefix = 51 | process.env.NODE_ENV === 'development' 52 | ? '' 53 | : 'http://www.example.org/spa'; 54 | expect(doc.getElementById('feature-public-url').textContent).toBe( 55 | `${prefix}.` 56 | ); 57 | expect( 58 | doc.querySelector('head link[rel="shortcut icon"]').getAttribute('href') 59 | ).toBe(`${prefix}/favicon.ico`); 60 | doc.defaultView.close(); 61 | }); 62 | 63 | it('shell env variables', async () => { 64 | const doc = await initDOM('shell-env-variables'); 65 | 66 | expect( 67 | doc.getElementById('feature-shell-env-variables').textContent 68 | ).toBe('fromtheshell.'); 69 | doc.defaultView.close(); 70 | }); 71 | 72 | it('expand .env variables', async () => { 73 | const doc = await initDOM('expand-env-variables'); 74 | 75 | expect(doc.getElementById('feature-expand-env-1').textContent).toBe( 76 | 'basic' 77 | ); 78 | expect(doc.getElementById('feature-expand-env-2').textContent).toBe( 79 | 'basic' 80 | ); 81 | expect(doc.getElementById('feature-expand-env-3').textContent).toBe( 82 | 'basic' 83 | ); 84 | expect( 85 | doc.getElementById('feature-expand-env-existing').textContent 86 | ).toBe('fromtheshell'); 87 | doc.defaultView.close(); 88 | }); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-scripts-with-ssr", 3 | "version": "0.6.0", 4 | "description": "Configuration and scripts for Create React App.", 5 | "repository": "joernb/react-scripts-with-ssr", 6 | "author": "Joern Buchwald", 7 | "homepage": "https://github.com/joernb/react-scripts-with-ssr#readme", 8 | "license": "MIT", 9 | "keywords": [ 10 | "react-scripts", 11 | "create-react-app", 12 | "ssr", 13 | "server-side-rendering" 14 | ], 15 | "engines": { 16 | "node": ">=6" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/joernb/react-scripts-with-ssr/issues" 20 | }, 21 | "files": [ 22 | "bin", 23 | "config", 24 | "lib", 25 | "scripts", 26 | "template", 27 | "template-typescript", 28 | "utils" 29 | ], 30 | "bin": { 31 | "react-scripts-with-ssr": "./bin/react-scripts.js" 32 | }, 33 | "types": "./lib/react-app.d.ts", 34 | "dependencies": { 35 | "@babel/core": "7.1.6", 36 | "@svgr/webpack": "2.4.1", 37 | "@types/express": "^4.16.1", 38 | "babel-core": "7.0.0-bridge.0", 39 | "babel-eslint": "9.0.0", 40 | "babel-jest": "23.6.0", 41 | "babel-loader": "8.0.4", 42 | "babel-plugin-named-asset-import": "^0.3.0", 43 | "babel-preset-react-app": "^7.0.0", 44 | "bfj": "6.1.1", 45 | "case-sensitive-paths-webpack-plugin": "2.1.2", 46 | "chalk": "2.4.1", 47 | "css-loader": "1.0.0", 48 | "dotenv": "6.0.0", 49 | "dotenv-expand": "4.2.0", 50 | "eslint": "5.6.0", 51 | "eslint-config-react-app": "^3.0.6", 52 | "eslint-loader": "2.1.1", 53 | "eslint-plugin-flowtype": "2.50.1", 54 | "eslint-plugin-import": "2.14.0", 55 | "eslint-plugin-jsx-a11y": "6.1.2", 56 | "eslint-plugin-react": "7.11.1", 57 | "express": "^4.16.4", 58 | "file-loader": "2.0.0", 59 | "fork-ts-checker-webpack-plugin-alt": "0.4.14", 60 | "fs-extra": "7.0.0", 61 | "html-webpack-plugin": "4.0.0-alpha.2", 62 | "identity-obj-proxy": "3.0.0", 63 | "jest": "23.6.0", 64 | "jest-pnp-resolver": "1.0.1", 65 | "jest-resolve": "23.6.0", 66 | "mini-css-extract-plugin": "0.4.3", 67 | "optimize-css-assets-webpack-plugin": "5.0.1", 68 | "pnp-webpack-plugin": "1.1.0", 69 | "postcss-flexbugs-fixes": "4.1.0", 70 | "postcss-loader": "3.0.0", 71 | "postcss-preset-env": "6.3.1", 72 | "postcss-safe-parser": "4.0.1", 73 | "react-app-polyfill": "^0.2.0", 74 | "react-dev-utils": "^7.0.1", 75 | "require-from-string": "^2.0.2", 76 | "resolve": "1.8.1", 77 | "sass-loader": "7.1.0", 78 | "style-loader": "0.23.0", 79 | "terser-webpack-plugin": "1.1.0", 80 | "url-loader": "1.1.1", 81 | "webpack": "4.19.1", 82 | "webpack-dev-server": "3.1.14", 83 | "webpack-manifest-plugin": "2.0.4", 84 | "webpack-node-externals": "^1.7.2", 85 | "workbox-webpack-plugin": "3.6.3" 86 | }, 87 | "devDependencies": { 88 | "react": "^16.3.2", 89 | "react-dom": "^16.3.2" 90 | }, 91 | "optionalDependencies": { 92 | "fsevents": "1.2.4" 93 | }, 94 | "browserslist": [ 95 | ">0.2%", 96 | "not dead", 97 | "not ie <= 11", 98 | "not op_mini all" 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /template/src/index.ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is supposed to export a request handler, which implements server-side rendering in a Node.js runtime 3 | * environment. 4 | * 5 | * In production, the request handler may be imported by an executable node script, which sets up an express server. 6 | * A sample script is provided in `react-scripts-with-ssr/scripts/serve.js`, which you may start with `npm run serve` 7 | * to test your production builds of the request handler. That script however is not part of the compilation. It is up 8 | * to you to implement, how the request handler is integrated in your server-side infrastructure. 9 | * 10 | * This file may also export a function called `devServerHandler`, which is supposed to return a request handler for 11 | * the development environment. That request handler is plugged into the local webpack dev server started by `npm start`. 12 | */ 13 | import React from 'react'; 14 | import { renderToNodeStream } from 'react-dom/server'; 15 | import express from 'express'; 16 | import * as fs from 'fs'; 17 | import * as path from 'path'; 18 | import App from './App'; 19 | 20 | // provide a way to emulate fs access in development mode when builds are served from in-memory 21 | let readFileSync = fs.readFileSync; 22 | 23 | const router = express.Router(); 24 | 25 | // define ssr path pattern, exclude file and hmr requests 26 | const ssrRegex = /^\/(?!static|favicon\.ico|.*hot-update\.js).*/; 27 | 28 | // do server-side rendering 29 | router.use(ssrRegex, (request, response, next) => { 30 | const template = readFileSync('build/index.html') 31 | .toString() 32 | .replace(/%BASE_HREF%/g, process.env.BASE_HREF || '') 33 | .replace(/%CLIENT_ENV%/g, JSON.stringify({ 34 | FOO: 'bar' 35 | })); 36 | 37 | const [head, tail] = template.split('%ROOT%'); 38 | const stream = renderToNodeStream(); 39 | response.type('html'); 40 | response.write(head); 41 | stream.pipe(response, { end: false }); 42 | stream.on("end", () => { 43 | response.write(tail); 44 | response.end(); 45 | }); 46 | }); 47 | 48 | // serve static files from build/ dir 49 | router.use(express.static( 50 | 'build', 51 | { 52 | // do not send index.html for '/' 53 | index: false 54 | } 55 | )); 56 | 57 | /** 58 | * Export a request handler. This can be plugged into an express instance or deployed as a serverless function. 59 | * An express router itself implements the request handler interface (composite design pattern). 60 | */ 61 | export default router; 62 | 63 | /** 64 | * Supposed to return a request handler which can be plugged into a webpack dev server during development. 65 | * This function should return a somehow altered or decorated version of the 'export default' request handler, 66 | * which handles differences between development and production environment. 67 | * @param compiler webpack compiler which compiles the ssr entry point 68 | */ 69 | export const devServerHandler = compiler => { 70 | // redirect file access to use in-memory fs of the compiler 71 | readFileSync = fileName => 72 | compiler.outputFileSystem.readFileSync( 73 | path.resolve( 74 | // handlers should expect files in build/ but the dev server writes them to dist/ 75 | fileName.replace('build', 'dist') 76 | ) 77 | ); 78 | 79 | // ignore in-memory file requests, will be handled by the webpack dev middleware 80 | const devServerRouter = express.Router(); 81 | devServerRouter.use(ssrRegex, router); 82 | return devServerRouter; 83 | }; 84 | -------------------------------------------------------------------------------- /template-typescript/src/index.ssr.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is supposed to export a request handler, which implements server-side rendering in a Node.js runtime 3 | * environment. 4 | * 5 | * In production, the request handler may be imported by an executable node script, which sets up an express server. 6 | * A sample script is provided in `react-scripts-with-ssr/scripts/serve.js`, which you may start with `npm run serve` 7 | * to test your production builds of the request handler. That script however is not part of the compilation. It is up 8 | * to you to implement, how the request handler is integrated in your server-side infrastructure. 9 | * 10 | * This file may also export a function called `devServerHandler`, which is supposed to return a request handler for 11 | * the development environment. That request handler is plugged into the local webpack dev server started by `npm start`. 12 | */ 13 | import React from 'react'; 14 | import { renderToNodeStream } from 'react-dom/server'; 15 | import express from 'express'; 16 | import * as fs from 'fs'; 17 | import * as path from 'path'; 18 | import App from './App'; 19 | 20 | // provide a way to emulate fs access in development mode when builds are served from in-memory 21 | let readFileSync: (filename: string) => Buffer = fs.readFileSync; 22 | 23 | const router = express.Router(); 24 | 25 | // define ssr path pattern, exclude file and hmr requests 26 | const ssrRegex = /^\/(?!static|favicon\.ico|.*hot-update\.js).*/; 27 | 28 | // do server-side rendering 29 | router.use(ssrRegex, (request: express.Request, response: express.Response, next: express.NextFunction) => { 30 | const template = readFileSync('build/index.html') 31 | .toString() 32 | .replace(/%BASE_HREF%/g, process.env.BASE_HREF || '') 33 | .replace(/%CLIENT_ENV%/g, JSON.stringify({ 34 | FOO: 'bar' 35 | })); 36 | 37 | const [head, tail] = template.split('%ROOT%'); 38 | const stream = renderToNodeStream(); 39 | response.type('html'); 40 | response.write(head); 41 | stream.pipe(response, { end: false }); 42 | stream.on("end", () => { 43 | response.write(tail); 44 | response.end(); 45 | }); 46 | }); 47 | 48 | // serve static files from build/ dir 49 | router.use(express.static( 50 | 'build', 51 | { 52 | // do not send index.html for '/' 53 | index: false 54 | } 55 | )); 56 | 57 | /** 58 | * Export a request handler. This can be plugged into an express instance or deployed as a serverless function. 59 | * An express router itself implements the request handler interface (composite design pattern). 60 | */ 61 | export default router; 62 | 63 | /** 64 | * Supposed to return a request handler which can be plugged into a webpack dev server during development. 65 | * This function should return a somehow altered or decorated version of the 'export default' request handler, 66 | * which handles differences between development and production environment. 67 | * @param compiler webpack compiler which compiles the ssr entry point 68 | */ 69 | export const devServerHandler = (compiler: any) => { 70 | // redirect file access to use in-memory fs of the compiler 71 | readFileSync = fileName => 72 | compiler.outputFileSystem.readFileSync( 73 | path.resolve( 74 | // handlers should expect files in build/ but the dev server writes them to dist/ 75 | fileName.replace('build', 'dist') 76 | ) 77 | ); 78 | 79 | // ignore in-memory file requests, will be handled by the webpack dev middleware 80 | const devServerRouter = express.Router(); 81 | devServerRouter.use(ssrRegex, router); 82 | return devServerRouter; 83 | }; 84 | -------------------------------------------------------------------------------- /config/env.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | const fs = require('fs'); 12 | const path = require('path'); 13 | const paths = require('./paths'); 14 | 15 | // Make sure that including paths.js after env.js will read .env variables. 16 | delete require.cache[require.resolve('./paths')]; 17 | 18 | const NODE_ENV = process.env.NODE_ENV; 19 | if (!NODE_ENV) { 20 | throw new Error( 21 | 'The NODE_ENV environment variable is required but was not specified.' 22 | ); 23 | } 24 | 25 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use 26 | var dotenvFiles = [ 27 | `${paths.dotenv}.${NODE_ENV}.local`, 28 | `${paths.dotenv}.${NODE_ENV}`, 29 | // Don't include `.env.local` for `test` environment 30 | // since normally you expect tests to produce the same 31 | // results for everyone 32 | NODE_ENV !== 'test' && `${paths.dotenv}.local`, 33 | paths.dotenv, 34 | ].filter(Boolean); 35 | 36 | // Load environment variables from .env* files. Suppress warnings using silent 37 | // if this file is missing. dotenv will never modify any environment variables 38 | // that have already been set. Variable expansion is supported in .env files. 39 | // https://github.com/motdotla/dotenv 40 | // https://github.com/motdotla/dotenv-expand 41 | dotenvFiles.forEach(dotenvFile => { 42 | if (fs.existsSync(dotenvFile)) { 43 | require('dotenv-expand')( 44 | require('dotenv').config({ 45 | path: dotenvFile, 46 | }) 47 | ); 48 | } 49 | }); 50 | 51 | // We support resolving modules according to `NODE_PATH`. 52 | // This lets you use absolute paths in imports inside large monorepos: 53 | // https://github.com/facebook/create-react-app/issues/253. 54 | // It works similar to `NODE_PATH` in Node itself: 55 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders 56 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. 57 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. 58 | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 59 | // We also resolve them to make sure all tools using them work consistently. 60 | const appDirectory = fs.realpathSync(process.cwd()); 61 | process.env.NODE_PATH = (process.env.NODE_PATH || '') 62 | .split(path.delimiter) 63 | .filter(folder => folder && !path.isAbsolute(folder)) 64 | .map(folder => path.resolve(appDirectory, folder)) 65 | .join(path.delimiter); 66 | 67 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 68 | // injected into the application via DefinePlugin in Webpack configuration. 69 | const REACT_APP = /^REACT_APP_/i; 70 | 71 | function getClientEnvironment(publicUrl) { 72 | const raw = Object.keys(process.env) 73 | .filter(key => REACT_APP.test(key)) 74 | .reduce( 75 | (env, key) => { 76 | env[key] = process.env[key]; 77 | return env; 78 | }, 79 | { 80 | // Useful for determining whether we’re running in production mode. 81 | // Most importantly, it switches React into the correct mode. 82 | NODE_ENV: process.env.NODE_ENV || 'development', 83 | // Useful for resolving the correct path to static assets in `public`. 84 | // For example, . 85 | // This should only be used as an escape hatch. Normally you would put 86 | // images into the `src` and `import` them in code to get their paths. 87 | PUBLIC_URL: publicUrl, 88 | } 89 | ); 90 | // Stringify all values so we can feed into Webpack DefinePlugin 91 | const stringified = { 92 | 'process.env': Object.keys(raw).reduce((env, key) => { 93 | env[key] = JSON.stringify(raw[key]); 94 | return env; 95 | }, {}), 96 | }; 97 | 98 | return { raw, stringified }; 99 | } 100 | 101 | module.exports = getClientEnvironment; 102 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | // Do this as the first thing so that any code reading it knows the right env. 12 | process.env.BABEL_ENV = 'test'; 13 | process.env.NODE_ENV = 'test'; 14 | process.env.PUBLIC_URL = ''; 15 | 16 | // Makes the script crash on unhandled rejections instead of silently 17 | // ignoring them. In the future, promise rejections that are not handled will 18 | // terminate the Node.js process with a non-zero exit code. 19 | process.on('unhandledRejection', err => { 20 | throw err; 21 | }); 22 | 23 | // Ensure environment variables are read. 24 | require('../config/env'); 25 | // @remove-on-eject-begin 26 | // Do the preflight check (only happens before eject). 27 | const verifyPackageTree = require('./utils/verifyPackageTree'); 28 | if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') { 29 | verifyPackageTree(); 30 | } 31 | const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup'); 32 | verifyTypeScriptSetup(); 33 | // @remove-on-eject-end 34 | 35 | const jest = require('jest'); 36 | const execSync = require('child_process').execSync; 37 | let argv = process.argv.slice(2); 38 | 39 | function isInGitRepository() { 40 | try { 41 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 42 | return true; 43 | } catch (e) { 44 | return false; 45 | } 46 | } 47 | 48 | function isInMercurialRepository() { 49 | try { 50 | execSync('hg --cwd . root', { stdio: 'ignore' }); 51 | return true; 52 | } catch (e) { 53 | return false; 54 | } 55 | } 56 | 57 | // Watch unless on CI, in coverage mode, or explicitly running all tests 58 | if ( 59 | !process.env.CI && 60 | argv.indexOf('--coverage') === -1 && 61 | argv.indexOf('--watchAll') === -1 62 | ) { 63 | // https://github.com/facebook/create-react-app/issues/5210 64 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 65 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 66 | } 67 | 68 | // @remove-on-eject-begin 69 | // This is not necessary after eject because we embed config into package.json. 70 | const createJestConfig = require('./utils/createJestConfig'); 71 | const path = require('path'); 72 | const paths = require('../config/paths'); 73 | argv.push( 74 | '--config', 75 | JSON.stringify( 76 | createJestConfig( 77 | relativePath => path.resolve(__dirname, '..', relativePath), 78 | path.resolve(paths.appSrc, '..'), 79 | false 80 | ) 81 | ) 82 | ); 83 | 84 | // This is a very dirty workaround for https://github.com/facebook/jest/issues/5913. 85 | // We're trying to resolve the environment ourselves because Jest does it incorrectly. 86 | // TODO: remove this as soon as it's fixed in Jest. 87 | const resolve = require('resolve'); 88 | function resolveJestDefaultEnvironment(name) { 89 | const jestDir = path.dirname( 90 | resolve.sync('jest', { 91 | basedir: __dirname, 92 | }) 93 | ); 94 | const jestCLIDir = path.dirname( 95 | resolve.sync('jest-cli', { 96 | basedir: jestDir, 97 | }) 98 | ); 99 | const jestConfigDir = path.dirname( 100 | resolve.sync('jest-config', { 101 | basedir: jestCLIDir, 102 | }) 103 | ); 104 | return resolve.sync(name, { 105 | basedir: jestConfigDir, 106 | }); 107 | } 108 | let cleanArgv = []; 109 | let env = 'jsdom'; 110 | let next; 111 | do { 112 | next = argv.shift(); 113 | if (next === '--env') { 114 | env = argv.shift(); 115 | } else if (next.indexOf('--env=') === 0) { 116 | env = next.substring('--env='.length); 117 | } else { 118 | cleanArgv.push(next); 119 | } 120 | } while (argv.length > 0); 121 | argv = cleanArgv; 122 | let resolvedEnv; 123 | try { 124 | resolvedEnv = resolveJestDefaultEnvironment(`jest-environment-${env}`); 125 | } catch (e) { 126 | // ignore 127 | } 128 | if (!resolvedEnv) { 129 | try { 130 | resolvedEnv = resolveJestDefaultEnvironment(env); 131 | } catch (e) { 132 | // ignore 133 | } 134 | } 135 | const testEnvironment = resolvedEnv || env; 136 | argv.push('--env', testEnvironment); 137 | // @remove-on-eject-end 138 | jest.run(argv); 139 | -------------------------------------------------------------------------------- /fixtures/kitchensink/integration/syntax.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import initDOM from './initDOM'; 9 | 10 | describe('Integration', () => { 11 | describe('Language syntax', () => { 12 | it('array destructuring', async () => { 13 | const doc = await initDOM('array-destructuring'); 14 | 15 | expect( 16 | doc.getElementById('feature-array-destructuring').childElementCount 17 | ).toBe(4); 18 | doc.defaultView.close(); 19 | }); 20 | 21 | it('array spread', async () => { 22 | const doc = await initDOM('array-spread'); 23 | 24 | expect(doc.getElementById('feature-array-spread').childElementCount).toBe( 25 | 4 26 | ); 27 | doc.defaultView.close(); 28 | }); 29 | 30 | it('async/await', async () => { 31 | const doc = await initDOM('async-await'); 32 | 33 | expect(doc.getElementById('feature-async-await').childElementCount).toBe( 34 | 4 35 | ); 36 | doc.defaultView.close(); 37 | }); 38 | 39 | it('class properties', async () => { 40 | const doc = await initDOM('class-properties'); 41 | 42 | expect( 43 | doc.getElementById('feature-class-properties').childElementCount 44 | ).toBe(4); 45 | doc.defaultView.close(); 46 | }); 47 | 48 | it('computed properties', async () => { 49 | const doc = await initDOM('computed-properties'); 50 | 51 | expect( 52 | doc.getElementById('feature-computed-properties').childElementCount 53 | ).toBe(4); 54 | doc.defaultView.close(); 55 | }); 56 | 57 | it('custom interpolation', async () => { 58 | const doc = await initDOM('custom-interpolation'); 59 | 60 | expect( 61 | doc.getElementById('feature-custom-interpolation').childElementCount 62 | ).toBe(4); 63 | doc.defaultView.close(); 64 | }); 65 | 66 | it('default parameters', async () => { 67 | const doc = await initDOM('default-parameters'); 68 | 69 | expect( 70 | doc.getElementById('feature-default-parameters').childElementCount 71 | ).toBe(4); 72 | doc.defaultView.close(); 73 | }); 74 | 75 | it('destructuring and await', async () => { 76 | const doc = await initDOM('destructuring-and-await'); 77 | 78 | expect( 79 | doc.getElementById('feature-destructuring-and-await').childElementCount 80 | ).toBe(4); 81 | doc.defaultView.close(); 82 | }); 83 | 84 | it('generators', async () => { 85 | const doc = await initDOM('generators'); 86 | 87 | expect(doc.getElementById('feature-generators').childElementCount).toBe( 88 | 4 89 | ); 90 | doc.defaultView.close(); 91 | }); 92 | 93 | it('object destructuring', async () => { 94 | const doc = await initDOM('object-destructuring'); 95 | 96 | expect( 97 | doc.getElementById('feature-object-destructuring').childElementCount 98 | ).toBe(4); 99 | doc.defaultView.close(); 100 | }); 101 | 102 | it('object spread', async () => { 103 | const doc = await initDOM('object-spread'); 104 | 105 | expect( 106 | doc.getElementById('feature-object-spread').childElementCount 107 | ).toBe(4); 108 | doc.defaultView.close(); 109 | }); 110 | 111 | it('promises', async () => { 112 | const doc = await initDOM('promises'); 113 | 114 | expect(doc.getElementById('feature-promises').childElementCount).toBe(4); 115 | doc.defaultView.close(); 116 | }); 117 | 118 | it('rest + default', async () => { 119 | const doc = await initDOM('rest-and-default'); 120 | 121 | expect( 122 | doc.getElementById('feature-rest-and-default').childElementCount 123 | ).toBe(4); 124 | doc.defaultView.close(); 125 | }); 126 | 127 | it('rest parameters', async () => { 128 | const doc = await initDOM('rest-parameters'); 129 | 130 | expect( 131 | doc.getElementById('feature-rest-parameters').childElementCount 132 | ).toBe(4); 133 | doc.defaultView.close(); 134 | }); 135 | 136 | it('template interpolation', async () => { 137 | const doc = await initDOM('template-interpolation'); 138 | 139 | expect( 140 | doc.getElementById('feature-template-interpolation').childElementCount 141 | ).toBe(4); 142 | doc.defaultView.close(); 143 | }); 144 | }); 145 | }); 146 | -------------------------------------------------------------------------------- /scripts/start.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | // Do this as the first thing so that any code reading it knows the right env. 12 | process.env.BABEL_ENV = 'development'; 13 | process.env.NODE_ENV = 'development'; 14 | 15 | // Makes the script crash on unhandled rejections instead of silently 16 | // ignoring them. In the future, promise rejections that are not handled will 17 | // terminate the Node.js process with a non-zero exit code. 18 | process.on('unhandledRejection', err => { 19 | throw err; 20 | }); 21 | 22 | // Ensure environment variables are read. 23 | require('../config/env'); 24 | // @remove-on-eject-begin 25 | // Do the preflight check (only happens before eject). 26 | const verifyPackageTree = require('./utils/verifyPackageTree'); 27 | if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') { 28 | verifyPackageTree(); 29 | } 30 | const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup'); 31 | verifyTypeScriptSetup(); 32 | // @remove-on-eject-end 33 | 34 | const fs = require('fs'); 35 | const chalk = require('chalk'); 36 | const webpack = require('webpack'); 37 | const WebpackDevServer = require('webpack-dev-server'); 38 | const clearConsole = require('react-dev-utils/clearConsole'); 39 | const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); 40 | const { 41 | choosePort, 42 | createCompiler, 43 | prepareProxy, 44 | prepareUrls, 45 | } = require('react-dev-utils/WebpackDevServerUtils'); 46 | const openBrowser = require('react-dev-utils/openBrowser'); 47 | const paths = require('../config/paths'); 48 | const configFactory = require('../config/webpack.ssr.config'); 49 | const createDevServerConfig = require('../config/webpackDevServer.ssr.config'); 50 | 51 | const useYarn = fs.existsSync(paths.yarnLockFile); 52 | const isInteractive = process.stdout.isTTY; 53 | 54 | // Warn and crash if required files are missing 55 | if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { 56 | process.exit(1); 57 | } 58 | 59 | // Tools like Cloud9 rely on this. 60 | const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; 61 | const HOST = process.env.HOST || '0.0.0.0'; 62 | 63 | if (process.env.HOST) { 64 | console.log( 65 | chalk.cyan( 66 | `Attempting to bind to HOST environment variable: ${chalk.yellow( 67 | chalk.bold(process.env.HOST) 68 | )}` 69 | ) 70 | ); 71 | console.log( 72 | `If this was unintentional, check that you haven't mistakenly set it in your shell.` 73 | ); 74 | console.log( 75 | `Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}` 76 | ); 77 | console.log(); 78 | } 79 | 80 | // We require that you explictly set browsers and do not fall back to 81 | // browserslist defaults. 82 | const { checkBrowsers } = require('react-dev-utils/browsersHelper'); 83 | checkBrowsers(paths.appPath, isInteractive) 84 | .then(() => { 85 | // We attempt to use the default port but if it is busy, we offer the user to 86 | // run on a different port. `choosePort()` Promise resolves to the next free port. 87 | return choosePort(HOST, DEFAULT_PORT); 88 | }) 89 | .then(port => { 90 | if (port == null) { 91 | // We have not found a port. 92 | return; 93 | } 94 | const config = configFactory('development'); 95 | const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; 96 | const appName = require(paths.appPackageJson).name; 97 | const urls = prepareUrls(protocol, HOST, port); 98 | // Create a webpack compiler that is configured with custom messages. 99 | const compiler = createCompiler(webpack, config, appName, urls, useYarn); 100 | // Load proxy config 101 | const proxySetting = require(paths.appPackageJson).proxy; 102 | const proxyConfig = prepareProxy(proxySetting, paths.appPublic); 103 | // Serve webpack assets generated by the compiler over a web server. 104 | const serverConfig = createDevServerConfig( 105 | proxyConfig, 106 | urls.lanUrlForConfig 107 | ); 108 | const devServer = new WebpackDevServer(compiler, serverConfig); 109 | // Launch WebpackDevServer. 110 | devServer.listen(port, HOST, err => { 111 | if (err) { 112 | return console.log(err); 113 | } 114 | if (isInteractive) { 115 | clearConsole(); 116 | } 117 | console.log(chalk.cyan('Starting the development server...\n')); 118 | openBrowser(urls.localUrlForBrowser); 119 | }); 120 | 121 | ['SIGINT', 'SIGTERM'].forEach(function(sig) { 122 | process.on(sig, function() { 123 | devServer.close(); 124 | process.exit(); 125 | }); 126 | }); 127 | }) 128 | .catch(err => { 129 | if (err && err.message) { 130 | console.log(err.message); 131 | } 132 | process.exit(1); 133 | }); 134 | -------------------------------------------------------------------------------- /scripts/utils/createJestConfig.js: -------------------------------------------------------------------------------- 1 | // @remove-file-on-eject 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 'use strict'; 9 | 10 | const fs = require('fs'); 11 | const chalk = require('chalk'); 12 | const paths = require('../../config/paths'); 13 | 14 | module.exports = (resolve, rootDir, isEjecting) => { 15 | // Use this instead of `paths.testsSetup` to avoid putting 16 | // an absolute filename into configuration after ejecting. 17 | const setupTestsMatches = paths.testsSetup.match(/src[/\\]setupTests\.(.+)/); 18 | const setupTestsFileExtension = 19 | (setupTestsMatches && setupTestsMatches[1]) || 'js'; 20 | const setupTestsFile = fs.existsSync(paths.testsSetup) 21 | ? `/src/setupTests.${setupTestsFileExtension}` 22 | : undefined; 23 | 24 | const config = { 25 | collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'], 26 | 27 | // TODO: this breaks Yarn PnP on eject. 28 | // But we can't simply emit this because it'll be an absolute path. 29 | // The proper fix is to write jest.config.js on eject instead of a package.json key. 30 | // Then these can always stay as require.resolve()s. 31 | resolver: isEjecting 32 | ? 'jest-pnp-resolver' 33 | : require.resolve('jest-pnp-resolver'), 34 | setupFiles: [ 35 | isEjecting 36 | ? 'react-app-polyfill/jsdom' 37 | : require.resolve('react-app-polyfill/jsdom'), 38 | ], 39 | 40 | setupTestFrameworkScriptFile: setupTestsFile, 41 | testMatch: [ 42 | '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', 43 | '/src/**/?(*.)(spec|test).{js,jsx,ts,tsx}', 44 | ], 45 | testEnvironment: 'jsdom', 46 | testURL: 'http://localhost', 47 | transform: { 48 | '^.+\\.(js|jsx|ts|tsx)$': isEjecting 49 | ? '/node_modules/babel-jest' 50 | : resolve('config/jest/babelTransform.js'), 51 | '^.+\\.css$': resolve('config/jest/cssTransform.js'), 52 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': resolve( 53 | 'config/jest/fileTransform.js' 54 | ), 55 | }, 56 | transformIgnorePatterns: [ 57 | '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$', 58 | '^.+\\.module\\.(css|sass|scss)$', 59 | ], 60 | moduleNameMapper: { 61 | '^react-native$': 'react-native-web', 62 | '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy', 63 | }, 64 | moduleFileExtensions: [...paths.moduleFileExtensions, 'node'].filter( 65 | ext => !ext.includes('mjs') 66 | ), 67 | }; 68 | if (rootDir) { 69 | config.rootDir = rootDir; 70 | } 71 | const overrides = Object.assign({}, require(paths.appPackageJson).jest); 72 | const supportedKeys = [ 73 | 'collectCoverageFrom', 74 | 'coverageReporters', 75 | 'coverageThreshold', 76 | 'globalSetup', 77 | 'globalTeardown', 78 | 'resetMocks', 79 | 'resetModules', 80 | 'snapshotSerializers', 81 | 'watchPathIgnorePatterns', 82 | ]; 83 | if (overrides) { 84 | supportedKeys.forEach(key => { 85 | if (overrides.hasOwnProperty(key)) { 86 | config[key] = overrides[key]; 87 | delete overrides[key]; 88 | } 89 | }); 90 | const unsupportedKeys = Object.keys(overrides); 91 | if (unsupportedKeys.length) { 92 | const isOverridingSetupFile = 93 | unsupportedKeys.indexOf('setupTestFrameworkScriptFile') > -1; 94 | 95 | if (isOverridingSetupFile) { 96 | console.error( 97 | chalk.red( 98 | 'We detected ' + 99 | chalk.bold('setupTestFrameworkScriptFile') + 100 | ' in your package.json.\n\n' + 101 | 'Remove it from Jest configuration, and put the initialization code in ' + 102 | chalk.bold('src/setupTests.js') + 103 | '.\nThis file will be loaded automatically.\n' 104 | ) 105 | ); 106 | } else { 107 | console.error( 108 | chalk.red( 109 | '\nOut of the box, Create React App only supports overriding ' + 110 | 'these Jest options:\n\n' + 111 | supportedKeys 112 | .map(key => chalk.bold(' \u2022 ' + key)) 113 | .join('\n') + 114 | '.\n\n' + 115 | 'These options in your package.json Jest configuration ' + 116 | 'are not currently supported by Create React App:\n\n' + 117 | unsupportedKeys 118 | .map(key => chalk.bold(' \u2022 ' + key)) 119 | .join('\n') + 120 | '\n\nIf you wish to override other Jest options, you need to ' + 121 | 'eject from the default setup. You can do so by running ' + 122 | chalk.bold('npm run eject') + 123 | ' but remember that this is a one-way operation. ' + 124 | 'You may also file an issue with Create React App to discuss ' + 125 | 'supporting more options out of the box.\n' 126 | ) 127 | ); 128 | } 129 | 130 | process.exit(1); 131 | } 132 | } 133 | return config; 134 | }; 135 | -------------------------------------------------------------------------------- /fixtures/kitchensink/integration/webpack.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | import initDOM, { resourceLoader } from './initDOM'; 9 | import url from 'url'; 10 | 11 | const matchCSS = (doc, regexes) => { 12 | if (process.env.E2E_FILE) { 13 | const elements = doc.getElementsByTagName('link'); 14 | let href = ''; 15 | for (const elem of elements) { 16 | if (elem.rel === 'stylesheet') { 17 | href = elem.href; 18 | } 19 | } 20 | resourceLoader({ url: url.parse(href) }, (_, textContent) => { 21 | for (const regex of regexes) { 22 | expect(textContent).toMatch(regex); 23 | } 24 | }); 25 | } else { 26 | for (let i = 0; i < regexes.length; ++i) { 27 | expect( 28 | doc.getElementsByTagName('style')[i].textContent.replace(/\s/g, '') 29 | ).toMatch(regexes[i]); 30 | } 31 | } 32 | }; 33 | 34 | describe('Integration', () => { 35 | describe('Webpack plugins', () => { 36 | it('css inclusion', async () => { 37 | const doc = await initDOM('css-inclusion'); 38 | matchCSS(doc, [ 39 | /html\{/, 40 | /#feature-css-inclusion\{background:.+;color:.+}/, 41 | ]); 42 | doc.defaultView.close(); 43 | }); 44 | 45 | it('css modules inclusion', async () => { 46 | const doc = await initDOM('css-modules-inclusion'); 47 | matchCSS(doc, [ 48 | /.+style_cssModulesInclusion__.+\{background:.+;color:.+}/, 49 | /.+assets_cssModulesIndexInclusion__.+\{background:.+;color:.+}/, 50 | ]); 51 | doc.defaultView.close(); 52 | }); 53 | 54 | it('scss inclusion', async () => { 55 | const doc = await initDOM('scss-inclusion'); 56 | matchCSS(doc, [/#feature-scss-inclusion\{background:.+;color:.+}/]); 57 | doc.defaultView.close(); 58 | }); 59 | 60 | it('scss modules inclusion', async () => { 61 | const doc = await initDOM('scss-modules-inclusion'); 62 | matchCSS(doc, [ 63 | /.+scss-styles_scssModulesInclusion.+\{background:.+;color:.+}/, 64 | /.+assets_scssModulesIndexInclusion.+\{background:.+;color:.+}/, 65 | ]); 66 | doc.defaultView.close(); 67 | }); 68 | 69 | it('sass inclusion', async () => { 70 | const doc = await initDOM('sass-inclusion'); 71 | matchCSS(doc, [/#feature-sass-inclusion\{background:.+;color:.+}/]); 72 | doc.defaultView.close(); 73 | }); 74 | 75 | it('sass modules inclusion', async () => { 76 | const doc = await initDOM('sass-modules-inclusion'); 77 | matchCSS(doc, [ 78 | /.+sass-styles_sassModulesInclusion.+\{background:.+;color:.+}/, 79 | /.+assets_sassModulesIndexInclusion.+\{background:.+;color:.+}/, 80 | ]); 81 | doc.defaultView.close(); 82 | }); 83 | 84 | it('image inclusion', async () => { 85 | const doc = await initDOM('image-inclusion'); 86 | 87 | expect(doc.getElementById('feature-image-inclusion').src).toMatch( 88 | /^data:image\/jpeg;base64.+==$/ 89 | ); 90 | doc.defaultView.close(); 91 | }); 92 | 93 | it('no ext inclusion', async () => { 94 | const doc = await initDOM('no-ext-inclusion'); 95 | 96 | expect(doc.getElementById('feature-no-ext-inclusion').href).toMatch( 97 | /\/static\/media\/aFileWithoutExt\.[a-f0-9]{8}\.bin$/ 98 | ); 99 | doc.defaultView.close(); 100 | }); 101 | 102 | it('json inclusion', async () => { 103 | const doc = await initDOM('json-inclusion'); 104 | 105 | expect(doc.getElementById('feature-json-inclusion').textContent).toBe( 106 | 'This is an abstract.' 107 | ); 108 | doc.defaultView.close(); 109 | }); 110 | 111 | it('linked modules', async () => { 112 | const doc = await initDOM('linked-modules'); 113 | 114 | expect(doc.getElementById('feature-linked-modules').textContent).toBe( 115 | '2.0.0' 116 | ); 117 | doc.defaultView.close(); 118 | }); 119 | 120 | it('svg inclusion', async () => { 121 | const doc = await initDOM('svg-inclusion'); 122 | expect(doc.getElementById('feature-svg-inclusion').src).toMatch( 123 | /\/static\/media\/logo\..+\.svg$/ 124 | ); 125 | doc.defaultView.close(); 126 | }); 127 | 128 | it('svg component', async () => { 129 | const doc = await initDOM('svg-component'); 130 | 131 | expect(doc.getElementById('feature-svg-component').textContent).toBe(''); 132 | doc.defaultView.close(); 133 | }); 134 | 135 | it('svg in css', async () => { 136 | const doc = await initDOM('svg-in-css'); 137 | matchCSS(doc, [/\/static\/media\/logo\..+\.svg/]); 138 | doc.defaultView.close(); 139 | }); 140 | 141 | it('unknown ext inclusion', async () => { 142 | const doc = await initDOM('unknown-ext-inclusion'); 143 | 144 | expect(doc.getElementById('feature-unknown-ext-inclusion').href).toMatch( 145 | /\/static\/media\/aFileWithExt\.[a-f0-9]{8}\.unknown$/ 146 | ); 147 | doc.defaultView.close(); 148 | }); 149 | }); 150 | }); 151 | -------------------------------------------------------------------------------- /template/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /template-typescript/src/serviceWorker.ts: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | type Config = { 24 | onSuccess?: (registration: ServiceWorkerRegistration) => void; 25 | onUpdate?: (registration: ServiceWorkerRegistration) => void; 26 | }; 27 | 28 | export function register(config?: Config) { 29 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 30 | // The URL constructor is available in all browsers that support SW. 31 | const publicUrl = new URL( 32 | (process as { env: { [key: string]: string } }).env.PUBLIC_URL, 33 | window.location.href 34 | ); 35 | if (publicUrl.origin !== window.location.origin) { 36 | // Our service worker won't work if PUBLIC_URL is on a different origin 37 | // from what our page is served on. This might happen if a CDN is used to 38 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 39 | return; 40 | } 41 | 42 | window.addEventListener('load', () => { 43 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 44 | 45 | if (isLocalhost) { 46 | // This is running on localhost. Let's check if a service worker still exists or not. 47 | checkValidServiceWorker(swUrl, config); 48 | 49 | // Add some additional logging to localhost, pointing developers to the 50 | // service worker/PWA documentation. 51 | navigator.serviceWorker.ready.then(() => { 52 | console.log( 53 | 'This web app is being served cache-first by a service ' + 54 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 55 | ); 56 | }); 57 | } else { 58 | // Is not localhost. Just register service worker 59 | registerValidSW(swUrl, config); 60 | } 61 | }); 62 | } 63 | } 64 | 65 | function registerValidSW(swUrl: string, config?: Config) { 66 | navigator.serviceWorker 67 | .register(swUrl) 68 | .then(registration => { 69 | registration.onupdatefound = () => { 70 | const installingWorker = registration.installing; 71 | if (installingWorker == null) { 72 | return; 73 | } 74 | installingWorker.onstatechange = () => { 75 | if (installingWorker.state === 'installed') { 76 | if (navigator.serviceWorker.controller) { 77 | // At this point, the updated precached content has been fetched, 78 | // but the previous service worker will still serve the older 79 | // content until all client tabs are closed. 80 | console.log( 81 | 'New content is available and will be used when all ' + 82 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 83 | ); 84 | 85 | // Execute callback 86 | if (config && config.onUpdate) { 87 | config.onUpdate(registration); 88 | } 89 | } else { 90 | // At this point, everything has been precached. 91 | // It's the perfect time to display a 92 | // "Content is cached for offline use." message. 93 | console.log('Content is cached for offline use.'); 94 | 95 | // Execute callback 96 | if (config && config.onSuccess) { 97 | config.onSuccess(registration); 98 | } 99 | } 100 | } 101 | }; 102 | }; 103 | }) 104 | .catch(error => { 105 | console.error('Error during service worker registration:', error); 106 | }); 107 | } 108 | 109 | function checkValidServiceWorker(swUrl: string, config?: Config) { 110 | // Check if the service worker can be found. If it can't reload the page. 111 | fetch(swUrl) 112 | .then(response => { 113 | // Ensure service worker exists, and that we really are getting a JS file. 114 | const contentType = response.headers.get('content-type'); 115 | if ( 116 | response.status === 404 || 117 | (contentType != null && contentType.indexOf('javascript') === -1) 118 | ) { 119 | // No service worker found. Probably a different app. Reload the page. 120 | navigator.serviceWorker.ready.then(registration => { 121 | registration.unregister().then(() => { 122 | window.location.reload(); 123 | }); 124 | }); 125 | } else { 126 | // Service worker found. Proceed as normal. 127 | registerValidSW(swUrl, config); 128 | } 129 | }) 130 | .catch(() => { 131 | console.log( 132 | 'No internet connection found. App is running in offline mode.' 133 | ); 134 | }); 135 | } 136 | 137 | export function unregister() { 138 | if ('serviceWorker' in navigator) { 139 | navigator.serviceWorker.ready.then(registration => { 140 | registration.unregister(); 141 | }); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-scripts-with-ssr [![Build Status](https://travis-ci.org/joernb/react-scripts-with-ssr.svg?branch=master)](https://travis-ci.org/joernb/react-scripts-with-ssr) 2 | 3 | This is a fork of [react-scripts](https://github.com/facebook/create-react-app/tree/master/packages/react-scripts), which adds support for server-side rendering (SSR). 4 | 5 | `react-scripts` is a part of [Create React App](https://github.com/facebook/create-react-app), which can be used with a customized version of `react-scripts`. 6 | 7 | ## Getting Started 8 | 9 | Install create-react-app: 10 | ```sh 11 | npm i -g create-react-app 12 | ``` 13 | 14 | Generate a new project (add `--typescript` for TypeScript support): 15 | ```sh 16 | npx create-react-app my-app --scripts-version react-scripts-with-ssr 17 | cd my-app 18 | ``` 19 | 20 | Start a local webpack dev server with integrated server-side rendering: 21 | ```sh 22 | npm start 23 | ``` 24 | 25 | Build a production version and test server-side rendering locally: 26 | ```sh 27 | npm run build 28 | npm run serve 29 | ``` 30 | 31 | ## How it works 32 | 33 | ### SSR entry point 34 | 35 | The script will generate an additional entry point for server-side rendering in `src/index.ssr.js` (or `src/index.ssr.tsx`). It exports an express-style request handler, that looks like this: 36 | 37 | ```js 38 | export default (request, response) => { 39 | // ... 40 | response.status(200).send("..."); 41 | }; 42 | ``` 43 | 44 | Webpack will compile this entry point as a separate library `build/ssr.js`. In production, that library may be imported by an executable node script, which sets up an express server and plugs in the request handler. Such a script is provided as an example at `react-scripts-with-ssr/scripts/serve.js`, which you may start with `npm run serve` to test your production builds. That script however is not part of the compilation. It is up to you to integrate the request handler into your server-side runtime environment. 45 | 46 | During development, the request handler will be integrated into the local webpack dev server. Start it with `npm start` and open `http://localhost:3000` to see the server-side rendered output. 47 | 48 | If `src/index.ssr.js` exports a function called `devServerHandler`, it will be invoked and its return value will be used as a request handler during development instead. This gives your entry point the possibility to make environment-specific adjustments. For example, all assets are compiled in-memory during development and should not be served from the real file system. 49 | 50 | ### Relative Urls, PUBLIC_URL and BASE_HREF 51 | `create-react-app` provides a variable called `PUBLIC_URL`, which is accessible via `process.env.PUBLIC_URL` in JavaScript or by using the placeholder `%PUBLIC_URL%` in HTML to reference assets. This variable is determined at **compile time** and must be specified before compilation, which makes your compiled web app dependant on the specified location. 52 | 53 | For projects with server-side rendering however, there is another way to deal with this. Instead of hardcoding the public url, HTML assets can be referenced with a relative url and the server-side renderer can read a specified base url at **runtime** and render it into a base tag. `react-scripts-with-ssr` supports using `PUBLIC_URL` but also allows the `BASE_HREF` approach: 54 | * Define a `BASE_HREF` environment variable in your server runtime environment containing your base url (e.g. `https://example.com/folder`). 55 | * Add `` to your index.html template. Notice the trailing slash. 56 | * Replace `%BASE_HREF%` with the value of `process.env.BASE_HREF` in your server-side request handler. 57 | * Make all asset references in HTML relative. Do not use `%PUBLIC_URL%` in URLs or server-relative URLs (e.g. `/some/url`). 58 | * Make the build scripts emit relative paths by providing `PUBLIC_URL` as environment variable with the value `.` during compile time or setting the `homepage` field in `package.json` to `.`. 59 | * If you need access to BASE_HREF in JavaScript, read it from `document.getElementsByTagName("base")[0].href;`. 60 | 61 | ### Environment variables 62 | 63 | `create-react-app` embeds environment variables prefixed with REACT_APP in the build during **compile time** and provides them with a simulated `process.env` object using Webpack's DefinePlugin. 64 | 65 | While embedding is necessary on the client-side, the ssr request handler runs in a Node.js context with real environment variables. `react-scripts-with-ssr` allows accessing external environment variables in the ssr request handler during **runtime**. However, all variables contained in the client-side build are also embedded into the ssr request handler as default values if they are not provided by the runtime environment. 66 | 67 | If you want to make your server's **runtime** environment variables available on the client-side, you can do this with a `clientEnv` variable: 68 | * Add a variable assignment script `` to the head section in `public/index.html`. 69 | * Replace the placeholder in the ssr request handler with `.replace(/%CLIENT_ENV%/g, JSON.stringify({ FOO: process.env.FOO }))`. 70 | * Access the value on the client-side with `clientEnv.FOO`. 71 | * For TypeScript: Declare the global variable `declare const clientEnv: NodeJS.ProcessEnv;`. 72 | 73 | You might also use this mechanism to transfer preloaded state to the client. 74 | 75 | 76 | ## Contribute 77 | 78 | ### Merge react-scripts updates 79 | 80 | Clone create-react-app and create a subtree branch for react-scripts: 81 | 82 | ```sh 83 | git clone git@github.com:facebook/create-react-app.git create-react-app 84 | cd create-react-app 85 | git checkout react-scripts@2.1.3 86 | git subtree split -P packages/react-scripts -b react-scripts-v2.1.3 87 | ``` 88 | 89 | Merge the subtree branch into this project: 90 | 91 | ```sh 92 | git remote add upstream ../create-react-app 93 | git merge upstream react-scripts-v2.1.3 94 | ``` 95 | 96 | ## Sponsors 97 | 98 | 99 | -------------------------------------------------------------------------------- /config/webpackDevServer.config.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); 12 | const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); 13 | const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); 14 | const ignoredFiles = require('react-dev-utils/ignoredFiles'); 15 | const paths = require('./paths'); 16 | const fs = require('fs'); 17 | 18 | const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; 19 | const host = process.env.HOST || '0.0.0.0'; 20 | 21 | module.exports = function(proxy, allowedHost) { 22 | return { 23 | // WebpackDevServer 2.4.3 introduced a security fix that prevents remote 24 | // websites from potentially accessing local content through DNS rebinding: 25 | // https://github.com/webpack/webpack-dev-server/issues/887 26 | // https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a 27 | // However, it made several existing use cases such as development in cloud 28 | // environment or subdomains in development significantly more complicated: 29 | // https://github.com/facebook/create-react-app/issues/2271 30 | // https://github.com/facebook/create-react-app/issues/2233 31 | // While we're investigating better solutions, for now we will take a 32 | // compromise. Since our WDS configuration only serves files in the `public` 33 | // folder we won't consider accessing them a vulnerability. However, if you 34 | // use the `proxy` feature, it gets more dangerous because it can expose 35 | // remote code execution vulnerabilities in backends like Django and Rails. 36 | // So we will disable the host check normally, but enable it if you have 37 | // specified the `proxy` setting. Finally, we let you override it if you 38 | // really know what you're doing with a special environment variable. 39 | disableHostCheck: 40 | !proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', 41 | // Enable gzip compression of generated files. 42 | compress: true, 43 | // Silence WebpackDevServer's own logs since they're generally not useful. 44 | // It will still show compile warnings and errors with this setting. 45 | clientLogLevel: 'none', 46 | // By default WebpackDevServer serves physical files from current directory 47 | // in addition to all the virtual build products that it serves from memory. 48 | // This is confusing because those files won’t automatically be available in 49 | // production build folder unless we copy them. However, copying the whole 50 | // project directory is dangerous because we may expose sensitive files. 51 | // Instead, we establish a convention that only files in `public` directory 52 | // get served. Our build script will copy `public` into the `build` folder. 53 | // In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%: 54 | // 55 | // In JavaScript code, you can access it with `process.env.PUBLIC_URL`. 56 | // Note that we only recommend to use `public` folder as an escape hatch 57 | // for files like `favicon.ico`, `manifest.json`, and libraries that are 58 | // for some reason broken when imported through Webpack. If you just want to 59 | // use an image, put it in `src` and `import` it from JavaScript instead. 60 | contentBase: paths.appPublic, 61 | // By default files from `contentBase` will not trigger a page reload. 62 | watchContentBase: true, 63 | // Enable hot reloading server. It will provide /sockjs-node/ endpoint 64 | // for the WebpackDevServer client so it can learn when the files were 65 | // updated. The WebpackDevServer client is included as an entry point 66 | // in the Webpack development configuration. Note that only changes 67 | // to CSS are currently hot reloaded. JS changes will refresh the browser. 68 | hot: true, 69 | // It is important to tell WebpackDevServer to use the same "root" path 70 | // as we specified in the config. In development, we always serve from /. 71 | publicPath: '/', 72 | // WebpackDevServer is noisy by default so we emit custom message instead 73 | // by listening to the compiler events with `compiler.hooks[...].tap` calls above. 74 | quiet: true, 75 | // Reportedly, this avoids CPU overload on some systems. 76 | // https://github.com/facebook/create-react-app/issues/293 77 | // src/node_modules is not ignored to support absolute imports 78 | // https://github.com/facebook/create-react-app/issues/1065 79 | watchOptions: { 80 | ignored: ignoredFiles(paths.appSrc), 81 | }, 82 | // Enable HTTPS if the HTTPS environment variable is set to 'true' 83 | https: protocol === 'https', 84 | host, 85 | overlay: false, 86 | historyApiFallback: { 87 | // Paths with dots should still use the history fallback. 88 | // See https://github.com/facebook/create-react-app/issues/387. 89 | disableDotRule: true, 90 | }, 91 | public: allowedHost, 92 | proxy, 93 | before(app, server) { 94 | if (fs.existsSync(paths.proxySetup)) { 95 | // This registers user provided middleware for proxy reasons 96 | require(paths.proxySetup)(app); 97 | } 98 | 99 | // This lets us fetch source contents from webpack for the error overlay 100 | app.use(evalSourceMapMiddleware(server)); 101 | // This lets us open files from the runtime error overlay. 102 | app.use(errorOverlayMiddleware()); 103 | 104 | // This service worker file is effectively a 'no-op' that will reset any 105 | // previous service worker registered for the same host:port combination. 106 | // We do this in development to avoid hitting the production cache if 107 | // it used the same host and port. 108 | // https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432 109 | app.use(noopServiceWorkerMiddleware()); 110 | }, 111 | }; 112 | }; 113 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | // @remove-on-eject-begin 2 | /** 3 | * Copyright (c) 2015-present, Facebook, Inc. 4 | * 5 | * This source code is licensed under the MIT license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | // @remove-on-eject-end 9 | 'use strict'; 10 | 11 | const path = require('path'); 12 | const fs = require('fs'); 13 | const url = require('url'); 14 | 15 | // Make sure any symlinks in the project folder are resolved: 16 | // https://github.com/facebook/create-react-app/issues/637 17 | const appDirectory = fs.realpathSync(process.cwd()); 18 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath); 19 | 20 | const envPublicUrl = process.env.PUBLIC_URL; 21 | 22 | function ensureSlash(inputPath, needsSlash) { 23 | const hasSlash = inputPath.endsWith('/'); 24 | if (hasSlash && !needsSlash) { 25 | return inputPath.substr(0, inputPath.length - 1); 26 | } else if (!hasSlash && needsSlash) { 27 | return `${inputPath}/`; 28 | } else { 29 | return inputPath; 30 | } 31 | } 32 | 33 | const getPublicUrl = appPackageJson => 34 | envPublicUrl || require(appPackageJson).homepage; 35 | 36 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer 37 | // "public path" at which the app is served. 38 | // Webpack needs to know it to put the right