From bb14761051a2433cf08307e997429aea0f4d7bb3 Mon Sep 17 00:00:00 2001 From: Enoah Netzach <fabrizio.castellarin@prontopro.it> Date: Thu, 20 Oct 2016 17:28:14 +0200 Subject: [PATCH 1/2] Add `PUBLIC_URL` env variable for advanced use (#937) * Add support for `PUBLIC_URL` env variable * Remove unnecessary duplications * Simplify served path choice logic * Honor PUBLIC_URL in development * Add e2e tests Enables serving static assets from specified host. --- packages/react-scripts/config/paths.js | 35 +++++++++++++++++-- .../react-scripts/config/utils/ensureSlash.js | 10 ++++++ .../config/webpack.config.dev.js | 3 +- .../config/webpack.config.prod.js | 25 +++---------- .../kitchensink/integration/env.test.js | 20 +++++++---- .../kitchensink/integration/initDOM.js | 6 ++-- .../fixtures/kitchensink/src/App.js | 10 ++++-- .../kitchensink/src/features/env/PublicUrl.js | 5 +++ .../src/features/env/PublicUrl.test.js | 10 ++++++ packages/react-scripts/scripts/build.js | 16 +++++---- packages/react-scripts/scripts/eject.js | 17 +++++---- packages/react-scripts/scripts/start.js | 2 +- tasks/e2e-kitchensink.sh | 16 +++++++-- 13 files changed, 122 insertions(+), 53 deletions(-) create mode 100644 packages/react-scripts/config/utils/ensureSlash.js create mode 100644 packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.js create mode 100644 packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.test.js diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 2f10ea2fb..abd9f7286 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -11,6 +11,7 @@ var path = require('path'); var fs = require('fs'); +var url = require('url'); // Make sure any symlinks in the project folder are resolved: // https://github.com/facebookincubator/create-react-app/issues/637 @@ -40,6 +41,28 @@ var nodePaths = (process.env.NODE_PATH || '') .filter(folder => !path.isAbsolute(folder)) .map(resolveApp); +var envPublicUrl = process.env.PUBLIC_URL; + +function getPublicUrl(appPackageJson) { + return envPublicUrl || require(appPackageJson).homepage; +} + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// Webpack needs to know it to put the right <script> hrefs into HTML even in +// single-page apps that may serve index.html for nested URLs like /todos/42. +// We can't use a relative path in HTML because we don't want to load something +// like /todos/42/static/js/bundle.7289d.js. We have to know the root. +function getServedPath(appPackageJson) { + var publicUrl = getPublicUrl(appPackageJson); + if (!publicUrl) { + return '/'; + } else if (envPublicUrl) { + return publicUrl; + } + return url.parse(publicUrl).pathname; +} + // config after eject: we're in ./config/ module.exports = { appBuild: resolveApp('build'), @@ -52,7 +75,9 @@ module.exports = { testsSetup: resolveApp('src/setupTests.js'), appNodeModules: resolveApp('node_modules'), ownNodeModules: resolveApp('node_modules'), - nodePaths: nodePaths + nodePaths: nodePaths, + publicUrl: getPublicUrl(resolveApp('package.json')), + servedPath: getServedPath(resolveApp('package.json')) }; // @remove-on-eject-begin @@ -73,7 +98,9 @@ module.exports = { appNodeModules: resolveApp('node_modules'), // this is empty with npm3 but node resolution searches higher anyway: ownNodeModules: resolveOwn('../node_modules'), - nodePaths: nodePaths + nodePaths: nodePaths, + publicUrl: getPublicUrl(resolveApp('package.json')), + servedPath: getServedPath(resolveApp('package.json')) }; // config before publish: we're in ./packages/react-scripts/config/ @@ -89,7 +116,9 @@ if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) testsSetup: resolveOwn('../template/src/setupTests.js'), appNodeModules: resolveOwn('../node_modules'), ownNodeModules: resolveOwn('../node_modules'), - nodePaths: nodePaths + nodePaths: nodePaths, + publicUrl: getPublicUrl(resolveOwn('../package.json')), + servedPath: getServedPath(resolveOwn('../package.json')) }; } // @remove-on-eject-end diff --git a/packages/react-scripts/config/utils/ensureSlash.js b/packages/react-scripts/config/utils/ensureSlash.js new file mode 100644 index 000000000..f4382384f --- /dev/null +++ b/packages/react-scripts/config/utils/ensureSlash.js @@ -0,0 +1,10 @@ +module.exports = function ensureSlash(path, needsSlash) { + var hasSlash = path.endsWith('/'); + if (hasSlash && !needsSlash) { + return path.substr(path, path.length - 1); + } else if (!hasSlash && needsSlash) { + return path + '/'; + } else { + return path; + } +} diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index ac63ba2f3..94ce7c26c 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -15,6 +15,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); +var ensureSlash = require('./utils/ensureSlash'); var getClientEnvironment = require('./env'); var paths = require('./paths'); @@ -29,7 +30,7 @@ var 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_PATH%/xyz looks better than %PUBLIC_PATH%xyz. -var publicUrl = ''; +var publicUrl = ensureSlash(paths.servedPath, false); // Get environment variables to inject into our app. var env = getClientEnvironment(publicUrl); diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 7181c4cca..ed7683534 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -16,6 +16,7 @@ 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 ensureSlash = require('./utils/ensureSlash'); var paths = require('./paths'); var getClientEnvironment = require('./env'); @@ -24,31 +25,13 @@ var getClientEnvironment = require('./env'); var path = require('path'); // @remove-on-eject-end -function ensureSlash(path, needsSlash) { - var hasSlash = path.endsWith('/'); - if (hasSlash && !needsSlash) { - return path.substr(path, path.length - 1); - } else if (!hasSlash && needsSlash) { - return path + '/'; - } else { - return path; - } -} - -// We use "homepage" field to infer "public path" at which the app is served. -// Webpack needs to know it to put the right <script> hrefs into HTML even in -// single-page apps that may serve index.html for nested URLs like /todos/42. -// We can't use a relative path in HTML because we don't want to load something -// like /todos/42/static/js/bundle.7289d.js. We have to know the root. -var homepagePath = require(paths.appPackageJson).homepage; -var homepagePathname = homepagePath ? url.parse(homepagePath).pathname : '/'; // 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 = ensureSlash(homepagePathname, true); +var publicPath = ensureSlash(paths.servedPath, true); // `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_PATH%/xyz looks better than %PUBLIC_PATH%xyz. -var publicUrl = ensureSlash(homepagePathname, false); +// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. +var publicUrl = ensureSlash(paths.servedPath, false); // Get environment variables to inject into our app. var env = getClientEnvironment(publicUrl); diff --git a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js index a179aa7cb..414229b22 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js @@ -3,22 +3,30 @@ import initDOM from './initDOM' describe('Integration', () => { describe('Environment variables', () => { + it('file env variables', async () => { + const doc = await initDOM('file-env-variables') + + expect(doc.getElementById('feature-file-env-variables').textContent).to.equal('fromtheenvfile.') + }) + it('NODE_PATH', async () => { const doc = await initDOM('node-path') expect(doc.getElementById('feature-node-path').childElementCount).to.equal(4) }) - it('shell env variables', async () => { - const doc = await initDOM('shell-env-variables') + it('PUBLIC_URL', async () => { + const doc = await initDOM('public-url') - expect(doc.getElementById('feature-shell-env-variables').textContent).to.equal('fromtheshell.') + expect(doc.getElementById('feature-public-url').textContent).to.equal('http://www.example.org/spa.') + expect(doc.querySelector('head link[rel="shortcut icon"]').getAttribute('href')) + .to.equal('http://www.example.org/spa/favicon.ico') }) - it('file env variables', async () => { - const doc = await initDOM('file-env-variables') + it('shell env variables', async () => { + const doc = await initDOM('shell-env-variables') - expect(doc.getElementById('feature-file-env-variables').textContent).to.equal('fromtheenvfile.') + expect(doc.getElementById('feature-shell-env-variables').textContent).to.equal('fromtheshell.') }) }) }) diff --git a/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js b/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js index cec022274..7cf8134b7 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/initDOM.js @@ -15,9 +15,11 @@ if (process.env.E2E_FILE) { const markup = fs.readFileSync(file, 'utf8') getMarkup = () => markup + const pathPrefix = process.env.PUBLIC_URL.replace(/^https?:\/\/[^\/]+\/?/, '') + resourceLoader = (resource, callback) => callback( null, - fs.readFileSync(path.join(path.dirname(file), resource.url.pathname), 'utf8') + fs.readFileSync(path.join(path.dirname(file), resource.url.pathname.replace(pathPrefix, '')), 'utf8') ) } else if (process.env.E2E_URL) { getMarkup = () => new Promise(resolve => { @@ -37,7 +39,7 @@ if (process.env.E2E_FILE) { export default feature => new Promise(async resolve => { const markup = await getMarkup() - const host = process.env.E2E_URL || 'http://localhost:3000' + const host = process.env.E2E_URL || 'http://www.example.org/spa:3000' const doc = jsdom.jsdom(markup, { features: { FetchExternalResources: ['script', 'css'], diff --git a/packages/react-scripts/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index fa297133f..36abe50d8 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -6,7 +6,7 @@ class BuiltEmitter extends Component { } componentDidMount() { - const { feature } = this.props + const { feature } = this.props; // Class components must call this.props.onReady when they're ready for the test. // We will assume functional components are ready immediately after mounting. @@ -44,7 +44,8 @@ class App extends Component { } componentDidMount() { - switch (location.hash.slice(1)) { + const feature = location.hash.slice(1); + switch (feature) { case 'array-destructuring': require.ensure([], () => this.setFeature(require('./features/syntax/ArrayDestructuring').default)); break; @@ -99,6 +100,9 @@ class App extends Component { case 'promises': require.ensure([], () => this.setFeature(require('./features/syntax/Promises').default)); break; + case 'public-url': + require.ensure([], () => this.setFeature(require('./features/env/PublicUrl').default)); + break; case 'rest-and-default': require.ensure([], () => this.setFeature(require('./features/syntax/RestAndDefault').default)); break; @@ -117,7 +121,7 @@ class App extends Component { case 'unknown-ext-inclusion': require.ensure([], () => this.setFeature(require('./features/webpack/UnknownExtInclusion').default)); break; - default: throw new Error('Unknown feature!'); + default: throw new Error(`Missing feature "${feature}"`); } } diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.js b/packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.js new file mode 100644 index 000000000..bbb7b958b --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.js @@ -0,0 +1,5 @@ +import React from 'react' + +export default () => ( + <span id="feature-public-url">{process.env.PUBLIC_URL}.</span> +) diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.test.js new file mode 100644 index 000000000..31e699ece --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/env/PublicUrl.test.js @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import PublicUrl from './PublicUrl'; + +describe('PUBLIC_URL', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(<PublicUrl />, div); + }); +}); diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js index 1e1b62170..7c953c354 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 url = require('url'); var filesize = require('filesize'); var gzipSize = require('gzip-size').sync; var webpack = require('webpack'); @@ -158,15 +159,16 @@ function build(previousSizeMap) { var openCommand = process.platform === 'win32' ? 'start' : 'open'; var appPackage = require(paths.appPackageJson); - var homepagePath = appPackage.homepage; + var publicUrl = paths.publicUrl; var publicPath = config.output.publicPath; - if (homepagePath && homepagePath.indexOf('.github.io/') !== -1) { + var publicPathname = url.parse(publicPath).pathname; + if (publicUrl && publicUrl.indexOf('.github.io/') !== -1) { // "homepage": "http://user.github.io/project" - console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.'); + console.log('The project was built assuming it is hosted at ' + chalk.green(publicPathname) + '.'); console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); console.log(); console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); - console.log('To publish it at ' + chalk.green(homepagePath) + ', run:'); + console.log('To publish it at ' + chalk.green(publicUrl) + ', run:'); // If script deploy has been added to package.json, skip the instructions if (typeof appPackage.scripts.deploy === 'undefined') { console.log(); @@ -198,14 +200,14 @@ function build(previousSizeMap) { console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); console.log(); } else { - // no homepage or "homepage": "http://mywebsite.com" - console.log('The project was built assuming it is hosted at the server root.'); - if (homepagePath) { + if (publicUrl) { // "homepage": "http://mywebsite.com" + console.log('The project was built assuming it is hosted at ' + chalk.green(publicUrl) + '.'); console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); console.log(); } else { // no homepage + console.log('The project was built assuming it is hosted at the server root.'); console.log('To override this, specify the ' + chalk.green('homepage') + ' in your ' + chalk.cyan('package.json') + '.'); console.log('For example, add this to build it for GitHub Pages:') console.log(); diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js index b8f9d3131..daa5958e9 100644 --- a/packages/react-scripts/scripts/eject.js +++ b/packages/react-scripts/scripts/eject.js @@ -43,12 +43,6 @@ prompt( } } - var folders = [ - 'config', - path.join('config', 'jest'), - 'scripts' - ]; - var files = [ path.join('config', 'env.js'), path.join('config', 'paths.js'), @@ -57,11 +51,20 @@ prompt( path.join('config', 'webpack.config.prod.js'), path.join('config', 'jest', 'cssTransform.js'), path.join('config', 'jest', 'fileTransform.js'), + path.join('config', 'utils', 'ensureSlash.js'), path.join('scripts', 'build.js'), path.join('scripts', 'start.js'), - path.join('scripts', 'test.js') + path.join('scripts', 'test.js'), ]; + var folders = files.reduce(function(prevFolders, file) { + var dirname = path.dirname(file); + if (prevFolders.indexOf(dirname) === -1) { + return prevFolders.concat(dirname); + } + return prevFolders; + }, []); + // Ensure that the app folder is clean and we won't override any files folders.forEach(verifyAbsent); files.forEach(verifyAbsent); diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 8615fb074..c326b9b94 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -241,7 +241,7 @@ function runDevServer(host, port, protocol) { // project directory is dangerous because we may expose sensitive files. // Instead, we establish a convention that only files in `public` directory // get served. Our build script will copy `public` into the `build` folder. - // In `index.html`, you can get URL of `public` folder with %PUBLIC_PATH%: + // In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%: // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> // In JavaScript code, you can access it with `process.env.PUBLIC_URL`. // Note that we only recommend to use `public` folder as an escape hatch diff --git a/tasks/e2e-kitchensink.sh b/tasks/e2e-kitchensink.sh index c681580b0..4d27b70d6 100755 --- a/tasks/e2e-kitchensink.sh +++ b/tasks/e2e-kitchensink.sh @@ -114,7 +114,11 @@ cd test-kitchensink npm link $root_path/packages/babel-preset-react-app # Test the build -NODE_PATH=src REACT_APP_SHELL_ENV_MESSAGE=fromtheshell npm run build +REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ + NODE_PATH=src \ + PUBLIC_URL=http://www.example.org/spa/ \ + npm run build + # Check for expected output test -e build/*.html test -e build/static/js/main.*.js @@ -131,6 +135,7 @@ tmp_server_log=`mktemp` PORT=3001 \ REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ NODE_PATH=src \ + PUBLIC_URL=http://www.example.org/spa/ \ nohup npm start &>$tmp_server_log & grep -q 'The app is running at:' <(tail -f $tmp_server_log) E2E_URL="http://localhost:3001" \ @@ -144,6 +149,7 @@ E2E_FILE=./build/index.html \ CI=true \ NODE_PATH=src \ NODE_ENV=production \ + PUBLIC_URL=http://www.example.org/spa/ \ node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.test.js # ****************************************************************************** @@ -166,7 +172,11 @@ npm link $root_path/packages/react-scripts rm .babelrc # Test the build -NODE_PATH=src REACT_APP_SHELL_ENV_MESSAGE=fromtheshell npm run build +REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ + NODE_PATH=src \ + PUBLIC_URL=http://www.example.org/spa/ \ + npm run build + # Check for expected output test -e build/*.html test -e build/static/js/main.*.js @@ -183,6 +193,7 @@ tmp_server_log=`mktemp` PORT=3002 \ REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ NODE_PATH=src \ + PUBLIC_URL=http://www.example.org/spa/ \ nohup npm start &>$tmp_server_log & grep -q 'The app is running at:' <(tail -f $tmp_server_log) E2E_URL="http://localhost:3002" \ @@ -196,6 +207,7 @@ E2E_FILE=./build/index.html \ CI=true \ NODE_ENV=production \ NODE_PATH=src \ + PUBLIC_URL=http://www.example.org/spa/ \ node_modules/.bin/mocha --require babel-register --require babel-polyfill integration/*.test.js # Cleanup -- GitLab From fe81e4acedc84c40742917f7b48973d94559c270 Mon Sep 17 00:00:00 2001 From: Joe Haddad <timer150@gmail.com> Date: Wed, 8 Feb 2017 19:59:56 -0500 Subject: [PATCH 2/2] Polish PUBLIC_URL --- packages/react-scripts/config/paths.js | 21 +++++++++++++------ .../react-scripts/config/utils/ensureSlash.js | 10 --------- .../config/webpack.config.dev.js | 5 ++--- .../config/webpack.config.prod.js | 7 +++---- .../kitchensink/integration/env.test.js | 5 +++-- packages/react-scripts/scripts/eject.js | 17 +++++++-------- tasks/e2e-kitchensink.sh | 2 -- 7 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 packages/react-scripts/config/utils/ensureSlash.js diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index abd9f7286..7d114080f 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -43,6 +43,17 @@ var nodePaths = (process.env.NODE_PATH || '') var envPublicUrl = process.env.PUBLIC_URL; +function ensureSlash(path, needsSlash) { + var hasSlash = path.endsWith('/'); + if (hasSlash && !needsSlash) { + return path.substr(path, path.length - 1); + } else if (!hasSlash && needsSlash) { + return path + '/'; + } else { + return path; + } +} + function getPublicUrl(appPackageJson) { return envPublicUrl || require(appPackageJson).homepage; } @@ -55,12 +66,10 @@ function getPublicUrl(appPackageJson) { // like /todos/42/static/js/bundle.7289d.js. We have to know the root. function getServedPath(appPackageJson) { var publicUrl = getPublicUrl(appPackageJson); - if (!publicUrl) { - return '/'; - } else if (envPublicUrl) { - return publicUrl; - } - return url.parse(publicUrl).pathname; + var servedUrl = envPublicUrl || ( + publicUrl ? url.parse(publicUrl).pathname : '/' + ); + return ensureSlash(servedUrl, true); } // config after eject: we're in ./config/ diff --git a/packages/react-scripts/config/utils/ensureSlash.js b/packages/react-scripts/config/utils/ensureSlash.js deleted file mode 100644 index f4382384f..000000000 --- a/packages/react-scripts/config/utils/ensureSlash.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = function ensureSlash(path, needsSlash) { - var hasSlash = path.endsWith('/'); - if (hasSlash && !needsSlash) { - return path.substr(path, path.length - 1); - } else if (!hasSlash && needsSlash) { - return path + '/'; - } else { - return path; - } -} diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index 94ce7c26c..2548c6208 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -15,7 +15,6 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); -var ensureSlash = require('./utils/ensureSlash'); var getClientEnvironment = require('./env'); var paths = require('./paths'); @@ -30,7 +29,7 @@ var 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_PATH%/xyz looks better than %PUBLIC_PATH%xyz. -var publicUrl = ensureSlash(paths.servedPath, false); +var publicUrl = ''; // Get environment variables to inject into our app. var env = getClientEnvironment(publicUrl); @@ -116,7 +115,7 @@ module.exports = { // ** ADDING/UPDATING LOADERS ** // The "url" loader handles all assets unless explicitly excluded. // The `exclude` list *must* be updated with every change to loader extensions. - // When adding a new loader, you must add its `test` + // When adding a new loader, you must add its `test` // as a new entry in the `exclude` list for "url" loader. // "url" loader embeds assets smaller than specified size as data URLs to avoid requests. diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index ed7683534..053eca67e 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -16,7 +16,6 @@ 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 ensureSlash = require('./utils/ensureSlash'); var paths = require('./paths'); var getClientEnvironment = require('./env'); @@ -27,11 +26,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 = ensureSlash(paths.servedPath, true); +var publicPath = paths.servedPath; // `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. -var publicUrl = ensureSlash(paths.servedPath, false); +var publicUrl = publicPath.slice(0, -1); // Get environment variables to inject into our app. var env = getClientEnvironment(publicUrl); @@ -106,7 +105,7 @@ module.exports = { // ** ADDING/UPDATING LOADERS ** // The "url" loader handles all assets unless explicitly excluded. // The `exclude` list *must* be updated with every change to loader extensions. - // When adding a new loader, you must add its `test` + // When adding a new loader, you must add its `test` // as a new entry in the `exclude` list in the "url" loader. // "url" loader embeds assets smaller than specified size as data URLs to avoid requests. diff --git a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js index 414229b22..e7b3afe42 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js @@ -18,9 +18,10 @@ describe('Integration', () => { it('PUBLIC_URL', async () => { const doc = await initDOM('public-url') - expect(doc.getElementById('feature-public-url').textContent).to.equal('http://www.example.org/spa.') + const prefix = process.env.NODE_ENV === 'development' ? '' : 'http://www.example.org/spa'; + expect(doc.getElementById('feature-public-url').textContent).to.equal(`${prefix}.`) expect(doc.querySelector('head link[rel="shortcut icon"]').getAttribute('href')) - .to.equal('http://www.example.org/spa/favicon.ico') + .to.equal(`${prefix}/favicon.ico`) }) it('shell env variables', async () => { diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js index daa5958e9..b8f9d3131 100644 --- a/packages/react-scripts/scripts/eject.js +++ b/packages/react-scripts/scripts/eject.js @@ -43,6 +43,12 @@ prompt( } } + var folders = [ + 'config', + path.join('config', 'jest'), + 'scripts' + ]; + var files = [ path.join('config', 'env.js'), path.join('config', 'paths.js'), @@ -51,20 +57,11 @@ prompt( path.join('config', 'webpack.config.prod.js'), path.join('config', 'jest', 'cssTransform.js'), path.join('config', 'jest', 'fileTransform.js'), - path.join('config', 'utils', 'ensureSlash.js'), path.join('scripts', 'build.js'), path.join('scripts', 'start.js'), - path.join('scripts', 'test.js'), + path.join('scripts', 'test.js') ]; - var folders = files.reduce(function(prevFolders, file) { - var dirname = path.dirname(file); - if (prevFolders.indexOf(dirname) === -1) { - return prevFolders.concat(dirname); - } - return prevFolders; - }, []); - // Ensure that the app folder is clean and we won't override any files folders.forEach(verifyAbsent); files.forEach(verifyAbsent); diff --git a/tasks/e2e-kitchensink.sh b/tasks/e2e-kitchensink.sh index 4d27b70d6..3c750feca 100755 --- a/tasks/e2e-kitchensink.sh +++ b/tasks/e2e-kitchensink.sh @@ -135,7 +135,6 @@ tmp_server_log=`mktemp` PORT=3001 \ REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ NODE_PATH=src \ - PUBLIC_URL=http://www.example.org/spa/ \ nohup npm start &>$tmp_server_log & grep -q 'The app is running at:' <(tail -f $tmp_server_log) E2E_URL="http://localhost:3001" \ @@ -193,7 +192,6 @@ tmp_server_log=`mktemp` PORT=3002 \ REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \ NODE_PATH=src \ - PUBLIC_URL=http://www.example.org/spa/ \ nohup npm start &>$tmp_server_log & grep -q 'The app is running at:' <(tail -f $tmp_server_log) E2E_URL="http://localhost:3002" \ -- GitLab