├── .editorconfig
├── .eslintrc
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── lerna.json
├── package.json
├── packages
├── react-app-tools
│ ├── LICENSE
│ ├── README.md
│ ├── WebpackDevServerUtils.js
│ ├── bin
│ │ └── react-app.js
│ ├── config
│ │ ├── babel.dependencies.js
│ │ ├── babel.js
│ │ ├── env.js
│ │ ├── jest
│ │ │ ├── babelTransform.js
│ │ │ ├── cssTransform.js
│ │ │ └── fileTransform.js
│ │ ├── paths.js
│ │ ├── webpack-overrides.js
│ │ ├── webpack.config.js
│ │ ├── webpack.configFactory.js
│ │ ├── webpack.js
│ │ └── webpackDevServer.config.js
│ ├── lib
│ │ └── react-app.d.ts
│ ├── package.json
│ ├── scripts
│ │ ├── build.js
│ │ ├── eject.js
│ │ ├── init.js
│ │ ├── start.js
│ │ ├── test.js
│ │ └── utils
│ │ │ ├── createJestConfig.js
│ │ │ ├── verifyPackageTree.js
│ │ │ └── verifyTypeScriptSetup.js
│ ├── template-typescript
│ │ ├── README.md
│ │ ├── gitignore
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.test.tsx
│ │ │ ├── App.tsx
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── logo.svg
│ │ │ └── serviceWorker.ts
│ └── template
│ │ ├── README.md
│ │ ├── gitignore
│ │ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ │ └── src
│ │ ├── components
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ └── logo.svg
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── server
│ │ └── index.js
│ │ └── serviceWorker.js
└── react-app
│ ├── index.js
│ └── package.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # http://editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 |
9 | # Change these settings to your own preference
10 | indent_style = space
11 | indent_size = 2
12 |
13 | # We recommend you to keep these unchanged
14 | end_of_line = lf
15 | charset = utf-8
16 | trim_trailing_whitespace = true
17 | insert_final_newline = true
18 |
19 | [*.md]
20 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "env": {
4 | "browser": true,
5 | "commonjs": true,
6 | "node": true,
7 | "es6": true
8 | },
9 | "parserOptions": {
10 | "ecmaVersion": 2018
11 | },
12 | "rules": {
13 | "no-console": "off",
14 | "strict": ["error", "global"],
15 | "curly": "warn"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/*
2 | !.vscode/settings.json
3 | node_modules/
4 | .DS_Store
5 | *.tgz
6 | lerna-debug.log
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package.json
3 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": true,
7 | "trailingComma": "es5"
8 | }
9 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true,
3 | "javascript.format.enable": false,
4 | "search.exclude": {
5 | "**/.idea": true,
6 | "**/node_modules": true,
7 | "**/lerna-debug.log": true,
8 | "**/yarn-error.log": true,
9 | "**/yarn.lock": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2013-present, Facebook, Inc.
4 | Copyright (c) 2015-present, Kriasoft.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | React App SDK
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Everything you love about **[Create React App](https://github.com/facebook/create-react-app)** plus
11 | server-side code support (SSR, GraphQL API, etc) and config overrides (Babel, Webpack, etc.). See
12 | the [demo project](https://github.com/kriasoft/react-firebase-starter).
13 |
14 | **React App SDK** is intended to be used as a drop-in replacement for `react-scripts` NPM module.
15 | If you want to add server-side code into your application built with Create React App, all you have
16 | to do is to replace `react-scripts` dev dependency with `react-app-tools` plus provide one more
17 | entry point for Node.js as demonstrated below:
18 |
19 | #### Directory Layout
20 |
21 | ```bash
22 | .
23 | ├── build/ # Compiled output
24 | ├── src/ # Universal application source code
25 | │ ├── components/ # Shared React.js components
26 | │ │ ├── /App/ # - The top-level React component
27 | │ │ ├── /Button/ # - Some other UI element
28 | │ │ └── ... # - etc.
29 | │ ├── server/ # Node.js app
30 | │ │ ├── ssr.js # - Server-side rendering, e.g. ReactDOMServer.renderToString()
31 | │ │ ├── api.js # - GraphQL API endpoint
32 | │ │ └── index.js # - Node.js app entry point
33 | │ └── index.js # Client-side app entry point, e.g. ReactDOM.hydrate(, container)
34 | └── package.json # List of project dependencies and NPM scripts
35 | ```
36 |
37 | #### `package.json`
38 |
39 | ```diff
40 | {
41 | "main": "build/server.js",
42 | "engines": {
43 | "node": ">=8.10"
44 | },
45 | "dependencies": {
46 | + "express": "^4.6.14",
47 | "react": "^16.8.4",
48 | "react-dom": "^16.8.4"
49 | },
50 | "devDependencies": {
51 | - "react-scripts": "^1.1.1"
52 | + "react-app-tools": "^3.1.0-preview.7"
53 | },
54 | "scripts": {
55 | - "start": "react-scripts start",
56 | + "start": "react-app start",
57 | - "build": "react-scripts build",
58 | + "build": "react-app build",
59 | - "test": "react-scripts test"
60 | + "test": "react-app test"
61 | }
62 | }
63 | ```
64 |
65 | #### `src/index.js` - Client-side rendering
66 |
67 | ```js
68 | import React from 'react';
69 | import ReactDOM from 'react-dom';
70 | import App from './components/App';
71 |
72 | ReactDOM.hydrate(, document.getElementById('root'));
73 | ```
74 |
75 | #### `src/server/index.js` - Server-side rendering and/or API endpoint
76 |
77 | ```js
78 | const path = require('path');
79 | const express = require('express');
80 | const React = require('react');
81 | const ReactDOMServer = require('react-dom/server');
82 | const App = require('../components/App');
83 | const stats = require('./stats.json');
84 |
85 | const app = express();
86 |
87 | app.get('*', (req, res) => {
88 | res.send(`
89 |
90 |
91 | ${ReactDOMServer.renderToString(
)}
92 | ${stats.entrypoints.main.assets.map(
93 | src => ``
94 | )}
95 |
96 |
97 | `);
98 | });
99 |
100 | if (process.env.NODE_ENV === 'production') {
101 | app.listen(process.env.PORT || 8080);
102 | } else {
103 | module.exports.default = app;
104 | }
105 | ```
106 |
107 | You can launch the app in development mode by running:
108 |
109 | ```sh
110 | $ npm install
111 | $ npm start
112 | ```
113 |
114 | Then open [http://localhost:3000/](http://localhost:3000/) to see your app.
115 | When you’re ready to deploy to production, create a minified bundle with `npm run build`.
116 |
117 | 
118 |
119 | For more information refer to Create React App documentation:
120 |
121 | - [Getting Started](https://github.com/facebookincubator/create-react-app#getting-started) – How to create a new app.
122 | - [User Guide](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md) – How to develop apps bootstrapped with Create React App.
123 |
124 | Join our Telegram chat for support and feature requests - https://t.me/reactapp
125 |
126 | 
How fast is React SSR?
127 |
128 | ## How to Customize
129 |
130 | Create `webpack.config.js` file in the root of your project that extends the
131 | default Webpack configuration. For example:
132 |
133 | ```js
134 | module.exports = () => {
135 | const [
136 | browserConfig,
137 | serverConfig,
138 | ] = require('react-app-tools/config/webpack');
139 | return [
140 | browserConfig,
141 | {
142 | ...serverConfig,
143 | plugins: {
144 | ...serverConfig.plugins.concat(
145 | new LimitChunkCountPlugin({ maxChunks: 1 })
146 | ),
147 | },
148 | },
149 | ];
150 | };
151 | ```
152 |
153 | ## Backers
154 |
155 | Love **React App SDK**? Help us keep it alive by [donating](https://opencollective.com/react-app)
156 | funds to cover project expenses!
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | ## Contribute
196 |
197 | Help shape the future of **React App SDK** by joining our [community](https://t.me/reactapp)
198 | today, check out the [open issues](https://github.com/kriasoft/react-app/issues), submit [new
199 | feature ideas](https://github.com/kriasoft/react-app/issues/new?labels=enhancement) and [bug
200 | reports](https://github.com/kriasoft/react-app/issues/new?labels=bug), send us [pull
201 | requests](CONTRIBUTING.md#submitting-a-pull-request)!
202 |
203 | ## License
204 |
205 | [MIT](https://github.com/kriasoft/react-app/blob/master/LICENSE) © 2016-present Facebook, Kriasoft.
206 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.6.0",
3 | "npmClient": "yarn",
4 | "useWorkspaces": true,
5 | "version": "independent"
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "workspaces": [
4 | "packages/*"
5 | ],
6 | "devDependencies": {
7 | "eslint": "5.15.1",
8 | "husky": "1.3.0",
9 | "lerna": "^2.9.1",
10 | "lint-staged": "^8.0.4",
11 | "prettier": "^1.16.4",
12 | "react-scripts": "2.1.8"
13 | },
14 | "lint-staged": {
15 | "*.js": [
16 | "eslint --no-ignore --fix",
17 | "prettier --write",
18 | "git add --force"
19 | ],
20 | "*.json": [
21 | "prettier --write",
22 | "git add --force"
23 | ]
24 | },
25 | "husky": {
26 | "hooks": {
27 | "pre-commit": "lint-staged"
28 | }
29 | },
30 | "scripts": {
31 | "format": "prettier --trailing-comma es5 --single-quote --write 'packages/*/*.js' 'packages/*/!(node_modules)/**/*.js'"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/packages/react-app-tools/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 |
--------------------------------------------------------------------------------
/packages/react-app-tools/README.md:
--------------------------------------------------------------------------------
1 | # react-app-tools
2 |
3 | This package is a fork of [`react-scripts`](https://npmjs.com/package/react-scripts) that adds a
4 | couple more features to [Create React App](https://github.com/facebook/create-react-app) tooling:
5 |
6 | * Ability to add, build, and test server-side code using the same instance of Webpack.
7 | * Ability to customize Babel, Webpack and other configs.
8 |
9 |
10 | Please refer to its documentation:
11 |
12 |
13 | - [Getting Started](https://facebook.github.io/create-react-app/docs/getting-started) – How to create a new app.
14 | - [User Guide](https://facebook.github.io/create-react-app/) – How to develop apps bootstrapped with Create React App.
15 | - [React App SDK](https://github.com/kriasoft/react-app) - the patched version of CRA
16 | - [React Starter Kit](https://github.com/kriasoft/react-firebase-starter) - project template (seed project)
17 |
18 | Support and feature requests:
19 |
20 | - https://t.me/ReactApp
21 | - https://t.me/ReactStarter
22 |
--------------------------------------------------------------------------------
/packages/react-app-tools/WebpackDevServerUtils.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 | 'use strict';
8 |
9 | const address = require('address');
10 | const fs = require('fs');
11 | const path = require('path');
12 | const url = require('url');
13 | const chalk = require('chalk');
14 | const detect = require('detect-port-alt');
15 | const isRoot = require('is-root');
16 | const inquirer = require('inquirer');
17 | const clearConsole = require('react-dev-utils/clearConsole');
18 | const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
19 | const getProcessForPort = require('react-dev-utils/getProcessForPort');
20 | const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
21 | const forkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
22 | const paths = require('./config/paths');
23 |
24 | const isInteractive = process.stdout.isTTY;
25 |
26 | function prepareUrls(protocol, host, port) {
27 | const formatUrl = hostname =>
28 | url.format({
29 | protocol,
30 | hostname,
31 | port,
32 | pathname: '/',
33 | });
34 | const prettyPrintUrl = hostname =>
35 | url.format({
36 | protocol,
37 | hostname,
38 | port: chalk.bold(port),
39 | pathname: '/',
40 | });
41 |
42 | const isUnspecifiedHost = host === '0.0.0.0' || host === '::';
43 | let prettyHost, lanUrlForConfig, lanUrlForTerminal;
44 | if (isUnspecifiedHost) {
45 | prettyHost = 'localhost';
46 | try {
47 | // This can only return an IPv4 address
48 | lanUrlForConfig = address.ip();
49 | if (lanUrlForConfig) {
50 | // Check if the address is a private ip
51 | // https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
52 | if (
53 | /^10[.]|^172[.](1[6-9]|2[0-9]|3[0-1])[.]|^192[.]168[.]/.test(
54 | lanUrlForConfig
55 | )
56 | ) {
57 | // Address is private, format it for later use
58 | lanUrlForTerminal = prettyPrintUrl(lanUrlForConfig);
59 | } else {
60 | // Address is not private, so we will discard it
61 | lanUrlForConfig = undefined;
62 | }
63 | }
64 | } catch (_e) {
65 | // ignored
66 | }
67 | } else {
68 | prettyHost = host;
69 | }
70 | const localUrlForTerminal = prettyPrintUrl(prettyHost);
71 | const localUrlForBrowser = formatUrl(prettyHost);
72 | return {
73 | lanUrlForConfig,
74 | lanUrlForTerminal,
75 | localUrlForTerminal,
76 | localUrlForBrowser,
77 | };
78 | }
79 |
80 | function printInstructions(appName, urls, useYarn) {
81 | console.log();
82 | console.log(`You can now view ${chalk.bold(appName)} in the browser.`);
83 | console.log();
84 |
85 | if (urls.lanUrlForTerminal) {
86 | console.log(
87 | ` ${chalk.bold('Local:')} ${urls.localUrlForTerminal}`
88 | );
89 | console.log(
90 | ` ${chalk.bold('On Your Network:')} ${urls.lanUrlForTerminal}`
91 | );
92 | } else {
93 | console.log(` ${urls.localUrlForTerminal}`);
94 | }
95 |
96 | console.log();
97 | console.log('Note that the development build is not optimized.');
98 | console.log(
99 | `To create a production build, use ` +
100 | `${chalk.cyan(`${useYarn ? 'yarn' : 'npm run'} build`)}.`
101 | );
102 | console.log();
103 | }
104 |
105 | function createCompiler({
106 | appName,
107 | config,
108 | devSocket,
109 | urls,
110 | useYarn,
111 | useTypeScript,
112 | webpack,
113 | }) {
114 | // "Compiler" is a low-level interface to Webpack.
115 | // It lets us listen to some events and provide our own custom messages.
116 | let compiler;
117 | try {
118 | compiler = webpack(config);
119 | } catch (err) {
120 | console.log(chalk.red('Failed to compile.'));
121 | console.log();
122 | console.log(err.message || err);
123 | console.log();
124 | process.exit(1);
125 | }
126 |
127 | // "invalid" event fires when you have changed a file, and Webpack is
128 | // recompiling a bundle. WebpackDevServer takes care to pause serving the
129 | // bundle, so if you refresh, it'll wait instead of serving the old one.
130 | // "invalid" is short for "bundle invalidated", it doesn't imply any errors.
131 | compiler.hooks.invalid.tap('invalid', () => {
132 | if (isInteractive) {
133 | clearConsole();
134 | }
135 | console.log('Compiling...');
136 |
137 | global.appPromise = new Promise(resolve => {
138 | global.appPromiseResolve = resolve;
139 | });
140 | });
141 |
142 | let isFirstCompile = true;
143 | let tsMessagesPromise;
144 | let tsMessagesResolver;
145 |
146 | global.appPromise = new Promise(resolve => {
147 | global.appPromiseResolve = resolve;
148 | });
149 |
150 | if (useTypeScript) {
151 | compiler.hooks.beforeCompile.tap('beforeCompile', () => {
152 | tsMessagesPromise = new Promise(resolve => {
153 | tsMessagesResolver = msgs => resolve(msgs);
154 | });
155 | });
156 |
157 | forkTsCheckerWebpackPlugin
158 | .getCompilerHooks(compiler)
159 | .receive.tap('afterTypeScriptCheck', (diagnostics, lints) => {
160 | const allMsgs = [...diagnostics, ...lints];
161 | const format = message =>
162 | `${message.file}\n${typescriptFormatter(message, true)}`;
163 |
164 | tsMessagesResolver({
165 | errors: allMsgs.filter(msg => msg.severity === 'error').map(format),
166 | warnings: allMsgs
167 | .filter(msg => msg.severity === 'warning')
168 | .map(format),
169 | });
170 | });
171 | }
172 |
173 | // "done" event fires when Webpack has finished recompiling the bundle.
174 | // Whether or not you have warnings or errors, you will get this event.
175 | compiler.hooks.done.tap('done', async stats => {
176 | if (isInteractive) {
177 | clearConsole();
178 | }
179 |
180 | // We have switched off the default Webpack output in WebpackDevServer
181 | // options so we are going to "massage" the warnings and errors and present
182 | // them in a readable focused way.
183 | // We only construct the warnings and errors for speed:
184 | // https://github.com/facebook/create-react-app/issues/4492#issuecomment-421959548
185 | const statsData = stats.toJson({
186 | all: false,
187 | warnings: true,
188 | errors: true,
189 | });
190 |
191 | if (useTypeScript && statsData.errors.length === 0) {
192 | const delayedMsg = setTimeout(() => {
193 | console.log(
194 | chalk.yellow(
195 | 'Files successfully emitted, waiting for typecheck results...'
196 | )
197 | );
198 | }, 100);
199 |
200 | const messages = await tsMessagesPromise;
201 | clearTimeout(delayedMsg);
202 | statsData.errors.push(...messages.errors);
203 | statsData.warnings.push(...messages.warnings);
204 |
205 | // Push errors and warnings into compilation result
206 | // to show them after page refresh triggered by user.
207 | stats.compilation.errors.push(...messages.errors);
208 | stats.compilation.warnings.push(...messages.warnings);
209 |
210 | if (messages.errors.length > 0) {
211 | devSocket.errors(messages.errors);
212 | } else if (messages.warnings.length > 0) {
213 | devSocket.warnings(messages.warnings);
214 | }
215 |
216 | if (isInteractive) {
217 | clearConsole();
218 | }
219 | }
220 |
221 | const messages = formatWebpackMessages(statsData);
222 | const isSuccessful = !messages.errors.length && !messages.warnings.length;
223 | if (isSuccessful) {
224 | console.log(chalk.green('Compiled successfully!'));
225 | }
226 | if (isSuccessful && (isInteractive || isFirstCompile)) {
227 | printInstructions(appName, urls, useYarn);
228 | }
229 | isFirstCompile = false;
230 |
231 | // If errors exist, only show errors.
232 | if (messages.errors.length) {
233 | // Only keep the first error. Others are often indicative
234 | // of the same problem, but confuse the reader with noise.
235 | if (messages.errors.length > 1) {
236 | messages.errors.length = 1;
237 | }
238 | console.log(chalk.red('Failed to compile.\n'));
239 | console.log(messages.errors.join('\n\n'));
240 | return;
241 | }
242 |
243 | // Show warnings if no errors were found.
244 | if (messages.warnings.length) {
245 | console.log(chalk.yellow('Compiled with warnings.\n'));
246 | console.log(messages.warnings.join('\n\n'));
247 |
248 | // Teach some ESLint tricks.
249 | console.log(
250 | '\nSearch for the ' +
251 | chalk.underline(chalk.yellow('keywords')) +
252 | ' to learn more about each warning.'
253 | );
254 | console.log(
255 | 'To ignore, add ' +
256 | chalk.cyan('// eslint-disable-next-line') +
257 | ' to the line before.\n'
258 | );
259 | }
260 |
261 | const statsJson = JSON.stringify(
262 | stats.stats[0].toJson({}, true),
263 | null,
264 | ' '
265 | );
266 | fs.writeFileSync(paths.stats, statsJson, 'utf8');
267 | if (paths.nodeBuildAppJs in require.cache) {
268 | try {
269 | const dispose = (require(paths.nodeBuildAppJs) || {}).dispose;
270 | if (typeof dispose === 'function') {
271 | dispose();
272 | }
273 | } catch (err) {
274 | console.log(err);
275 | }
276 | }
277 | delete require.cache[paths.stats];
278 | delete require.cache[paths.nodeBuildAppJs];
279 | global.appPromiseResolve();
280 | });
281 |
282 | // You can safely remove this after ejecting.
283 | // We only use this block for testing of Create React App itself:
284 | const isSmokeTest = process.argv.some(
285 | arg => arg.indexOf('--smoke-test') > -1
286 | );
287 | if (isSmokeTest) {
288 | compiler.hooks.failed.tap('smokeTest', async () => {
289 | await tsMessagesPromise;
290 | process.exit(1);
291 | });
292 | compiler.hooks.done.tap('smokeTest', async stats => {
293 | await tsMessagesPromise;
294 | if (stats.hasErrors() || stats.hasWarnings()) {
295 | process.exit(1);
296 | } else {
297 | process.exit(0);
298 | }
299 | });
300 | }
301 |
302 | return compiler;
303 | }
304 |
305 | function resolveLoopback(proxy) {
306 | const o = url.parse(proxy);
307 | o.host = undefined;
308 | if (o.hostname !== 'localhost') {
309 | return proxy;
310 | }
311 | // Unfortunately, many languages (unlike node) do not yet support IPv6.
312 | // This means even though localhost resolves to ::1, the application
313 | // must fall back to IPv4 (on 127.0.0.1).
314 | // We can re-enable this in a few years.
315 | /*try {
316 | o.hostname = address.ipv6() ? '::1' : '127.0.0.1';
317 | } catch (_ignored) {
318 | o.hostname = '127.0.0.1';
319 | }*/
320 |
321 | try {
322 | // Check if we're on a network; if we are, chances are we can resolve
323 | // localhost. Otherwise, we can just be safe and assume localhost is
324 | // IPv4 for maximum compatibility.
325 | if (!address.ip()) {
326 | o.hostname = '127.0.0.1';
327 | }
328 | } catch (_ignored) {
329 | o.hostname = '127.0.0.1';
330 | }
331 | return url.format(o);
332 | }
333 |
334 | // We need to provide a custom onError function for httpProxyMiddleware.
335 | // It allows us to log custom error messages on the console.
336 | function onProxyError(proxy) {
337 | return (err, req, res) => {
338 | const host = req.headers && req.headers.host;
339 | console.log(
340 | chalk.red('Proxy error:') +
341 | ' Could not proxy request ' +
342 | chalk.cyan(req.url) +
343 | ' from ' +
344 | chalk.cyan(host) +
345 | ' to ' +
346 | chalk.cyan(proxy) +
347 | '.'
348 | );
349 | console.log(
350 | 'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
351 | chalk.cyan(err.code) +
352 | ').'
353 | );
354 | console.log();
355 |
356 | // And immediately send the proper error response to the client.
357 | // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
358 | if (res.writeHead && !res.headersSent) {
359 | res.writeHead(500);
360 | }
361 | res.end(
362 | 'Proxy error: Could not proxy request ' +
363 | req.url +
364 | ' from ' +
365 | host +
366 | ' to ' +
367 | proxy +
368 | ' (' +
369 | err.code +
370 | ').'
371 | );
372 | };
373 | }
374 |
375 | function prepareProxy(proxy, appPublicFolder) {
376 | // `proxy` lets you specify alternate servers for specific requests.
377 | if (!proxy) {
378 | return undefined;
379 | }
380 | if (typeof proxy !== 'string') {
381 | console.log(
382 | chalk.red('When specified, "proxy" in package.json must be a string.')
383 | );
384 | console.log(
385 | chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".')
386 | );
387 | console.log(
388 | chalk.red('Either remove "proxy" from package.json, or make it a string.')
389 | );
390 | process.exit(1);
391 | }
392 |
393 | // If proxy is specified, let it handle any request except for files in the public folder.
394 | function mayProxy(pathname) {
395 | const maybePublicPath = path.resolve(appPublicFolder, pathname.slice(1));
396 | return !fs.existsSync(maybePublicPath);
397 | }
398 |
399 | if (!/^http(s)?:\/\//.test(proxy)) {
400 | console.log(
401 | chalk.red(
402 | 'When "proxy" is specified in package.json it must start with either http:// or https://'
403 | )
404 | );
405 | process.exit(1);
406 | }
407 |
408 | let target;
409 | if (process.platform === 'win32') {
410 | target = resolveLoopback(proxy);
411 | } else {
412 | target = proxy;
413 | }
414 | return [
415 | {
416 | target,
417 | logLevel: 'silent',
418 | // For single page apps, we generally want to fallback to /index.html.
419 | // However we also want to respect `proxy` for API calls.
420 | // So if `proxy` is specified as a string, we need to decide which fallback to use.
421 | // We use a heuristic: We want to proxy all the requests that are not meant
422 | // for static assets and as all the requests for static assets will be using
423 | // `GET` method, we can proxy all non-`GET` requests.
424 | // For `GET` requests, if request `accept`s text/html, we pick /index.html.
425 | // Modern browsers include text/html into `accept` header when navigating.
426 | // However API calls like `fetch()` won’t generally accept text/html.
427 | // If this heuristic doesn’t work well for you, use `src/setupProxy.js`.
428 | context: function(pathname, req) {
429 | return (
430 | req.method !== 'GET' ||
431 | (mayProxy(pathname) &&
432 | req.headers.accept &&
433 | req.headers.accept.indexOf('text/html') === -1)
434 | );
435 | },
436 | onProxyReq: proxyReq => {
437 | // Browsers may send Origin headers even with same-origin
438 | // requests. To prevent CORS issues, we have to change
439 | // the Origin to match the target URL.
440 | if (proxyReq.getHeader('origin')) {
441 | proxyReq.setHeader('origin', target);
442 | }
443 | },
444 | onError: onProxyError(target),
445 | secure: false,
446 | changeOrigin: true,
447 | ws: true,
448 | xfwd: true,
449 | },
450 | ];
451 | }
452 |
453 | function choosePort(host, defaultPort) {
454 | return detect(defaultPort, host).then(
455 | port =>
456 | new Promise(resolve => {
457 | if (port === defaultPort) {
458 | return resolve(port);
459 | }
460 | const message =
461 | process.platform !== 'win32' && defaultPort < 1024 && !isRoot()
462 | ? `Admin permissions are required to run a server on a port below 1024.`
463 | : `Something is already running on port ${defaultPort}.`;
464 | if (isInteractive) {
465 | clearConsole();
466 | const existingProcess = getProcessForPort(defaultPort);
467 | const question = {
468 | type: 'confirm',
469 | name: 'shouldChangePort',
470 | message:
471 | chalk.yellow(
472 | message +
473 | `${existingProcess ? ` Probably:\n ${existingProcess}` : ''}`
474 | ) + '\n\nWould you like to run the app on another port instead?',
475 | default: true,
476 | };
477 | inquirer.prompt(question).then(answer => {
478 | if (answer.shouldChangePort) {
479 | resolve(port);
480 | } else {
481 | resolve(null);
482 | }
483 | });
484 | } else {
485 | console.log(chalk.red(message));
486 | resolve(null);
487 | }
488 | }),
489 | err => {
490 | throw new Error(
491 | chalk.red(`Could not find an open port at ${chalk.bold(host)}.`) +
492 | '\n' +
493 | ('Network error message: ' + err.message || err) +
494 | '\n'
495 | );
496 | }
497 | );
498 | }
499 |
500 | module.exports = {
501 | choosePort,
502 | createCompiler,
503 | prepareProxy,
504 | prepareUrls,
505 | };
506 |
--------------------------------------------------------------------------------
/packages/react-app-tools/bin/react-app.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 | const result = spawn.sync(
33 | 'node',
34 | nodeArgs
35 | .concat(require.resolve('../scripts/' + script))
36 | .concat(args.slice(scriptIndex + 1)),
37 | { stdio: 'inherit' }
38 | );
39 | if (result.signal) {
40 | if (result.signal === 'SIGKILL') {
41 | console.log(
42 | 'The build failed because the process exited too early. ' +
43 | 'This probably means the system ran out of memory or someone called ' +
44 | '`kill -9` on the process.'
45 | );
46 | } else if (result.signal === 'SIGTERM') {
47 | console.log(
48 | 'The build failed because the process exited too early. ' +
49 | 'Someone might have called `kill` or `killall`, or the system could ' +
50 | 'be shutting down.'
51 | );
52 | }
53 | process.exit(1);
54 | }
55 | process.exit(result.status);
56 | break;
57 | }
58 | default:
59 | console.log('Unknown script "' + script + '".');
60 | console.log('Perhaps you need to update react-scripts?');
61 | console.log(
62 | 'See: https://facebook.github.io/create-react-app/docs/updating-to-new-releases'
63 | );
64 | break;
65 | }
66 |
--------------------------------------------------------------------------------
/packages/react-app-tools/config/babel.dependencies.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 | 'use strict';
8 |
9 | const path = require('path');
10 |
11 | const validateBoolOption = (name, value, defaultValue) => {
12 | if (typeof value === 'undefined') {
13 | value = defaultValue;
14 | }
15 |
16 | if (typeof value !== 'boolean') {
17 | throw new Error(`Preset react-app: '${name}' option must be a boolean.`);
18 | }
19 |
20 | return value;
21 | };
22 |
23 | module.exports = function(api, opts) {
24 | if (!opts) {
25 | opts = {};
26 | }
27 |
28 | // This is similar to how `env` works in Babel:
29 | // https://babeljs.io/docs/usage/babelrc/#env-option
30 | // We are not using `env` because it’s ignored in versions > babel-core@6.10.4:
31 | // https://github.com/babel/babel/issues/4539
32 | // https://github.com/facebook/create-react-app/issues/720
33 | // It’s also nice that we can enforce `NODE_ENV` being specified.
34 | var env = process.env.BABEL_ENV || process.env.NODE_ENV;
35 | var isEnvDevelopment = env === 'development';
36 | var isEnvProduction = env === 'production';
37 | var isEnvTest = env === 'test';
38 | var isEnvNode = api.caller(caller => caller.target === 'node');
39 |
40 | var areHelpersEnabled = validateBoolOption('helpers', opts.helpers, false);
41 | var useAbsoluteRuntime = validateBoolOption(
42 | 'absoluteRuntime',
43 | opts.absoluteRuntime,
44 | true
45 | );
46 |
47 | var absoluteRuntimePath = undefined;
48 | if (useAbsoluteRuntime) {
49 | absoluteRuntimePath = path.dirname(
50 | require.resolve('@babel/runtime/package.json')
51 | );
52 | }
53 |
54 | if (!isEnvDevelopment && !isEnvProduction && !isEnvTest) {
55 | throw new Error(
56 | 'Using `react-app-tools/config/babel` requires that you specify `NODE_ENV` or ' +
57 | '`BABEL_ENV` environment variables. Valid values are "development", ' +
58 | '"test", and "production". Instead, received: ' +
59 | JSON.stringify(env) +
60 | '.'
61 | );
62 | }
63 |
64 | return {
65 | // Babel assumes ES Modules, which isn't safe until CommonJS
66 | // dies. This changes the behavior to assume CommonJS unless
67 | // an `import` or `export` is present in the file.
68 | // https://github.com/webpack/webpack/issues/4039#issuecomment-419284940
69 | sourceType: 'unambiguous',
70 | presets: [
71 | (isEnvTest || isEnvNode) && [
72 | // ES features necessary for user's Node version
73 | require('@babel/preset-env').default,
74 | {
75 | targets: {
76 | node: '8.14',
77 | },
78 | // Do not transform modules to CJS
79 | modules: false,
80 | // Exclude transforms that make all code slower
81 | exclude: ['transform-typeof-symbol'],
82 | },
83 | ],
84 | (isEnvProduction || isEnvDevelopment) &&
85 | !isEnvNode && [
86 | // Latest stable ECMAScript features
87 | require('@babel/preset-env').default,
88 | {
89 | // We want Create React App to be IE 9 compatible until React itself
90 | // no longer works with IE 9
91 | targets: {
92 | ie: 9,
93 | },
94 | // Users cannot override this behavior because this Babel
95 | // configuration is highly tuned for ES5 support
96 | ignoreBrowserslistConfig: true,
97 | // If users import all core-js they're probably not concerned with
98 | // bundle size. We shouldn't rely on magic to try and shrink it.
99 | useBuiltIns: false,
100 | // Do not transform modules to CJS
101 | modules: false,
102 | // Exclude transforms that make all code slower
103 | exclude: ['transform-typeof-symbol'],
104 | },
105 | ],
106 | ].filter(Boolean),
107 | plugins: [
108 | // Polyfills the runtime needed for async/await, generators, and friends
109 | // https://babeljs.io/docs/en/babel-plugin-transform-runtime
110 | [
111 | require('@babel/plugin-transform-runtime').default,
112 | {
113 | corejs: false,
114 | helpers: areHelpersEnabled,
115 | regenerator: true,
116 | // https://babeljs.io/docs/en/babel-plugin-transform-runtime#useesmodules
117 | // We should turn this on once the lowest version of Node LTS
118 | // supports ES Modules.
119 | useESModules: isEnvDevelopment || isEnvProduction,
120 | // Undocumented option that lets us encapsulate our runtime, ensuring
121 | // the correct version is used
122 | // https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src/index.js#L35-L42
123 | absoluteRuntime: absoluteRuntimePath,
124 | },
125 | ],
126 | // Adds syntax support for import()
127 | require('@babel/plugin-syntax-dynamic-import').default,
128 | (isEnvTest || isEnvNode) &&
129 | // Transform dynamic import to require
130 | require('babel-plugin-transform-dynamic-import').default,
131 | ].filter(Boolean),
132 | };
133 | };
134 |
--------------------------------------------------------------------------------
/packages/react-app-tools/config/babel.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 | 'use strict';
8 |
9 | const path = require('path');
10 |
11 | const validateBoolOption = (name, value, defaultValue) => {
12 | if (typeof value === 'undefined') {
13 | value = defaultValue;
14 | }
15 |
16 | if (typeof value !== 'boolean') {
17 | throw new Error(`Preset react-app: '${name}' option must be a boolean.`);
18 | }
19 |
20 | return value;
21 | };
22 |
23 | module.exports = function(api, opts) {
24 | if (!opts) {
25 | opts = {};
26 | }
27 |
28 | // This is similar to how `env` works in Babel:
29 | // https://babeljs.io/docs/usage/babelrc/#env-option
30 | // We are not using `env` because it’s ignored in versions > babel-core@6.10.4:
31 | // https://github.com/babel/babel/issues/4539
32 | // https://github.com/facebook/create-react-app/issues/720
33 | // It’s also nice that we can enforce `NODE_ENV` being specified.
34 | var env = process.env.BABEL_ENV || process.env.NODE_ENV;
35 | var isEnvDevelopment = env === 'development';
36 | var isEnvProduction = env === 'production';
37 | var isEnvTest = env === 'test';
38 | var isEnvNode = api.caller(caller => caller.target === 'node');
39 |
40 | var useESModules = validateBoolOption(
41 | 'useESModules',
42 | opts.useESModules,
43 | isEnvDevelopment || isEnvProduction
44 | );
45 | var isFlowEnabled = validateBoolOption('flow', opts.flow, true);
46 | var isTypeScriptEnabled = validateBoolOption(
47 | 'typescript',
48 | opts.typescript,
49 | true
50 | );
51 | var areHelpersEnabled = validateBoolOption('helpers', opts.helpers, true);
52 | var useAbsoluteRuntime = validateBoolOption(
53 | 'absoluteRuntime',
54 | opts.absoluteRuntime,
55 | true
56 | );
57 |
58 | var absoluteRuntimePath = undefined;
59 | if (useAbsoluteRuntime) {
60 | absoluteRuntimePath = path.dirname(
61 | require.resolve('@babel/runtime/package.json')
62 | );
63 | }
64 |
65 | if (!isEnvDevelopment && !isEnvProduction && !isEnvTest) {
66 | throw new Error(
67 | 'Using `babel-preset-react-app` requires that you specify `NODE_ENV` or ' +
68 | '`BABEL_ENV` environment variables. Valid values are "development", ' +
69 | '"test", and "production". Instead, received: ' +
70 | JSON.stringify(env) +
71 | '.'
72 | );
73 | }
74 |
75 | return {
76 | presets: [
77 | (isEnvTest || isEnvNode) && [
78 | // ES features necessary for user's Node version
79 | require('@babel/preset-env').default,
80 | {
81 | targets: {
82 | node: '8.14',
83 | browsers: [],
84 | },
85 | },
86 | ],
87 | !isEnvNode &&
88 | (isEnvProduction || isEnvDevelopment) && [
89 | // Latest stable ECMAScript features
90 | require('@babel/preset-env').default,
91 | {
92 | // We want Create React App to be IE 9 compatible until React itself
93 | // no longer works with IE 9
94 | targets: {
95 | ie: 9,
96 | },
97 | // Users cannot override this behavior because this Babel
98 | // configuration is highly tuned for ES5 support
99 | ignoreBrowserslistConfig: true,
100 | // If users import all core-js they're probably not concerned with
101 | // bundle size. We shouldn't rely on magic to try and shrink it.
102 | useBuiltIns: false,
103 | // Do not transform modules to CJS
104 | modules: false,
105 | // Exclude transforms that make all code slower
106 | exclude: ['transform-typeof-symbol'],
107 | },
108 | ],
109 | [
110 | require('@babel/preset-react').default,
111 | {
112 | // Adds component stack to warning messages
113 | // Adds __self attribute to JSX which React will use for some warnings
114 | development: isEnvDevelopment || isEnvTest,
115 | // Will use the native built-in instead of trying to polyfill
116 | // behavior for any plugins that require one.
117 | useBuiltIns: true,
118 | },
119 | ],
120 | isTypeScriptEnabled && [require('@babel/preset-typescript').default],
121 | ].filter(Boolean),
122 | plugins: [
123 | // Strip flow types before any other transform, emulating the behavior
124 | // order as-if the browser supported all of the succeeding features
125 | // https://github.com/facebook/create-react-app/pull/5182
126 | // We will conditionally enable this plugin below in overrides as it clashes with
127 | // @babel/plugin-proposal-decorators when using TypeScript.
128 | // https://github.com/facebook/create-react-app/issues/5741
129 | isFlowEnabled && [
130 | require('@babel/plugin-transform-flow-strip-types').default,
131 | false,
132 | ],
133 | // Experimental macros support. Will be documented after it's had some time
134 | // in the wild.
135 | require('babel-plugin-macros'),
136 | // Necessary to include regardless of the environment because
137 | // in practice some other transforms (such as object-rest-spread)
138 | // don't work without it: https://github.com/babel/babel/issues/7215
139 | require('@babel/plugin-transform-destructuring').default,
140 | // Turn on legacy decorators for TypeScript files
141 | isTypeScriptEnabled && [
142 | require('@babel/plugin-proposal-decorators').default,
143 | false,
144 | ],
145 | // class { handleClick = () => { } }
146 | // Enable loose mode to use assignment instead of defineProperty
147 | // See discussion in https://github.com/facebook/create-react-app/issues/4263
148 | [
149 | require('@babel/plugin-proposal-class-properties').default,
150 | {
151 | loose: true,
152 | },
153 | ],
154 | // The following two plugins use Object.assign directly, instead of Babel's
155 | // extends helper. Note that this assumes `Object.assign` is available.
156 | // { ...todo, completed: true }
157 | [
158 | require('@babel/plugin-proposal-object-rest-spread').default,
159 | {
160 | useBuiltIns: true,
161 | },
162 | ],
163 | // Polyfills the runtime needed for async/await, generators, and friends
164 | // https://babeljs.io/docs/en/babel-plugin-transform-runtime
165 | !isEnvNode && [
166 | require('@babel/plugin-transform-runtime').default,
167 | {
168 | corejs: false,
169 | helpers: areHelpersEnabled,
170 | regenerator: true,
171 | // https://babeljs.io/docs/en/babel-plugin-transform-runtime#useesmodules
172 | // We should turn this on once the lowest version of Node LTS
173 | // supports ES Modules.
174 | useESModules,
175 | // Undocumented option that lets us encapsulate our runtime, ensuring
176 | // the correct version is used
177 | // https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src/index.js#L35-L42
178 | absoluteRuntime: absoluteRuntimePath,
179 | },
180 | ],
181 | isEnvProduction && [
182 | // Remove PropTypes from production build
183 | require('babel-plugin-transform-react-remove-prop-types').default,
184 | {
185 | removeImport: true,
186 | },
187 | ],
188 | // function* () { yield 42; yield 43; }
189 | !(isEnvTest || isEnvNode) && [
190 | require('@babel/plugin-transform-regenerator').default,
191 | {
192 | // Async functions are converted to generators by @babel/preset-env
193 | async: false,
194 | },
195 | ],
196 | // Adds syntax support for import()
197 | require('@babel/plugin-syntax-dynamic-import').default,
198 | (isEnvTest || isEnvNode) &&
199 | // Transform dynamic import to require
200 | require('babel-plugin-dynamic-import-node'),
201 | ].filter(Boolean),
202 | overrides: [
203 | isFlowEnabled && {
204 | exclude: /\.tsx?$/,
205 | plugins: [require('@babel/plugin-transform-flow-strip-types').default],
206 | },
207 | isTypeScriptEnabled && {
208 | test: /\.tsx?$/,
209 | plugins: [
210 | [
211 | require('@babel/plugin-proposal-decorators').default,
212 | { legacy: true },
213 | ],
214 | ],
215 | },
216 | ].filter(Boolean),
217 | };
218 | };
219 |
--------------------------------------------------------------------------------
/packages/react-app-tools/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 = Object.keys(raw).reduce((env, key) => {
92 | env[`process.env.${key}`] = JSON.stringify(raw[key]);
93 | return env;
94 | }, {});
95 |
96 | return { raw, stringified };
97 | }
98 |
99 | module.exports = getClientEnvironment;
100 |
--------------------------------------------------------------------------------
/packages/react-app-tools/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')],
14 | caller: { name: 'jest', target: 'node' },
15 | configFile: false,
16 | });
17 |
--------------------------------------------------------------------------------
/packages/react-app-tools/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 |
--------------------------------------------------------------------------------
/packages/react-app-tools/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/en/webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | const assetFilename = JSON.stringify(path.basename(filename));
11 |
12 | if (filename.match(/\.svg$/)) {
13 | return `const React = require('react');
14 | module.exports = {
15 | __esModule: true,
16 | default: ${assetFilename},
17 | ReactComponent: React.forwardRef((props, ref) => ({
18 | $$typeof: Symbol.for('react.element'),
19 | type: 'svg',
20 | ref: ref,
21 | key: null,
22 | props: Object.assign({}, props, {
23 | children: ${assetFilename}
24 | })
25 | })),
26 | };`;
27 | }
28 |
29 | return `module.exports = ${assetFilename};`;
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/packages/react-app-tools/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 `
16 | )}
17 |