134

I'm trying

PUBLIC_URL=http://example.com npm run build

with a project built using the latest create-react-script.

However, the occurrences of %PUBLIC_URL% in public/index.html are replaced with an empty string, not the expected value PUBLIC_URL.

public/index.html contains code like

<script src="%PUBLIC_URL%/static/js/jarvis.widget.min.js"></script>

Hours of searching the internet and stack overflow show that very little is written about PUBLIC_URL. I cloned create-react-app from GitHub and have been browsing the code but have not yet been enlightened.

Does anyone have any suggestions as to what I'm doing wrong?

2
  • 1
    the url should be in the strings ```PUBLIC_URL="example.com" npm run build Commented Sep 3, 2020 at 18:03
  • It is still not working in the last version. Fixed using REACT_APP_PUBLIC_URL Commented Jun 22, 2023 at 12:21

14 Answers 14

93

If the other answers aren't working for you, there's also a homepage field in package.json. After running npm run build you should get a message like the following:

The project was built assuming it is hosted at the server root.
To override this, specify the homepage in your package.json.
For example, add this to build it for GitHub Pages:

  "homepage" : "http://myname.github.io/myapp",

You would just add it as one of the root fields in package.json, e.g.

{
  // ...
  "scripts": {
    // ...
  },
  "homepage": "https://example.com"
}

When it's successfully set, either via homepage or PUBLIC_URL, you should instead get a message like this:

The project was built assuming it is hosted at https://example.com.
You can control this with the homepage field in your package.json.
Sign up to request clarification or add additional context in comments.

3 Comments

There's actually a bug preventing this from working as expected at the moment: github.com/facebook/create-react-app/issues/8813
This worked for me when I went back to react-scripts 3.3.0.
From what I can tell, setting homepage seems to override the value for PUBLIC_URL
90

People like me who are looking for something like this in in build:

<script type="text/javascript" src="https://dsomething.cloudfront.net/static/js/main.ec7f8972.js">

Then setting https://dsomething.cloudfront.net to homepage in package.json will not work.

1. Quick Solution

Build your project like this:
(windows)

set PUBLIC_URL=https://dsomething.cloudfront.net&&npm run build

(linux/mac)

PUBLIC_URL=https://dsomething.cloudfront.net npm run build

And you will get

<script type="text/javascript" src="https://dsomething.cloudfront.net/static/js/main.ec7f8972.js">

in your built index.html

2. Permanent & Recommended Solution

Create a file called .env at your project root(same place where package.json is located).
In this file write this(no quotes around the url):

PUBLIC_URL=https://dsomething.cloudfront.net

Build your project as usual (npm run build)
This will also generate index.html with:

<script type="text/javascript" src="https://dsomething.cloudfront.net/static/js/main.ec7f8972.js">

3. Weird Solution (Will do not work in latest react-scripts version)

Add this in your package.json
"homepage": "http://://dsomething.cloudfront.net",

Then index.html will be generated with:

<script type="text/javascript" src="//dsomething.cloudfront.net/static/js/main.ec7f8972.js">

Which is basically the same as:

<script type="text/javascript" src="https://dsomething.cloudfront.net/static/js/main.ec7f8972.js">

in my understanding.

Github Issue Github Comment

6 Comments

I'm not really sure why they closed the issue. Only solution that works for me is the third one you suggest and it indeed seems really weird. Therefore I still think this is a bug. Or can someone explain to me the meaning of last comment before the issue was closed?
It will not work in the latest react scripts version, please use the .env approach.
@Vaibhav Hi! I having facing a different problem. I want to change the /static/js path to /static/dashboard/js/. But I can't find any solution on the internet about how to do this. Any idea? I have even asked a question too. Check here stackoverflow.com/questions/66655025/…
This answer is a solution to the react bug described in github.com/facebook/create-react-app/issues/8813. I can't thank you enough for this.
Thanks for this answer. I tried the .env file and it didn't work at first. I realized that i was saving it as a .txt extension by mistake so anyone reading make sure when you're saving your .env file you choose (on windows) Save as type: "All Files". Maybe you could add this to the answer for people reading in future?
|
28

That is not how the PUBLIC_URL variable is used. According to the documentation, you can use the PUBLIC_URL in your HTML:

<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">

Or in your JavaScript:

render() {
  // Note: this is an escape hatch and should be used sparingly!
  // Normally we recommend using `import` for getting asset URLs
  // as described in “Adding Images and Fonts” above this section.
  return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
}

The PUBLIC_URL is not something you set to a value of your choosing, it is a way to store files in your deployment outside of Webpack's build system.

To view this, run your CRA app and add this to the src/index.js file:

console.log('public url: ', process.env.PUBLIC_URL)

You'll see the URL already exists.

Read more in the CRA docs.

2 Comments

"The PUBLIC_URL is not something you set to a value of your choosing". Are you sure about that? create-react-app.dev/docs/advanced-configuration -> "You can adjust various development and production settings by setting environment variables in your shell or with .env". PUBLIC_URL -> "You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application."
The responder is right. CRA framework wants you edit app context path via package.json homepage and PUBLIC_URL receives that value. They opened it for altering and currently I imaging the only case when instead of the relative context path you want to embed a fixed protocol / domain / port (to make it difficult to clone your app??) Customization should be externalized somehow, and PUBLIC_URL is here for your build pipelines.
11

Actually the way of setting environment variables is different between different Operating System.

Windows (cmd.exe)

set PUBLIC_URL=http://xxxx.com&&npm start

(Note: the lack of whitespace is intentional.)

Linux, macOS (Bash)

 PUBLIC_URL=http://xxxx.com npm start

Recommended: cross-env

{
  "scripts": {
    "serve": "cross-env PUBLIC_URL=http://xxxx.com npm start"
  }
}

ref: create-react-app/README.md#adding-temporary-environment-variables-in-your-shell at master · facebookincubator/create-react-app

2 Comments

why do you have npm start in the build script?
{ "scripts": { "start": "npm run serve" } }
11

If you see there source code they check if process.env.NODE_ENV === 'development' returns true, and they automatically removes host URL and only return path.

For example, if you set like below

PUBLIC_URL=http://example.com/static/

They will remove http://example.com and only return /static.

However since you only set root URL like http://example.com, they will just return an empty string since there no subpath in your URL string.

This only happens if you call react-scripts start, and if you call react-scripts build then isEnvDevelopment will be false, so it will just return http://example.com as what you set in the .env file.

Here is the source code of getPublicUrlOrPath.js.

/**
 * Returns a URL or a path with slash at the end
 * In production can be URL, abolute path, relative path
 * In development always will be an absolute path
 * In development can use `path` module functions for operations
 *
 * @param {boolean} isEnvDevelopment
 * @param {(string|undefined)} homepage a valid url or pathname
 * @param {(string|undefined)} envPublicUrl a valid url or pathname
 * @returns {string}
 */
function getPublicUrlOrPath(isEnvDevelopment, homepage, envPublicUrl) {
  const stubDomain = 'https://create-react-app.dev';

  if (envPublicUrl) {
    // ensure last slash exists
    envPublicUrl = envPublicUrl.endsWith('/')
      ? envPublicUrl
      : envPublicUrl + '/';

    // validate if `envPublicUrl` is a URL or path like
    // `stubDomain` is ignored if `envPublicUrl` contains a domain
    const validPublicUrl = new URL(envPublicUrl, stubDomain);

    return isEnvDevelopment
      ? envPublicUrl.startsWith('.')
        ? '/'
        : validPublicUrl.pathname
      : // Some apps do not use client-side routing with pushState.
        // For these, "homepage" can be set to "." to enable relative asset paths.
        envPublicUrl;
  }

  if (homepage) {
    // strip last slash if exists
    homepage = homepage.endsWith('/') ? homepage : homepage + '/';

    // validate if `homepage` is a URL or path like and use just pathname
    const validHomepagePathname = new URL(homepage, stubDomain).pathname;
    return isEnvDevelopment
      ? homepage.startsWith('.')
        ? '/'
        : validHomepagePathname
      : // Some apps do not use client-side routing with pushState.
      // For these, "homepage" can be set to "." to enable relative asset paths.
      homepage.startsWith('.')
      ? homepage
      : validHomepagePathname;
  }

  return '/';
}

Comments

9

Have a look at the documentation. You can have a .env file which picks up the PUBLIC_URL

Although you should remember that what its used for -

You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application.

Comments

6

As documented here create-react-app will only import environment variables beginning with REACT_APP_, so the PUBLIC_URL, I believe, as mentioned by @redbmk, comes from the homepage setting in the package.json file.

Comments

3

Not sure why you aren't able to set it. In the source, PUBLIC_URL takes precedence over homepage

const envPublicUrl = process.env.PUBLIC_URL;
...
const getPublicUrl = appPackageJson =>
  envPublicUrl || require(appPackageJson).homepage;

You can try setting breakpoints in their code to see what logic is overriding your environment variable.

Comments

3

This problem becomes apparent when you try to host a react app in github pages.

How I fixed this,

In in my main application file, called app.tsx, where I include the router. I set the basename, eg, <BrowserRouter basename="/Seans-TypeScript-ReactJS-Redux-Boilerplate/">

Note that it is a relative url, this completely simplifies the ability to run locally and hosted. The basename value, matches the repository title on GitHub. This is the path that GitHub pages will auto create.

That is all I needed to do.

See working example hosted on GitHub pages at

https://sean-bradley.github.io/Seans-TypeScript-ReactJS-Redux-Boilerplate/

3 Comments

But after hard refresh page goes to 404 error page
is that a problem with my answer, or a problem with react?
I am just asking is it any solution to overcome that hard refresh problem ?
2

This solution works on a Linux bash command line:

  1. Go to your react project root directory.
  2. open the bash terminal on that directory.
  3. After that run below two commands and you will see that the PUBLIC_URL changed:
> export PUBLIC_URL=https://example.com
> npm run build

Comments

1

If the PUBLIC_URL environment variable has no effect, it may be due to this issue, which causes PUBLIC_URL to be ignored in development. It was fixed in create-react-app version 3.4.0.

Comments

1

If your app has routing, try like below

  1. Create a file called .env at your project root where package.json is located, then add your production URL like below

    PUBLIC_URL=https://something.com
    
  2. add basename to BrowserRouter in the route configure (in App.js/ App.jsx)

    <BrowserRouter basename="https://something.com">
    

Comments

0

First of all the react compiled code is "pure java script". As such, from an html page, it is possible to reference this code using something like:

< script src="my_compiled_component.js" >< /script >

The creation of react components must not depend on the main website hyperlink. From react code, to locate the website your components are running from use something like:

window.location.protocol + '//'+ window.location.hostname + ':' + window.location.port

Following this pattern it is important to understand that some folders might need to have modified permissions so everybody can find your components through html calls. How to define where to place the compiled react code? This could be done from manually to using something like webpack that allows you to set this output.

Comments

0

A little late on this but I had this same problem and discovered the following ...

I had a .env.local file with the line:

PUBLIC_URL=''

... and a .env file with:

PUBLIC_URL='https://example.com'

Well, when running npm run build, values in .env.local win over values in .env per the CRA docs, so my URLs were getting built with empty strings.

Now I could swear that used to be flipped but maybe not?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.