diff --git a/config/paths.js b/config/paths.js
index 1d50c38b9f8..1c154c36164 100644
--- a/config/paths.js
+++ b/config/paths.js
@@ -70,17 +70,18 @@ module.exports = {
};
// @remove-on-eject-end
-// @remove-on-publish-begin
-module.exports = {
- appBuild: resolveOwn('../../../build'),
- appPublic: resolveOwn('../template/public'),
- appHtml: resolveOwn('../template/public/index.html'),
- appIndexJs: resolveOwn('../template/src/index.js'),
- appPackageJson: resolveOwn('../package.json'),
- appSrc: resolveOwn('../template/src'),
- testsSetup: resolveOwn('../template/src/setupTests.js'),
- appNodeModules: resolveOwn('../node_modules'),
- ownNodeModules: resolveOwn('../node_modules'),
- nodePaths: nodePaths
-};
-// @remove-on-publish-end
+// config before publish: we're in ./packages/react-scripts/config/
+if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) {
+ module.exports = {
+ appBuild: resolveOwn('../../../build'),
+ appPublic: resolveOwn('../template/public'),
+ appHtml: resolveOwn('../template/public/index.html'),
+ appIndexJs: resolveOwn('../template/src/index.js'),
+ appPackageJson: resolveOwn('../package.json'),
+ appSrc: resolveOwn('../template/src'),
+ testsSetup: resolveOwn('../template/src/setupTests.js'),
+ appNodeModules: resolveOwn('../node_modules'),
+ ownNodeModules: resolveOwn('../node_modules'),
+ nodePaths: nodePaths
+ };
+}
diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js
index cd5e27df6fb..ad5a699daf1 100644
--- a/config/webpack.config.dev.js
+++ b/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');
@@ -126,12 +125,9 @@ module.exports = {
plugins: [].concat(customConfig.babelPlugins),
// @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.
@@ -141,7 +137,7 @@ module.exports = {
// in development "style" loader enables hot editing of CSS.
{
test: /\.css$/,
- loader: customConfig.values.CSS_MODULES ? customConfig.values.CSS_MODULES.dev : 'style!css!postcss'
+ loader: customConfig.values.CSS_MODULES ? customConfig.values.CSS_MODULES.dev : 'style!css?importLoaders=1!postcss'
},
// JSON is not enabled by default in Webpack but both Node and Browserify
// allow it implicitly so we also enable it.
@@ -179,7 +175,7 @@ module.exports = {
},
// @remove-on-eject-end
// We use PostCSS for autoprefixing only.
- postcss: function () {
+ postcss: function() {
return [
autoprefixer({
browsers: [
diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js
index 8c11bae02b8..a316e75cd23 100644
--- a/config/webpack.config.prod.js
+++ b/config/webpack.config.prod.js
@@ -14,6 +14,7 @@ var autoprefixer = require('autoprefixer');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
+var ManifestPlugin = require('webpack-manifest-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
var url = require('url');
var paths = require('./paths');
@@ -153,10 +154,9 @@ module.exports = {
// Webpack 1.x uses Uglify plugin as a signal to minify *all* the assets
// including CSS. This is confusing and will be removed in Webpack 2:
// https://github.com/webpack/webpack/issues/283
- loader: ExtractTextPlugin.extract(customConfig.values.CSS_MODULES ? 'style!css?modules&-autoprefixer&importLoaders=1!postcss' : 'style!css?-autoprefixer!postcss')
+ loader: ExtractTextPlugin.extract(customConfig.values.CSS_MODULES ? 'style!css?modules&-autoprefixer&importLoaders=1!postcss' : 'style!css?importLoaders=1&-autoprefixer!postcss')
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
-
// JSON is not enabled by default in Webpack but both Node and Browserify
// allow it implicitly so we also enable it.
{
@@ -194,7 +194,7 @@ module.exports = {
},
// @remove-on-eject-end
// We use PostCSS for autoprefixing only.
- postcss: function () {
+ postcss: function() {
return [
autoprefixer({
browsers: [
@@ -255,7 +255,13 @@ module.exports = {
}
}),
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
- new ExtractTextPlugin('static/css/[name].[contenthash:8].css')
+ new ExtractTextPlugin('static/css/[name].[contenthash:8].css'),
+ // Generate a manifest file which contains a mapping of all asset filenames
+ // to their corresponding output file so that tools can pick it up without
+ // having to parse `index.html`.
+ new ManifestPlugin({
+ fileName: 'asset-manifest.json'
+ })
].concat(customConfig.plugins),
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
diff --git a/package.json b/package.json
index 4a2dd1febb0..6d8e38e3d63 100644
--- a/package.json
+++ b/package.json
@@ -23,46 +23,45 @@
"react-scripts": "./bin/react-scripts.js"
},
"dependencies": {
- "autoprefixer": "6.4.1",
- "babel-core": "6.14.0",
- "babel-eslint": "6.1.2",
- "babel-jest": "15.0.0",
- "babel-loader": "6.2.5",
- "babel-plugin-transform-decorators-legacy": "^1.3.4",
- "babel-preset-react-app": "^0.2.1",
+ "autoprefixer": "6.5.1",
+ "babel-core": "6.17.0",
+ "babel-eslint": "7.0.0",
+ "babel-jest": "16.0.0",
+ "babel-loader": "6.2.7",
+ "babel-preset-react-app": "^1.0.0",
"babel-preset-stage-0": "^6.5.0",
+ "babel-plugin-transform-decorators-legacy": "^1.3.4",
"case-sensitive-paths-webpack-plugin": "1.1.4",
"chalk": "1.1.3",
"connect-history-api-fallback": "1.3.0",
- "cross-spawn": "4.0.0",
- "css-loader": "0.24.0",
- "detect-port": "1.0.0",
+ "cross-spawn": "4.0.2",
+ "css-loader": "0.25.0",
+ "detect-port": "1.0.1",
"dotenv": "2.0.0",
- "eslint": "3.5.0",
- "eslint-config-react-app": "^0.2.1",
- "eslint-loader": "1.5.0",
- "eslint-plugin-flowtype": "2.18.1",
- "eslint-plugin-import": "1.12.0",
- "eslint-plugin-jsx-a11y": "2.2.2",
- "eslint-plugin-react": "6.3.0",
+ "eslint": "3.8.1",
+ "eslint-config-react-app": "^0.3.0",
+ "eslint-loader": "1.6.0",
+ "eslint-plugin-flowtype": "2.21.0",
+ "eslint-plugin-import": "2.0.1",
+ "eslint-plugin-jsx-a11y": "2.2.3",
+ "eslint-plugin-react": "6.4.1",
"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.22.0",
- "http-proxy-middleware": "0.17.1",
- "jest": "15.1.1",
+ "html-webpack-plugin": "2.24.0",
+ "http-proxy-middleware": "0.17.2",
+ "jest": "16.0.2",
"json-loader": "0.5.4",
"less": "^2.7.1",
"less-loader": "^2.2.3",
"node-sass": "^3.10.0",
"object-assign": "4.1.0",
"path-exists": "2.1.0",
- "postcss-loader": "0.13.0",
+ "postcss-loader": "1.0.0",
"promise": "7.1.1",
- "react-dev-utils": "^0.2.1",
+ "react-dev-utils": "^0.3.0",
"recursive-readdir": "2.1.0",
"rimraf": "2.5.4",
"sass-loader": "^4.0.2",
@@ -72,7 +71,8 @@
"stylus-loader": "^2.3.1",
"url-loader": "0.5.7",
"webpack": "1.13.2",
- "webpack-dev-server": "1.16.1",
+ "webpack-dev-server": "1.16.2",
+ "webpack-manifest-plugin": "1.1.0",
"whatwg-fetch": "1.0.0"
},
"devDependencies": {
@@ -134,6 +134,7 @@
"url-loader",
"webpack",
"webpack-dev-server",
+ "webpack-manifest-plugin",
"whatwg-fetch"
]
}
diff --git a/scripts/build.js b/scripts/build.js
index 4c61dc93ba7..d0b92f6a73b 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -118,13 +118,27 @@ function printFileSizes(stats, previousSizeMap) {
});
}
+// Print out errors
+function printErrors(summary, errors) {
+ console.log(chalk.red(summary));
+ console.log();
+ errors.forEach(err => {
+ console.log(err.message || err);
+ console.log();
+ });
+}
+
// Create the production build and print the deployment instructions.
function build(previousSizeMap) {
console.log('Creating an optimized production build...');
webpack(config).run((err, stats) => {
if (err) {
- console.error('Failed to create a production build. Reason:');
- console.error(err.message || err);
+ printErrors('Failed to compile.', [err]);
+ process.exit(1);
+ }
+
+ if (stats.compilation.errors.length) {
+ printErrors('Failed to compile.', stats.compilation.errors);
process.exit(1);
}
diff --git a/scripts/eject.js b/scripts/eject.js
index be1350e6e3c..5e7c568b572 100644
--- a/scripts/eject.js
+++ b/scripts/eject.js
@@ -30,6 +30,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', 'customizers.js'),
path.join('config', 'env.js'),
@@ -46,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));
diff --git a/scripts/start.js b/scripts/start.js
index 53877dd6a32..f887dd20407 100644
--- a/scripts/start.js
+++ b/scripts/start.js
@@ -195,6 +195,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/template/README.md b/template/README.md
index 13f63c2e23f..3203c5fcbb9 100644
--- a/template/README.md
+++ b/template/README.md
@@ -174,7 +174,7 @@ Then add this block to the `package.json` file of your project:
Finally, you will need to install some packages *globally*:
```sh
-npm install -g eslint-config-react-app@0.2.1 eslint@3.5.0 babel-eslint@6.1.2 eslint-plugin-react@6.3.0 eslint-plugin-import@1.12.0 eslint-plugin-jsx-a11y@2.2.2 eslint-plugin-flowtype@2.18.1
+npm install -g eslint-config-react-app@0.3.0 eslint@3.8.1 babel-eslint@7.0.0 eslint-plugin-react@6.4.1 eslint-plugin-import@2.0.1 eslint-plugin-jsx-a11y@2.2.3 eslint-plugin-flowtype@2.21.0
```
We recognize that this is suboptimal, but it is currently required due to the way we hide the ESLint dependency. The ESLint team is already [working on a solution to this](https://github.com/eslint/eslint/issues/3458) so this may become unnecessary in a couple of months.
@@ -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.
@@ -444,6 +444,8 @@ default you will have `NODE_ENV` defined for you, and any other environment vari
variable named `REACT_APP_SECRET_CODE` will be exposed in your JS as `process.env.REACT_APP_SECRET_CODE`, in addition
to `process.env.NODE_ENV`.
+>Note: Changing any environment variables will require you to restart the development server if it is running.
+
These environment variables can be useful for displaying information conditionally based on where the project is
deployed or consuming sensitive data that lives outside of version control.
@@ -800,8 +802,8 @@ node_js:
- 6
cache:
directories:
- - node_modules
-script
+ - node_modules
+script:
- npm test
```
1. Trigger your first build with a git push.
@@ -879,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
@@ -899,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/utils/createJestConfig.js b/utils/createJestConfig.js
index 7eb9f9775c1..df0238f2587 100644
--- a/utils/createJestConfig.js
+++ b/utils/createJestConfig.js
@@ -18,16 +18,16 @@ 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')],
setupTestFrameworkScriptFile: setupTestsFile,
testPathIgnorePatterns: ['/(build|docs|node_modules)/'],
testEnvironment: 'node',
- testRegex: '(/__tests__/.*|\\.(test|spec))\\.(js|jsx)$',
};
if (rootDir) {
config.rootDir = rootDir;