简体   繁体   English

无法使用自定义 PUBLIC_URL 构建 create-react-app 项目

[英]Can't build create-react-app project with custom PUBLIC_URL

I'm trying我正在努力

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

with a project built using the latest create-react-script.使用最新的 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中出现的%PUBLIC_URL%被替换为空字符串,而不是预期的值PUBLIC_URL

public/index.html contains code like public/index.html包含类似的代码

<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 .数小时的互联网搜索和堆栈溢出表明,关于PUBLIC_URL的文章很少。 I cloned create-react-app from GitHub and have been browsing the code but have not yet been enlightened.我从 GitHub 上克隆了 create-react-app,一直在浏览代码,但还没有得到启发。

Does anyone have any suggestions as to what I'm doing wrong?有人对我做错了什么有任何建议吗?

If the other answers aren't working for you, there's also a homepage field in package.json .如果其他答案对您不起作用,那么package.json中还有一个homepage字段。 After running npm run build you should get a message like the following:运行npm run build后,您应该会收到如下消息:

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 , eg您只需将其添加为package.json中的根字段之一,例如

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

When it's successfully set, either via homepage or PUBLIC_URL , you should instead get a message like this:通过homepagePUBLIC_URL成功设置后,您应该收到如下消息:

The project was built assuming it is hosted at https://example.com.
You can control this with the homepage field in your package.json.

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.然后将https://dsomething.cloudfront.net设置为package.json中的homepage将不起作用。

1. Quick Solution 1. 快速解决方案

Build your project like this:像这样构建您的项目:
(windows) (视窗)

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

(linux/mac) (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在您构建的 index.html 中

2. Permanent & Recommended Solution 2. 永久和推荐的解决方案

Create a file called .env at your project root(same place where package.json is located).在您的项目根目录(与 package.json 所在的位置相同)创建一个名为.env的文件。
In this file write this(no quotes around the url):在这个文件中写下这个(在 url 周围没有引号):

PUBLIC_URL=https://dsomething.cloudfront.net

Build your project as usual ( npm run build )像往常一样构建你的项目( npm run build
This will also generate index.html with:这也将生成 index.html :

<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) 3. 奇怪的解决方案(在最新的 react-scripts 版本中不起作用)

Add this in your package.json在你的 package.json 中添加这个
"homepage": "http://://dsomething.cloudfront.net", "主页": "http://dsomething.cloudfront.net",

Then index.html will be generated with:然后 index.html 将生成:

<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 Github 问题Github 评论

That is not how the PUBLIC_URL variable is used.这不是 PUBLIC_URL 变量的使用方式。 According to the documentation , you can use the PUBLIC_URL in your HTML:根据文档,您可以在 HTML 中使用 PUBLIC_URL:

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

Or in your JavaScript:或者在你的 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. PUBLIC_URL 不是您设置为您选择的值的东西,它是一种在 Webpack 构建系统之外的部署中存储文件的方式。

To view this, run your CRA app and add this to the src/index.js file:要查看此内容,请运行您的 CRA 应用并将其添加到src/index.js文件中:

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

You'll see the URL already exists.您会看到 URL 已经存在。

Read more in the CRA docs .CRA 文档中阅读更多内容。

Actually the way of setting environment variables is different between different Operating System.实际上,不同操作系统之间设置环境变量的方式是不同的。

Windows (cmd.exe)视窗 (cmd.exe)

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

(Note: the lack of whitespace is intentional.) (注意:缺少空格是故意的。)

Linux, macOS (Bash) Linux、macOS(重击)

 PUBLIC_URL=http://xxxx.com npm start

Recommended: cross-env推荐: 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 ref: create-react-app/README.md#adding-temporary-environment-variables-in-your-shell at master · facebookincubator/create-react-app

Have a look at the documentation .看看文档 You can have a .env file which picks up the PUBLIC_URL你可以有一个 .env 文件来获取 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).您可以使用此变量强制将资产逐字引用到您提供的 url(包括主机名)。 This may be particularly useful when using a CDN to host your application.这在使用 CDN 托管您的应用程序时可能特别有用。

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.如果您看到那里的源代码,他们会检查process.env.NODE_ENV === 'development'是否返回true ,并且他们会自动删除主机 URL 并且只返回路径。

For example, if you set like below例如,如果您设置如下

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

They will remove http://example.com and only return /static .他们将删除http://example.com并且只返回/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.但是,由于您只设置了像http://example.com这样的根 URL,因此它们只会返回一个空字符串,因为您的 URL 字符串中没有子路径。

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.仅当您调用react-scripts start时才会发生这种情况,并且如果您调用react-scripts buildisEnvDevelopment将为false ,因此它只会返回http://example.com作为您在.env文件中设置的内容。

Here is the source code of getPublicUrlOrPath.js .这是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 '/';
}

