diff --git a/.travis.yml b/.travis.yml
index 75383b87806..ec44c3294da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,3 +9,6 @@ cache:
- packages/create-react-app/node_modules
- packages/react-scripts/node_modules
script: tasks/e2e.sh
+env:
+ - USE_YARN=no
+ - USE_YARN=yes
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index 2bcdd77dc36..374dbf17958 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -1,5 +1,25 @@
If you are reporting a bug, please fill in below. Otherwise feel free to remove this template entirely.
+### Can you reproduce the problem with latest npm?
+
+Many errors, especially related to "missing modules", are due to npm bugs.
+
+If you're using Windows, [follow these instructions to update npm](https://github.com/npm/npm/wiki/Troubleshooting#upgrading-on-windows).
+
+If you're using OS X or Linux, run this to update npm:
+
+```
+npm install -g npm@latest
+
+cd your_project_directory
+rm -rf node_modules
+npm install
+```
+
+Then try to reproduce the issue again.
+
+Can you still reproduce it?
+
### Description
What are you reporting?
diff --git a/README.md b/README.md
index 334dd477e85..df0046aa39a 100644
--- a/README.md
+++ b/README.md
@@ -205,6 +205,8 @@ Some of the more popular and actively maintained ones are:
* [insin/nwb](https://github.com/insin/nwb)
* [mozilla/neo](https://github.com/mozilla/neo)
* [NYTimes/kyt](https://github.com/NYTimes/kyt)
+* [zeit/next.js](https://github.com/zeit/next.js)
+* [gatsbyjs/gatsby](https://github.com/gatsbyjs/gatsby)
Notable alternatives also include:
diff --git a/packages/babel-preset-react-app/index.js b/packages/babel-preset-react-app/index.js
index d6e9c4519d4..a2639c6d4cf 100644
--- a/packages/babel-preset-react-app/index.js
+++ b/packages/babel-preset-react-app/index.js
@@ -27,15 +27,7 @@ const plugins = [
regenerator: true,
// Resolve the Babel runtime relative to the config.
moduleName: path.dirname(require.resolve('babel-runtime/package'))
- }],
- // The following two plugins are currently necessary to get
- // babel-preset-env to work with rest/spread. More info here:
- // https://github.com/babel/babel-preset-env#caveats
- // https://github.com/babel/babel/issues/4074
- // const { a, ...z } = obj;
- require.resolve('babel-plugin-transform-es2015-destructuring'),
- // const fn = ({ a, ...otherProps }) => otherProps;
- require.resolve('babel-plugin-transform-es2015-parameters')
+ }]
];
// This is similar to how `env` works in Babel:
@@ -54,6 +46,12 @@ if (env !== 'development' && env !== 'test' && env !== 'production') {
}
if (env === 'development' || env === 'test') {
+ // The following two plugins are currently necessary to make React warnings
+ // include more valuable information. They are included here because they are
+ // currently not enabled in babel-preset-react. See the below threads for more info:
+ // https://github.com/babel/babel/issues/4702
+ // https://github.com/babel/babel/pull/3540#issuecomment-228673661
+ // https://github.com/facebookincubator/create-react-app/issues/989
plugins.push.apply(plugins, [
// Adds component stack to warning messages
require.resolve('babel-plugin-transform-react-jsx-source'),
@@ -68,7 +66,7 @@ if (env === 'test') {
// ES features necessary for user's Node version
[require('babel-preset-env').default, {
targets: {
- node: parseFloat(process.versions.node),
+ node: 'current',
},
}],
// JSX, Flow
@@ -99,4 +97,3 @@ if (env === 'test') {
// ]);
}
}
-
diff --git a/packages/babel-preset-react-app/package.json b/packages/babel-preset-react-app/package.json
index bba2df1e0b1..13f00ed227d 100644
--- a/packages/babel-preset-react-app/package.json
+++ b/packages/babel-preset-react-app/package.json
@@ -12,15 +12,13 @@
],
"dependencies": {
"babel-plugin-transform-class-properties": "6.16.0",
- "babel-plugin-transform-es2015-destructuring": "6.16.0",
- "babel-plugin-transform-es2015-parameters": "6.17.0",
- "babel-plugin-transform-object-rest-spread": "6.16.0",
+ "babel-plugin-transform-object-rest-spread": "6.19.0",
"babel-plugin-transform-react-constant-elements": "6.9.1",
"babel-plugin-transform-react-jsx-self": "6.11.0",
"babel-plugin-transform-react-jsx-source": "6.9.0",
"babel-plugin-transform-regenerator": "6.16.1",
"babel-plugin-transform-runtime": "6.15.0",
- "babel-preset-env": "0.0.6",
+ "babel-preset-env": "0.0.8",
"babel-preset-latest": "6.16.0",
"babel-preset-react": "6.16.0",
"babel-runtime": "6.11.6"
diff --git a/packages/create-react-app/index.js b/packages/create-react-app/index.js
index d6478a13545..23d8b5e8dea 100644
--- a/packages/create-react-app/index.js
+++ b/packages/create-react-app/index.js
@@ -101,26 +101,54 @@ function createApp(name, verbose, version) {
process.chdir(root);
console.log('Installing packages. This might take a couple minutes.');
- console.log('Installing react-scripts from npm...');
+ console.log('Installing react-scripts...');
console.log();
run(root, appName, version, verbose, originalDirectory);
}
-function run(root, appName, version, verbose, originalDirectory) {
- var installPackage = getInstallPackage(version);
- var packageName = getPackageName(installPackage);
+function install(packageToInstall, verbose, callback) {
var args = [
- 'install',
- verbose && '--verbose',
- '--save-dev',
- '--save-exact',
- installPackage,
- ].filter(function(e) { return e; });
- var proc = spawn('npm', args, {stdio: 'inherit'});
+ 'add',
+ '--dev',
+ '--exact',
+ packageToInstall,
+ ];
+ var proc = spawn('yarn', args, {stdio: 'inherit'});
+
+ var yarnExists = true;
+ proc.on('error', function (err) {
+ if (err.code === 'ENOENT') {
+ yarnExists = false;
+ }
+ });
proc.on('close', function (code) {
+ if (yarnExists) {
+ callback(code, 'yarn', args);
+ return;
+ }
+ // No Yarn installed, continuing with npm.
+ args = [
+ 'install',
+ verbose && '--verbose',
+ '--save-dev',
+ '--save-exact',
+ packageToInstall,
+ ].filter(function(e) { return e; });
+ var npmProc = spawn('npm', args, {stdio: 'inherit'});
+ npmProc.on('close', function (code) {
+ callback(code, 'npm', args);
+ });
+ });
+}
+
+function run(root, appName, version, verbose, originalDirectory) {
+ var packageToInstall = getInstallPackage(version);
+ var packageName = getPackageName(packageToInstall);
+
+ install(packageToInstall, verbose, function (code, command, args) {
if (code !== 0) {
- console.error('`npm ' + args.join(' ') + '` failed');
+ console.error('`' + command + ' ' + args.join(' ') + '` failed');
return;
}
diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js
index f2f79a2dcc1..6df5bfdd93b 100644
--- a/packages/eslint-config-react-app/index.js
+++ b/packages/eslint-config-react-app/index.js
@@ -44,7 +44,7 @@ module.exports = {
settings: {
'import/ignore': [
'node_modules',
- '\\.(json|css|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$',
+ '\\.(json|css|ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$',
],
'import/extensions': ['.js'],
'import/resolver': {
diff --git a/packages/react-dev-utils/openBrowser.js b/packages/react-dev-utils/openBrowser.js
index 76b33a5924a..bee85a7d299 100644
--- a/packages/react-dev-utils/openBrowser.js
+++ b/packages/react-dev-utils/openBrowser.js
@@ -28,7 +28,7 @@ function openBrowser(url) {
// Fallback to opn
// (It will always open new tab)
try {
- opn(url);
+ opn(url).catch(() => {}); // Prevent `unhandledRejection` error.
return true;
} catch (err) {
return false;
diff --git a/packages/react-dev-utils/openChrome.applescript b/packages/react-dev-utils/openChrome.applescript
index 4dfec4a2657..b36b70f6cfc 100644
--- a/packages/react-dev-utils/openChrome.applescript
+++ b/packages/react-dev-utils/openChrome.applescript
@@ -23,7 +23,7 @@ on run argv
set theTabIndex to 0
repeat with theTab in every tab of theWindow
set theTabIndex to theTabIndex + 1
- if theTab's URL is theURL then
+ if theTab's URL as string contains theURL then
set found to true
exit repeat
end if
@@ -38,6 +38,7 @@ on run argv
tell theTab to reload
set index of theWindow to 1
set theWindow's active tab index to theTabIndex
+ tell theWindow to activate
else
tell window 1
activate
diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json
index 14c860999ae..1fe5c556c79 100644
--- a/packages/react-dev-utils/package.json
+++ b/packages/react-dev-utils/package.json
@@ -29,8 +29,5 @@
"opn": "4.0.2",
"sockjs-client": "1.0.3",
"strip-ansi": "3.0.1"
- },
- "peerDependencies": {
- "webpack": "^1.13.2"
}
}
diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js
index c5e22ff7078..e99975c33fb 100644
--- a/packages/react-scripts/config/paths.js
+++ b/packages/react-scripts/config/paths.js
@@ -43,6 +43,7 @@ module.exports = {
appIndexJs: resolveApp('src/index.js'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
+ yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveApp('src/setupTests.js'),
appNodeModules: resolveApp('node_modules'),
ownNodeModules: resolveApp('node_modules'),
@@ -62,6 +63,7 @@ module.exports = {
appIndexJs: resolveApp('src/index.js'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
+ yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveApp('src/setupTests.js'),
appNodeModules: resolveApp('node_modules'),
// this is empty with npm3 but node resolution searches higher anyway:
@@ -80,6 +82,7 @@ if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1)
appIndexJs: resolveOwn('../template/src/index.js'),
appPackageJson: resolveOwn('../package.json'),
appSrc: resolveOwn('../template/src'),
+ yarnLockFile: resolveOwn('../template/yarn.lock'),
testsSetup: resolveOwn('../template/src/setupTests.js'),
appNodeModules: resolveOwn('../node_modules'),
ownNodeModules: resolveOwn('../node_modules'),
diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js
index b7388fb44f4..5d091241cb0 100644
--- a/packages/react-scripts/config/webpack.config.dev.js
+++ b/packages/react-scripts/config/webpack.config.dev.js
@@ -15,7 +15,6 @@ var webpack = require('webpack');
var nesting = require('postcss-nesting');
var cssvariables = require('postcss-css-variables');
var values = require('postcss-modules-values');
-var findCacheDir = require('find-cache-dir');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
@@ -125,12 +124,9 @@ module.exports = {
presets: [require.resolve('babel-preset-react-app')],
// @remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
- // It enables caching results in ./node_modules/.cache/react-scripts/
- // directory for faster rebuilds. We use findCacheDir() because of:
- // https://github.com/facebookincubator/create-react-app/issues/483
- cacheDirectory: findCacheDir({
- name: 'react-scripts'
- })
+ // It enables caching results in ./node_modules/.cache/babel-loader/
+ // directory for faster rebuilds.
+ cacheDirectory: true
}
},
{
diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json
index 48aa7bb2fb2..fe591cc3d09 100644
--- a/packages/react-scripts/package.json
+++ b/packages/react-scripts/package.json
@@ -27,7 +27,7 @@
"babel-core": "6.17.0",
"babel-eslint": "7.0.0",
"babel-jest": "16.0.0",
- "babel-loader": "6.2.5",
+ "babel-loader": "6.2.7",
"babel-plugin-transform-remove-console": "^6.8.0",
"babel-preset-react-app": "^1.0.0",
"case-sensitive-paths-webpack-plugin": "1.1.4",
@@ -48,7 +48,6 @@
"extract-text-webpack-plugin": "1.0.1",
"file-loader": "0.9.0",
"filesize": "3.3.0",
- "find-cache-dir": "0.1.1",
"fs-extra": "0.30.0",
"gzip-size": "3.0.0",
"html-webpack-plugin": "2.24.0",
diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js
index d0b92f6a73b..8b1cd4cc48f 100644
--- a/packages/react-scripts/scripts/build.js
+++ b/packages/react-scripts/scripts/build.js
@@ -21,6 +21,7 @@ require('dotenv').config({silent: true});
var chalk = require('chalk');
var fs = require('fs-extra');
var path = require('path');
+var pathExists = require('path-exists');
var filesize = require('filesize');
var gzipSize = require('gzip-size').sync;
var rimrafSync = require('rimraf').sync;
@@ -31,6 +32,8 @@ var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
var recursive = require('recursive-readdir');
var stripAnsi = require('strip-ansi');
+var useYarn = pathExists.sync(paths.yarnLockFile);
+
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
@@ -161,7 +164,11 @@ function build(previousSizeMap) {
console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.');
console.log('To publish it at ' + chalk.green(homepagePath) + ', run:');
console.log();
- console.log(' ' + chalk.cyan('npm') + ' install --save-dev gh-pages');
+ if (useYarn) {
+ console.log(' ' + chalk.cyan('yarn') + ' add gh-pages');
+ } else {
+ console.log(' ' + chalk.cyan('npm') + ' install --save-dev gh-pages');
+ }
console.log();
console.log('Add the following script in your ' + chalk.cyan('package.json') + '.');
console.log();
@@ -173,7 +180,7 @@ function build(previousSizeMap) {
console.log();
console.log('Then run:');
console.log();
- console.log(' ' + chalk.cyan('npm') + ' run deploy');
+ console.log(' ' + chalk.cyan(useYarn ? 'yarn' : 'npm') + ' run deploy');
console.log();
} else if (publicPath !== '/') {
// "homepage": "http://mywebsite.com/project"
@@ -200,7 +207,11 @@ function build(previousSizeMap) {
console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.');
console.log('You may also serve it locally with a static server:')
console.log();
- console.log(' ' + chalk.cyan('npm') + ' install -g pushstate-server');
+ if (useYarn) {
+ console.log(' ' + chalk.cyan('yarn') + ' global add pushstate-server');
+ } else {
+ console.log(' ' + chalk.cyan('npm') + ' install -g pushstate-server');
+ }
console.log(' ' + chalk.cyan('pushstate-server') + ' build');
console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000');
console.log();
diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js
index d14aec6abef..7d4996665ec 100644
--- a/packages/react-scripts/scripts/eject.js
+++ b/packages/react-scripts/scripts/eject.js
@@ -10,6 +10,8 @@
var createJestConfig = require('../utils/createJestConfig');
var fs = require('fs');
var path = require('path');
+var pathExists = require('path-exists');
+var paths = require('../config/paths');
var prompt = require('react-dev-utils/prompt');
var rimrafSync = require('rimraf').sync;
var spawnSync = require('cross-spawn').sync;
@@ -30,6 +32,25 @@ prompt(
var ownPath = path.join(__dirname, '..');
var appPath = path.join(ownPath, '..', '..');
+
+ function verifyAbsent(file) {
+ if (fs.existsSync(path.join(appPath, file))) {
+ console.error(
+ '`' + file + '` already exists in your app folder. We cannot ' +
+ 'continue as you would lose all the changes in that file or directory. ' +
+ 'Please move or delete it (maybe make a copy for backup) and run this ' +
+ 'command again.'
+ );
+ process.exit(1);
+ }
+ }
+
+ var folders = [
+ 'config',
+ path.join('config', 'jest'),
+ 'scripts'
+ ];
+
var files = [
path.join('config', 'env.js'),
path.join('config', 'paths.js'),
@@ -44,22 +65,13 @@ prompt(
];
// Ensure that the app folder is clean and we won't override any files
- files.forEach(function(file) {
- if (fs.existsSync(path.join(appPath, file))) {
- console.error(
- '`' + file + '` already exists in your app folder. We cannot ' +
- 'continue as you would lose all the changes in that file or directory. ' +
- 'Please delete it (maybe make a copy for backup) and run this ' +
- 'command again.'
- );
- process.exit(1);
- }
- });
+ folders.forEach(verifyAbsent);
+ files.forEach(verifyAbsent);
// Copy the files over
- fs.mkdirSync(path.join(appPath, 'config'));
- fs.mkdirSync(path.join(appPath, 'config', 'jest'));
- fs.mkdirSync(path.join(appPath, 'scripts'));
+ folders.forEach(function(folder) {
+ fs.mkdirSync(path.join(appPath, folder))
+ });
console.log();
console.log(cyan('Copying files into ' + appPath));
@@ -133,9 +145,15 @@ prompt(
);
console.log();
- console.log(cyan('Running npm install...'));
- rimrafSync(ownPath);
- spawnSync('npm', ['install'], {stdio: 'inherit'});
+ if (pathExists.sync(paths.yarnLockFile)) {
+ console.log(cyan('Running yarn...'));
+ rimrafSync(ownPath);
+ spawnSync('yarn', [], {stdio: 'inherit'});
+ } else {
+ console.log(cyan('Running npm install...'));
+ rimrafSync(ownPath);
+ spawnSync('npm', ['install'], {stdio: 'inherit'});
+ }
console.log(green('Ejected successfully!'));
console.log();
diff --git a/packages/react-scripts/scripts/init.js b/packages/react-scripts/scripts/init.js
index fa42f6dcee6..c9a4ea14ac4 100644
--- a/packages/react-scripts/scripts/init.js
+++ b/packages/react-scripts/scripts/init.js
@@ -17,6 +17,7 @@ module.exports = function(appPath, appName, verbose, originalDirectory) {
var ownPackageName = require(path.join(__dirname, '..', 'package.json')).name;
var ownPath = path.join(appPath, 'node_modules', ownPackageName);
var appPackage = require(path.join(appPath, 'package.json'));
+ var useYarn = pathExists.sync(path.join(appPath, 'yarn.lock'));
// Copy over some of the devDependencies
appPackage.dependencies = appPackage.dependencies || {};
@@ -58,21 +59,31 @@ module.exports = function(appPath, appName, verbose, originalDirectory) {
}
});
- // Run another npm install for react and react-dom
- console.log('Installing react and react-dom from npm...');
+ // Run yarn or npm for react and react-dom
+ // TODO: having to do two npm/yarn installs is bad, can we avoid it?
+ var command;
+ var args;
+
+ if (useYarn) {
+ command = 'yarn';
+ args = ['add'];
+ } else {
+ command = 'npm';
+ args = [
+ 'install',
+ '--save',
+ verbose && '--verbose'
+ ].filter(function(e) { return e; });
+ }
+ args.push('react', 'react-dom');
+
+ console.log('Installing react and react-dom using ' + command + '...');
console.log();
- // TODO: having to do two npm installs is bad, can we avoid it?
- var args = [
- 'install',
- 'react',
- 'react-dom',
- '--save',
- verbose && '--verbose'
- ].filter(function(e) { return e; });
- var proc = spawn('npm', args, {stdio: 'inherit'});
+
+ var proc = spawn(command, args, {stdio: 'inherit'});
proc.on('close', function (code) {
if (code !== 0) {
- console.error('`npm ' + args.join(' ') + '` failed');
+ console.error('`' + command + ' ' + args.join(' ') + '` failed');
return;
}
@@ -91,23 +102,23 @@ module.exports = function(appPath, appName, verbose, originalDirectory) {
console.log('Success! Created ' + appName + ' at ' + appPath);
console.log('Inside that directory, you can run several commands:');
console.log();
- console.log(chalk.cyan(' npm start'));
+ console.log(chalk.cyan(' ' + command + ' start'));
console.log(' Starts the development server.');
console.log();
- console.log(chalk.cyan(' npm run build'));
+ console.log(chalk.cyan(' ' + command + ' run build'));
console.log(' Bundles the app into static files for production.');
console.log();
- console.log(chalk.cyan(' npm test'));
+ console.log(chalk.cyan(' ' + command + ' test'));
console.log(' Starts the test runner.');
console.log();
- console.log(chalk.cyan(' npm run eject'));
+ console.log(chalk.cyan(' ' + command + ' run eject'));
console.log(' Removes this tool and copies build dependencies, configuration files');
console.log(' and scripts into the app directory. If you do this, you can’t go back!');
console.log();
console.log('We suggest that you begin by typing:');
console.log();
console.log(chalk.cyan(' cd'), cdpath);
- console.log(' ' + chalk.cyan('npm start'));
+ console.log(' ' + chalk.cyan(command + ' start'));
if (readmeExists) {
console.log();
console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`'));
diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js
index 8a115dd8e27..5e996c71ddc 100644
--- a/packages/react-scripts/scripts/start.js
+++ b/packages/react-scripts/scripts/start.js
@@ -28,9 +28,13 @@ var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
var openBrowser = require('react-dev-utils/openBrowser');
var prompt = require('react-dev-utils/prompt');
+var pathExists = require('path-exists');
var config = require('../config/webpack.config.dev');
var paths = require('../config/paths');
+var useYarn = pathExists.sync(paths.yarnLockFile);
+var cli = useYarn ? 'yarn' : 'npm';
+
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
@@ -85,7 +89,7 @@ function setupCompiler(host, port, protocol) {
console.log(' ' + chalk.cyan(protocol + '://' + host + ':' + port + '/'));
console.log();
console.log('Note that the development build is not optimized.');
- console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.');
+ console.log('To create a production build, use ' + chalk.cyan(cli + ' run build') + '.');
console.log();
}
diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md
index 6f13b12d2e0..3203c5fcbb9 100644
--- a/packages/react-scripts/template/README.md
+++ b/packages/react-scripts/template/README.md
@@ -320,7 +320,7 @@ function Header() {
return ;
}
-export default function Header;
+export default Header;
```
This ensures that when the project is built, Webpack will correctly move the images into the build folder, and provide us with correct paths.
@@ -881,15 +881,15 @@ This will let Create React App correctly infer the root path to use in the gener
Open your `package.json` and add a `homepage` field:
```js
- "homepage": "http://myusername.github.io/my-app",
+ "homepage": "https://myusername.github.io/my-app",
```
**The above step is important!**
Create React App uses the `homepage` field to determine the root URL in the built HTML file.
-Now, whenever you run `npm run build`, you will see a cheat sheet with instructions on how to deploy to GitHub pages.
+Now, whenever you run `npm run build`, you will see a cheat sheet with instructions on how to deploy to GitHub Pages.
-To publish it at [http://myusername.github.io/my-app](http://myusername.github.io/my-app), run:
+To publish it at [https://myusername.github.io/my-app](https://myusername.github.io/my-app), run:
```sh
npm install --save-dev gh-pages
@@ -901,16 +901,20 @@ Add the following script in your `package.json`:
// ...
"scripts": {
// ...
- "deploy": "gh-pages -d build"
+ "deploy": "npm run build&&gh-pages -d build"
}
```
+(Note: the lack of whitespace is intentional.)
+
Then run:
```sh
npm run deploy
```
+You can configure a custom domain with GitHub Pages by adding a `CNAME` file to the `public/` folder.
+
Note that GitHub Pages doesn't support routers that use the HTML5 `pushState` history API under the hood (for example, React Router using `browserHistory`). This is because when there is a fresh page load for a url like `http://user.github.io/todomvc/todos/42`, where `/todos/42` is a frontend route, the GitHub Pages server returns 404 because it knows nothing of `/todos/42`. If you want to add a router to a project hosted on GitHub Pages, here are a couple of solutions:
* You could switch from using HTML5 history API to routing with hashes. If you use React Router, you can switch to `hashHistory` for this effect, but the URL will be longer and more verbose (for example, `http://user.github.io/todomvc/#/todos/42?_k=yknaj`). [Read more](https://github.com/reactjs/react-router/blob/master/docs/guides/Histories.md#histories) about different history implementations in React Router.
* Alternatively, you can use a trick to teach GitHub Pages to handle 404 by redirecting to your `index.html` page with a special redirect parameter. You would need to add a `404.html` file with the redirection code to the `build` folder before deploying your project, and you’ll need to add code handling the redirect parameter to `index.html`. You can find a detailed explanation of this technique [in this guide](https://github.com/rafrex/spa-github-pages).
diff --git a/packages/react-scripts/utils/createJestConfig.js b/packages/react-scripts/utils/createJestConfig.js
index 94d6b2c34af..4ce8bc1c906 100644
--- a/packages/react-scripts/utils/createJestConfig.js
+++ b/packages/react-scripts/utils/createJestConfig.js
@@ -18,9 +18,10 @@ module.exports = (resolve, rootDir, isEjecting) => {
const setupTestsFile = pathExists.sync(paths.testsSetup) ? '/src/setupTests.js' : undefined;
const config = {
+ collectCoverageFrom: ['src/**/*.{js,jsx}'],
moduleFileExtensions: ['jsx', 'js', 'json'],
moduleNameMapper: {
- '^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': resolve('config/jest/FileStub.js'),
+ '^.+\\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': resolve('config/jest/FileStub.js'),
'^.+\\.css$': resolve('config/jest/CSSStub.js'),
"^.+\\.pcss$": "identity-obj-proxy"
},
diff --git a/tasks/e2e.sh b/tasks/e2e.sh
index 88e1fdf4e20..094fba9e22b 100755
--- a/tasks/e2e.sh
+++ b/tasks/e2e.sh
@@ -53,6 +53,12 @@ set -x
cd ..
root_path=$PWD
+if [ "$USE_YARN" = "yes" ]
+then
+ # Install Yarn so that the test can use it to install packages.
+ npm install -g yarn
+fi
+
npm install
# Lint own code