diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index 6bd61c99cc6..4e75be521bb 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -27,6 +27,9 @@ var path = require('path'); // Webpack uses `publicPath` to determine where the app is being served from. // It requires a trailing slash, or the file assets will get an incorrect path. var publicPath = paths.servedPath; +// Some apps do not use client-side routing with pushState. +// For these, "homepage" can be set to "." to enable relative asset paths. +var shouldUseRelativeAssetPaths = publicPath === './'; // `publicUrl` is just like `publicPath`, but we will provide it to our app // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. @@ -40,6 +43,18 @@ if (env.stringified['process.env'].NODE_ENV !== '"production"') { throw new Error('Production builds must have NODE_ENV=production.'); } +// Note: defined here because it will be used more than once. +const cssFilename = 'static/css/[name].[contenthash:8].css'; + +// ExtractTextPlugin expects the build output to be flat. +// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27) +// However, our output is structured with css, js and media folders. +// To have this structure working with relative paths, we have to use custom options. +const extractTextPluginOptions = shouldUseRelativeAssetPaths + // Making sure that the publicPath goes back to to build folder. + ? { publicPath: Array(cssFilename.split('/').length).join('../') } + : undefined; + // This is the production configuration. // It compiles slowly and is focused on producing a fast and minimal bundle. // The development configuration is different and lives in a separate file. @@ -150,7 +165,11 @@ module.exports = { // in the main CSS file. { test: /\.css$/, - loader: ExtractTextPlugin.extract('style', 'css?importLoaders=1!postcss') + loader: ExtractTextPlugin.extract( + 'style', + 'css?importLoaders=1!postcss', + extractTextPluginOptions + ) // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, // JSON is not enabled by default in Webpack but both Node and Browserify @@ -241,7 +260,7 @@ module.exports = { } }), // Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`. - new ExtractTextPlugin('static/css/[name].[contenthash:8].css'), + new ExtractTextPlugin(cssFilename), // 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`. diff --git a/template/README.md b/template/README.md index 357df8d5dee..c85e544720b 100644 --- a/template/README.md +++ b/template/README.md @@ -1070,6 +1070,17 @@ To override this, specify the `homepage` in your `package.json`, for example: This will let Create React App correctly infer the root path to use in the generated HTML file. +#### Serving the Same Build from Different Paths + +>Note: this feature is available with `react-scripts@0.9.0` and higher. + +If you are not using the HTML5 `pushState` history API or not using client-side routing at all, it is unnecessary to specify the URL from which your app will be served. Instead, you can put this in your `package.json`: + +```js + "homepage": ".", +``` + +This will make sure that all the asset paths are relative to `index.html`. You will then be able to move your app from `http://mywebsite.com` to `http://mywebsite.com/relativepath` or even `http://mywebsite.com/relative/path` without having to rebuild it. ### Firebase