What you are doing wrong, is to expect the PUBLIC_URL and process.env.PUBLIC_URL would have same value. 你做错了,是期望PUBLIC_URL和process.env.PUBLIC_URL具有相同的值。

create-react-app has two different PUBLIC_URL: create-react-app有两个不同的PUBLIC_URL:

  1. The one in the process environment or package.json homepage. 进程环境或package.json主页中的那个。
  2. The one in node process.env. 节点process.env中的那个。

The process environment PUBLIC_URL overrides any package.json homepage. 进程环境PUBLIC_URL会覆盖任何package.json主页。 It can be full URL with scheme, host and path. 它可以是带有方案,主机和路径的完整URL。 The host would be used to give correct deployment instructions. 主机将用于提供正确的部署说明。

The process.env.PUBLIC_URL is only the path from process environment PUBLIC_URL or homepage. process.env.PUBLIC_URL仅是进程环境PUBLIC_URL或主页的路径。

Therefore, when you run 因此,当你跑步

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

In React you'll have 在React你会有

process.env.PUBLIC_URL === ''

If you had 如果你有

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

In React you'd have 在React你有

process.env.PUBLIC_URL === '/foo'

Not sure why you aren't able to set it.不知道为什么你不能设置它。 In the source , PUBLIC_URL takes precedence over homepage源代码中, PUBLIC_URL优先于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.您可以尝试在他们的代码中设置断点,以查看哪些逻辑覆盖了您的环境变量。

如此所述, create-react-app 只会导入以REACT_APP_开头的环境变量,因此我相信PUBLIC_URL ,正如@redbmk 所提到的,来自package.json文件中的homepage设置。

This problem becomes apparent when you try to host a react app in github pages.当您尝试在 github 页面中托管一个 react 应用程序时,这个问题变得很明显。

How I fixed this,我是如何解决这个问题的,

In in my main application file, called app.tsx , where I include the router.在我的名为app.tsx的主应用程序文件中,我在其中包含了路由器。 I set the basename, eg, <BrowserRouter basename="/Seans-TypeScript-ReactJS-Redux-Boilerplate/">我设置了基本名称,例如<BrowserRouter basename="/Seans-TypeScript-ReactJS-Redux-Boilerplate/">

Note that it is a relative url, this completely simplifies the ability to run locally and hosted.请注意,它是一个相对 url,这完全简化了在本地运行和托管的能力。 The basename value, matches the repository title on GitHub. basename 值与 GitHub 上的存储库标题匹配。 This is the path that GitHub pages will auto create.这是 GitHub 页面将自动创建的路径。

That is all I needed to do.这就是我需要做的。

See working example hosted on GitHub pages at请参阅托管在 GitHub 页面上的工作示例

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

This solution works on a Linux bash command line:此解决方案适用于 Linux bash 命令行:

  1. Go to your react project root directory.转到您的反应项目根目录。
  2. open the bash terminal on that directory.打开该目录上的 bash 终端。
  3. After that run below two commands and you will see that the PUBLIC_URL changed:之后运行以下两个命令,您将看到PUBLIC_URL发生了变化:
> export PUBLIC_URL=https://example.com
> npm run build

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.如果PUBLIC_URL环境变量没有影响,可能是由于这个问题,导致开发中忽略了PUBLIC_URL It was fixed in create-react-app version 3.4.0 .它已在 create-react-app 版本3.4.0中修复。

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在 package.json 所在的项目根目录创建一个名为 .env 的文件,然后添加您的生产 URL,如下所示

    PUBLIC_URL=https://something.com
  2. add basename to BrowserRouter in the route configure (in App.js/ App.jsx)在路由配置中将basename添加到BrowserRouter (在 App.js/App.jsx 中)

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

First of all the react compiled code is "pure java script".首先反应编译的代码是“纯java脚本”。 As such, from an html page, it is possible to reference this code using something like:因此,从 html 页面中,可以使用以下方式引用此代码:

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

The creation of react components must not depend on the main website hyperlink. React 组件的创建不能依赖于主网站的超链接。 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.遵循此模式,重要的是要了解某些文件夹可能需要修改权限,以便每个人都可以通过 html 调用找到您的组件。 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.这可以从手动完成,也可以使用 webpack 之类的允许您设置此输出的东西来完成。

Open Command Prompt inside your Application's source. 在应用程序源中打开命令提示符。 Run the Command 运行命令

npm run eject npm运行弹出

Open your scripts/build.js file and add this at the beginning of the file after 'use strict' line 打开您的scripts / build.js文件,并将其添加到“使用严格”行之后的文件开头

'use strict';
....
process.env.PUBLIC_URL = './' 
// Provide the (current) path which you want to set here.
.....

在此处输入图片说明

Run

npm run build npm运行构建

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM