diff --git a/docusaurus/docs/deployment.md b/docusaurus/docs/deployment.md index f4b257e6003..507628d9bc3 100644 --- a/docusaurus/docs/deployment.md +++ b/docusaurus/docs/deployment.md @@ -167,9 +167,9 @@ The AWS Amplify Console provides continuous deployment and hosting for modern we 1. Login to the Amplify Console [here](https://console.aws.amazon.com/amplify/home). 1. Connect your Create React App repo and pick a branch. If you're looking for a Create React App+Amplify starter, try the [create-react-app-auth-amplify starter](https://github.com/swaminator/create-react-app-auth-amplify) that demonstrates setting up auth in 10 minutes with Create React App. 1. The Amplify Console automatically detects the build settings. Choose Next. -1. Choose *Save and deploy*. +1. Choose _Save and deploy_. -If the build succeeds, the app is deployed and hosted on a global CDN with an amplifyapp.com domain. You can now continuously deploy changes to your frontend or backend. Continuous deployment allows developers to deploy updates to their frontend and backend on every code commit to their Git repository. +If the build succeeds, the app is deployed and hosted on a global CDN with an amplifyapp.com domain. You can now continuously deploy changes to your frontend or backend. Continuous deployment allows developers to deploy updates to their frontend and backend on every code commit to their Git repository. ## [Azure](https://azure.microsoft.com/) diff --git a/docusaurus/docs/getting-started.md b/docusaurus/docs/getting-started.md index ecc99198e03..ab52bc6c7b5 100644 --- a/docusaurus/docs/getting-started.md +++ b/docusaurus/docs/getting-started.md @@ -62,7 +62,6 @@ yarn create react-app my-app _`yarn create` is available in Yarn 0.25+_ - ### Creating a TypeScript app Follow our [Adding TypeScript](adding-typescript.md) documentation to create a TypeScript app. diff --git a/packages/react-scripts/config/modules.js b/packages/react-scripts/config/modules.js new file mode 100644 index 00000000000..b232fe37150 --- /dev/null +++ b/packages/react-scripts/config/modules.js @@ -0,0 +1,92 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +// @remove-on-eject-end +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const paths = require('./paths'); +const chalk = require('react-dev-utils/chalk'); + +/** + * Get the baseUrl of a compilerOptions object. + * + * @param {Object} options + */ +function getAdditionalModulePaths(options = {}) { + const baseUrl = options.baseUrl; + + // We need to explicitly check for null and undefined (and not a falsy value) because + // TypeScript treats an empty string as `.`. + if (baseUrl == null) { + // If there's no baseUrl set we respect NODE_PATH + // Note that NODE_PATH is deprecated and will be removed + // in the next major release of create-react-app. + + const nodePath = process.env.NODE_PATH || ''; + return nodePath.split(path.delimiter).filter(Boolean); + } + + const baseUrlResolved = path.resolve(paths.appPath, baseUrl); + + // We don't need to do anything if `baseUrl` is set to `node_modules`. This is + // the default behavior. + if (path.relative(paths.appNodeModules, baseUrlResolved) === '') { + return null; + } + + // Allow the user set the `baseUrl` to `appSrc`. + if (path.relative(paths.appSrc, baseUrlResolved) === '') { + return [paths.appSrc]; + } + + // Otherwise, throw an error. + throw new Error( + chalk.red.bold( + "Your project's `baseUrl` can only be set to `src` or `node_modules`." + + ' Create React App does not support other values at this time.' + ) + ); +} + +function getModules() { + // Check if TypeScript is setup + const hasTsConfig = fs.existsSync(paths.appTsConfig); + const hasJsConfig = fs.existsSync(paths.appJsConfig); + + if (hasTsConfig && hasJsConfig) { + throw new Error( + 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.' + ); + } + + let config; + + // If there's a tsconfig.json we assume it's a + // TypeScript project and set up the config + // based on tsconfig.json + if (hasTsConfig) { + config = require(paths.appTsConfig); + // Otherwise we'll check if there is jsconfig.json + // for non TS projects. + } else if (hasJsConfig) { + config = require(paths.appJsConfig); + } + + config = config || {}; + const options = config.compilerOptions || {}; + + const additionalModulePaths = getAdditionalModulePaths(options); + + return { + additionalModulePaths: additionalModulePaths, + hasTsConfig, + }; +} + +module.exports = getModules(); diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index b719054583b..e5a3e0b5374 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -84,6 +84,7 @@ module.exports = { appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), + appJsConfig: resolveApp('jsconfig.json'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveModule(resolveApp, 'src/setupTests'), proxySetup: resolveApp('src/setupProxy.js'), @@ -106,6 +107,7 @@ module.exports = { appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), + appJsConfig: resolveApp('jsconfig.json'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveModule(resolveApp, 'src/setupTests'), proxySetup: resolveApp('src/setupProxy.js'), @@ -140,6 +142,7 @@ if ( appPackageJson: resolveOwn('package.json'), appSrc: resolveOwn('template/src'), appTsConfig: resolveOwn('template/tsconfig.json'), + appJsConfig: resolveOwn('template/jsconfig.json'), yarnLockFile: resolveOwn('template/yarn.lock'), testsSetup: resolveModule(resolveOwn, 'template/src/setupTests'), proxySetup: resolveOwn('template/src/setupProxy.js'), diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 42004dc7f6c..a0ba6c6306e 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -28,6 +28,7 @@ const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeM const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const paths = require('./paths'); +const modules = require('./modules'); const getClientEnvironment = require('./env'); const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); @@ -268,10 +269,7 @@ module.exports = function(webpackEnv) { // We placed these paths second because we want `node_modules` to "win" // if there are any conflicts. This matches Node resolution mechanism. // https://github.com/facebook/create-react-app/issues/253 - modules: ['node_modules', paths.appNodeModules].concat( - // It is guaranteed to exist because we tweak it in `env.js` - process.env.NODE_PATH.split(path.delimiter).filter(Boolean) - ), + modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []), // These are the reasonable defaults supported by the Node ecosystem. // We also include JSX as a common component filename extension to support // some tools, although we do not recommend using it, see: diff --git a/packages/react-scripts/fixtures/kitchensink/integration/config.test.js b/packages/react-scripts/fixtures/kitchensink/integration/config.test.js new file mode 100644 index 00000000000..6d09b56c481 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/integration/config.test.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import initDOM from './initDOM'; + +describe('Integration', () => { + describe('jsconfig.json/tsconfig.json', () => { + it('Supports setting baseUrl to src', async () => { + const doc = await initDOM('base-url'); + + expect(doc.getElementById('feature-base-url').childElementCount).toBe(4); + doc.defaultView.close(); + }); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js index f86a09d52f6..7181c2fa78d 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js @@ -43,12 +43,6 @@ describe('Integration', () => { } }); - it('NODE_PATH', async () => { - doc = await initDOM('node-path'); - - expect(doc.getElementById('feature-node-path').childElementCount).toBe(4); - }); - it('PUBLIC_URL', async () => { doc = await initDOM('public-url'); diff --git a/packages/react-scripts/fixtures/kitchensink/jsconfig.json b/packages/react-scripts/fixtures/kitchensink/jsconfig.json new file mode 100644 index 00000000000..ec2332eb49c --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/jsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "baseUrl": "src" + } +} diff --git a/packages/react-scripts/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index 547138832f3..457b552601d 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -166,9 +166,6 @@ class App extends Component { this.setFeature(f.default) ); break; - case 'node-path': - import('./features/env/NodePath').then(f => this.setFeature(f.default)); - break; case 'no-ext-inclusion': import('./features/webpack/NoExtInclusion').then(f => this.setFeature(f.default) @@ -239,6 +236,11 @@ class App extends Component { this.setFeature(f.default) ); break; + case 'base-url': + import('./features/config/BaseUrl').then(f => + this.setFeature(f.default) + ); + break; default: this.setState({ error: `Missing feature "${feature}"` }); } diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js b/packages/react-scripts/fixtures/kitchensink/src/features/config/BaseUrl.js similarity index 95% rename from packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js rename to packages/react-scripts/fixtures/kitchensink/src/features/config/BaseUrl.js index e89228e20b0..818d4db271b 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/features/env/NodePath.js +++ b/packages/react-scripts/fixtures/kitchensink/src/features/config/BaseUrl.js @@ -30,7 +30,7 @@ export default class extends Component { render() { return ( -