From d8ffc1beb077e44761db62d3fe053656734ca902 Mon Sep 17 00:00:00 2001 From: Thibault Derousseaux Date: Mon, 6 Feb 2017 15:02:27 +0100 Subject: [PATCH 1/4] Fix paths in CSS files when homepage is set to "./" In the production build, ExtractTextPlugin is used to generate a separate CSS file instead of injecting style through JavaScript. This plugin does not work well by default with nested output structure. To fix it, we give it a relative publicPath pointing to the build folder. --- .../config/webpack.config.prod.js | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 6bd61c99cc6..100ad850fde 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -27,6 +27,11 @@ 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; +// Not everybody wants a single-page app with client side routing without hash. +// Sometimes, people would rather be able to deploy their app anywhere, +// without having to specify a "homepage". +// We can detect this when the publicPath is set to "./". +var isPublicPathRelative = 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 +45,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 = isPublicPathRelative + // 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 +167,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 +262,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`. From 757f8dfb13158fc300701fae6ee48851d4453cdd Mon Sep 17 00:00:00 2001 From: Thibault Derousseaux Date: Mon, 6 Feb 2017 22:31:30 +0100 Subject: [PATCH 2/4] Add section in README to explain how to make builds deployable anywhere --- packages/react-scripts/template/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index 357df8d5dee..cc32e4e07cf 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -1070,6 +1070,18 @@ 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. +#### Making builds deployable anywhere + +>Note: this feature is available with `react-scripts@0.9.0` and higher. + +If your are not using the HTML5 `pushState` history API or not using client-side routing at all, you do not have to specify the definitive URL of your application. Instead, you can put this in your `package.json`: + +```js + "homepage": "./", +``` + +This will make sure that all the assets are loaded relatively to the generated `index.html`, effectively allowing you to build your application once and deploy it anywhere. + ### Firebase From 6e2d23ecfde42a5a5bada16c5a29971f06edb275 Mon Sep 17 00:00:00 2001 From: Thibault Derousseaux Date: Thu, 9 Feb 2017 14:19:11 +0100 Subject: [PATCH 3/4] Apply review requested change --- packages/react-scripts/config/webpack.config.prod.js | 10 ++++------ packages/react-scripts/template/README.md | 9 ++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 100ad850fde..4e75be521bb 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -27,11 +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; -// Not everybody wants a single-page app with client side routing without hash. -// Sometimes, people would rather be able to deploy their app anywhere, -// without having to specify a "homepage". -// We can detect this when the publicPath is set to "./". -var isPublicPathRelative = publicPath === './'; +// 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. @@ -52,7 +50,7 @@ const cssFilename = 'static/css/[name].[contenthash:8].css'; // (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 = isPublicPathRelative +const extractTextPluginOptions = shouldUseRelativeAssetPaths // Making sure that the publicPath goes back to to build folder. ? { publicPath: Array(cssFilename.split('/').length).join('../') } : undefined; diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index cc32e4e07cf..eb562e1b14c 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -1070,18 +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. -#### Making builds deployable anywhere +#### Setting Homepage to "." >Note: this feature is available with `react-scripts@0.9.0` and higher. -If your are not using the HTML5 `pushState` history API or not using client-side routing at all, you do not have to specify the definitive URL of your application. Instead, you can put this in your `package.json`: +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": "./", + "homepage": ".", ``` -This will make sure that all the assets are loaded relatively to the generated `index.html`, effectively allowing you to build your application once and deploy it anywhere. - +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 From 4bae7ee53b570321b2b2ff360edc0b8f1bd9ca88 Mon Sep 17 00:00:00 2001 From: Thibault Derousseaux Date: Thu, 9 Feb 2017 14:39:39 +0100 Subject: [PATCH 4/4] Apply review changes 2 --- packages/react-scripts/template/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index eb562e1b14c..c85e544720b 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -1070,7 +1070,7 @@ 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. -#### Setting Homepage to "." +#### Serving the Same Build from Different Paths >Note: this feature is available with `react-scripts@0.9.0` and higher. @@ -1080,7 +1080,7 @@ If you are not using the HTML5 `pushState` history API or not using client-side "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. +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