Create-react-app: support PUBLIC_URL during development as well

Created on 6 Jan 2019  ·  14Comments  ·  Source: facebook/create-react-app

Is this a bug report?

no

Situation

Imagine I want to have the next product structure:

  1. SPA (created using create-react-app), which is going to be served as /auth
  2. API, which is going to be served as /auth/api/*
  3. gateway, which resolves all the requests to the appropriate microservices

Here is a demo repo I prepared.

Problem

In the current version of CRA the variable PUBLIC_URL is ignored during the development.
The closest answer to the question why? which I found was this:
https://github.com/facebook/create-react-app/commit/30ee52cf3b2cbb6ac70999c02b1196bcaba8d4ca#diff-a7f98c18479be87c9f33e7604dbd1a09L33

which was updated by https://github.com/facebook/create-react-app/commit/30ee52cf3b2cbb6ac70999c02b1196bcaba8d4ca#diff-dc0c4e7c623b73660da1809fc60cf6baR74 (@Timer)

But this is exactly what prevents people from developing CRA applications while being under the gateway. I think it is quite handy in the "microservices" world.

Question

Are there any solutions to this problem? Is this something we can change in the CRA behaviour?

Regards,

proposal

Most helpful comment

Following this as I m not able to get parity in my dev and prod environment.
I have 2 react apps which I m trying to host from domain.com/path1 and domain.com/path2
For npm run build, PUBLIC_URL is set to /path1 or /path2 and the index.html neatly uses /path1/static.
However, the same doesnot happen when we do npm start.
How do we get dev/prod parity in this case?

All 14 comments

I got caught up in this as well. I expected that PUBLIC_URL would be used here:

https://github.com/facebook/create-react-app/blob/30ee52cf3b2cbb6ac70999c02b1196bcaba8d4ca/packages/react-scripts/config/webpackDevServer.config.js#L71

I don't know enough about CRA to say why it _shouldn't_, but I definitely expected it to work that way.

(It was natural to me that homepage be a production-only URL, since it goes in the package.json)

Did some quick research into this, and it seems _possible_, but 1 single line blocked me:

diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js
index 25cc88a..a9ac3ca 100644
--- a/packages/react-scripts/config/webpack.config.js
+++ b/packages/react-scripts/config/webpack.config.js
@@ -59,9 +59,8 @@ module.exports = function(webpackEnv) {
   // 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.
   // In development, we always serve from the root. This makes config easier.
-  const publicPath = isEnvProduction
-    ? paths.servedPath
-    : isEnvDevelopment && '/';
+  const 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.
   const shouldUseRelativeAssetPaths = publicPath === './';
@@ -69,9 +68,8 @@ module.exports = function(webpackEnv) {
   // `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.
-  const publicUrl = isEnvProduction
-    ? publicPath.slice(0, -1)
-    : isEnvDevelopment && '';
+  const publicUrl = publicPath.slice(0, -1);
+
   // Get environment variables to inject into our app.
   const env = getClientEnvironment(publicUrl);

@@ -169,7 +167,7 @@ module.exports = function(webpackEnv) {
         : isEnvDevelopment && 'static/js/[name].chunk.js',
       // We inferred the "public path" (such as / or /my-project) from homepage.
       // We use "/" in development.
-      publicPath: publicPath,
+      publicPath,
       // Point sourcemap entries to original disk location (format as URL on Windows)
       devtoolModuleFilenameTemplate: isEnvProduction
         ? info =>
@@ -587,7 +585,7 @@ module.exports = function(webpackEnv) {
       // having to parse `index.html`.
       new ManifestPlugin({
         fileName: 'asset-manifest.json',
-        publicPath: publicPath,
+        publicPath,
       }),
       // Moment.js is an extremely popular library that bundles large locale files
       // by default due to how Webpack interprets its code. This is a practical
diff --git a/packages/react-scripts/config/webpackDevServer.config.js b/packages/react-scripts/config/webpackDevServer.config.js
index 60a9713..21a9428 100644
--- a/packages/react-scripts/config/webpackDevServer.config.js
+++ b/packages/react-scripts/config/webpackDevServer.config.js
@@ -68,7 +68,12 @@ module.exports = function(proxy, allowedHost) {
     hot: true,
     // It is important to tell WebpackDevServer to use the same "root" path
     // as we specified in the config. In development, we always serve from /.
+
+    // ❌ /whatever/static/js/bundle.js doesn't work
+    // ✅ /static/js/bundle.js still does
+    // 🤔 Changing this to /whatever prevents %PUBLIC_URL% from being replaced!?
     publicPath: '/',
+
     // WebpackDevServer is noisy by default so we emit custom message instead
     // by listening to the compiler events with `compiler.hooks[...].tap` calls above.
     quiet: true,
diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json
index a9ed5e4..cd62d26 100644
--- a/packages/react-scripts/package.json
+++ b/packages/react-scripts/package.json
@@ -3,6 +3,7 @@
   "version": "2.1.3",
   "description": "Configuration and scripts for Create React App.",
   "repository": "facebook/create-react-app",
+  "homepage": "http://localhost:3000/whatever",
   "license": "MIT",
   "engines": {
     "node": ">=6"

(Tested via a fork & yarn start)

@ericclemmons other thing you can try is to set ./ as PUBLIC_URL. This works both on local and on production.

But I still think that PUBLIC_URL should be configurable during the development.

Sorry, I don't fully understand. How would I set PUBLIC_URL as ./ when it's only used in production?

(I may submit that diff as a PR, since it's soooo close to working!)

@ericclemmons sorry, I've mixed it up. I used ./ but that was not development mode.
Thanks for your PR, let's see if it'll be accepted.

I have a page action which calls the server like this:

fetch( process.env.PUBLIC_URL + '/upload-data', ...

This works fine if I do a full build
However if I use npm run start then it doesn't work as PUBLIC_URL is ''

I can add a value to the .env file as REACT_APP_PUBLIC_URL but this kind of seems to defeat the purpose of PUBLIC_URL

👍

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

I believe this issue should not be closed. At least it will be good to receive an answer from the create-react-app contributors to understand if it's a feature or bug.

@Timer @gaearon

My PR is slated for v3, so this can be closed when that's merged, right?

>

Following this as I m not able to get parity in my dev and prod environment.
I have 2 react apps which I m trying to host from domain.com/path1 and domain.com/path2
For npm run build, PUBLIC_URL is set to /path1 or /path2 and the index.html neatly uses /path1/static.
However, the same doesnot happen when we do npm start.
How do we get dev/prod parity in this case?

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

And still, this issue is not stale. But needs an attention of contributors, so we know if it's a bug or a feature.

There's an open PR to address this issue: #6280

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fson picture fson  ·  3Comments

dualcnhq picture dualcnhq  ·  3Comments

barcher picture barcher  ·  3Comments

alleroux picture alleroux  ·  3Comments

fson picture fson  ·  3Comments