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 1c154c36164..89cd2059cd7 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: @@ -79,6 +81,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 d875c63e8d9..c2b544cca54 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -12,7 +12,6 @@ var path = require('path'); var autoprefixer = require('autoprefixer'); var webpack = require('webpack'); -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'); @@ -122,12 +121,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 } }, // "postcss" loader applies autoprefixer to our CSS. diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 58bb4ab1d06..b4cad963979 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-preset-react-app": "^1.0.0", "case-sensitive-paths-webpack-plugin": "1.1.4", "chalk": "1.1.3", @@ -46,7 +46,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 8723c281637..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(); } @@ -195,6 +199,8 @@ function addMiddleware(devServer) { function runDevServer(host, port, protocol) { var devServer = new WebpackDevServer(compiler, { + // Enable gzip compression of generated files. + compress: true, // Silence WebpackDevServer's own logs since they're generally not useful. // It will still show compile warnings and errors with this setting. clientLogLevel: 'none', 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 Logo; } -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 39c864ab8f4..df0238f2587 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') }, setupFiles: [resolve('config/polyfills.js')], 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