简体   繁体   English

我应该如何配置 create-react-app 以从子目录提供应用程序?

[英]How should I configure create-react-app to serve app from subdirectory?

I have classic web application rendered on server.我在服务器上呈现了经典的 Web 应用程序。 I want to create admin panel as single page application in React.我想在 React 中创建管理面板作为单页应用程序。 I want to server admin panel from https://smyapp.example.com/admin/ .我想从https://smyapp.example.com/admin/服务器管理面板。 I try to use create-react-app but it assumes that i serve SPA from root URL.我尝试使用create-react-app但它假定我从根 URL 提供 SPA。 How should I configure create-react-app to serve app from "admin" subdirectory?我应该如何配置create-react-app以从"admin"子目录提供应用程序? In documentation I found "homepage" property but if I properly understand it requires complete url.在文档中我找到了"homepage"属性,但如果我正确理解它需要完整的 url。 I can't give complete url because my app is deployed in few environments.我无法提供完整的 url,因为我的应用程序部署在少数环境中。

In addition to your requirements , I am adding mine:除了您的要求外,我还添加了我的:

  • It should be done by CD, through an env variable.它应该由 CD 通过一个环境变量来完成。
  • If I need to rename the subdirectory, I should only have to change the env variable.如果我需要重命名子目录,我只需要更改 env 变量。
  • It should work with react-router.它应该与反应路由器一起使用。
  • It should work with scss (sass) and html.它应该适用于 scss (sass) 和 html。
  • Everything should work normally in dev mode (npm start).一切都应该在开发模式下正常工作(npm start)。

I also had to implement it in Angular2+ project not long ago, I found it harder to implement in React then in Angular2+ where you are good to go with ng build --base-href /<project_name>/ .不久前,我还不得不在 Angular2+ 项目中实现它,我发现在 React 中实现它比在 Angular2+ 中实现它更难,你最好使用ng build --base-href /<project_name>/ source 资源


Short version精简版

  1. Before building, set PUBLIC_URL env variable to the value of your subdirectory, let use /subdir for example.在构建之前,将PUBLIC_URL变量设置为子目录的值,例如使用/subdir You can also put this variable into your .env.production ( in case you do not have that file you can check the doc )您也可以将此变量放入您的.env.production 中(如果您没有该文件,您可以查看文档
  2. In public/index.html add the base element bellow, this is for static files like images.public/index.html中添加基本元素波纹管,这是用于静态文件,如图像。
<base href="%PUBLIC_URL%/">
  1. Also in public/index.html , if you have custom link element, make sure theyre are prefixed with %PUBLIC_URL% (like manifest.json and favicon.ico href).同样在public/index.html中,如果您有自定义link元素,请确保它们以%PUBLIC_URL%为前缀(如manifest.jsonfavicon.ico href)。
  2. If you use BrowserRouter , you can add basename prop:如果你使用BrowserRouter ,你可以添加basename属性:
<BrowserRouter basename={process.env.PUBLIC_URL} />
  1. If you use Router instead, because you need access to history.push method, to programmatically change page, do the following:如果您改用Router ,因为您需要访问history.push方法,以编程方式更改页面,请执行以下操作:
// history.tsx
import {createBrowserHistory} from 'history';

export default createBrowserHistory({ basename: process.env.PUBLIC_URL });
<!-- Where your router is, for me, App.tsx -->
<Router history={history}>
  ...
</Router>
  1. Use relative links inside your elements在元素内使用相对链接
<!-- "./assets/quotes.png" is also ok, but "/assets/quotes.png" is not -->
<img src="assets/quotes.png" alt="" />
  1. Move your background-image links from scss to jsx/tsx files (note that you may not need to do that if you use css files):将您的background-image链接从 scss 移动到 jsx/tsx 文件(请注意,如果您使用 css 文件,您可能不需要这样做):
/*remove that*/
background-image: url('/assets/background-form.jpg');
<section style={{backgroundImage: `url('assets/background-form.jpg')`}}>
...

You should be done.你应该完成了。


Additional informations附加信息

I preferred to use PUBLIC_URL instead of homepage in package.json because I want to use env variable set on gitlab to set the subdir.我更喜欢在package.json中使用PUBLIC_URL而不是homepage ,因为我想使用 gitlab 上设置的 env 变量来设置子目录。 Relevant resources about the subject:关于该主题的相关资源:

PUBLIC_URL override homepage , and PUBLIC_URL also take the domain name, if you provide one. PUBLIC_URL覆盖homepage ,并且PUBLIC_URL也采用域名,如果您提供一个。 If you set only homepage , PUBLIC_URL will be set to the value of homepage .如果只设置homepagePUBLIC_URL将设置为homepage的值。


If you do not want to use a base element in your index.html (I would not know why), you will need to append process.env.PUBLIC_URL to every link yourself.如果您不想在 index.html 中使用基本元素(我不知道为什么),您需要自己将process.env.PUBLIC_URL附加到每个链接。 Note that if you have react-router with a base element, but have not set basename prop, you will get a warning.请注意,如果您有带有基本元素的 react-router,但尚未设置basename属性,您将收到警告。


Sass won't compile with an incorrect relative path. Sass 不会使用不正确的相对路径进行编译。 It also won't compile with correct relative path to your ../public/assets folder, because of ModuleScopePlugin restrictions, you can avoid the restriction by moving your image inside the src folder, I haven't tried that.它也不会以正确的相对路径编译到您的../public/assets文件夹,因为ModuleScopePlugin限制,您可以通过将图像移动到 src 文件夹中来避免限制,我没有尝试过。


There seem to be no way of testing relative path in development mode (npm start).似乎没有办法在开发模式下测试相对路径(npm start)。 see comment 见评论


Finnaly, theses stackoverflow link have related issues:最后,这些stackoverflow链接有相关问题:

For create-react-app v2 and react-router v4, I used the following combo to serve a production (staging, uat, etc) app under "/app":对于 create-react-app v2 和 react-router v4,我使用以下组合在“/app”下为生产(staging、uat 等)应用程序提供服务:

package.json:包.json:

"homepage": "/app"

Then in the app entry point:然后在应用入口点:

 <BrowserRouter basename={process.env.PUBLIC_URL}>
  {/* other components */}
 </BrowserRouter>

And everything "just works" across both local-dev and deployed environments.在本地开发和部署环境中,一切都“正常工作”。 HTH!

You should add entry in package.json for this.为此,您应该在package.json中添加条目。

Add a key "homepage": "your-subfolder/" in your package.json All static files will be loaded from "your-subfolder"在你的package.json中添加一个键 "homepage": "your-subfolder/" 所有静态文件都将从 "your-subfolder" 加载

If there is no subfolder and you need to load from same folder you need to add the path as "./" or remove the entire line which has "homepage": "xxxxxxxxxx"如果没有子文件夹并且您需要从同一文件夹加载,则需要将路径添加为“./”或删除具有"homepage": "xxxxxxxxxx"

"homepage": "./"

From the official docs来自官方文档

By default, Create React App produces a build assuming your app is hosted at the server root.默认情况下,Create React App 会生成一个构建,假设您的应用程序托管在服务器根目录中。 To override this, specify the homepage in your package.json, for example:要覆盖它,请在 package.json 中指定主页,例如:

"homepage": "http://mywebsite.com/relativepath", "主页": "http://mywebsite.com/relativepath",

Note: If you are using react-router@^4 , you can route <Link> s using the basename prop on any <Router> .注意:如果您使用react-router@^4 ,您可以使用任何<Router>上的 basename 属性路由<Link> > 。

From here and also check the official CRA docs这里查看官方 CRA 文档

要获取相对 URL,您可以像这样构建应用程序:

PUBLIC_URL="." npm run build

Maybe you could use react-router and its relative basename parameter which allows you to serve your app from a subdirectory.也许您可以使用react-router及其相对basename参数,它允许您从子目录中为您的应用程序提供服务。

basename is the base URL for all locations. basename是所有位置的基本 URL。 If your app is served from a sub-directory on your server, you'll want to set this to the sub-directory.如果您的应用程序是从服务器上的子目录提供的,您需要将其设置为子目录。 A properly formatted basename should have a leading slash, but no trailing slash.格式正确的基本名称应该有一个前导斜杠,但没有尾随斜杠。

For instance:例如:

<BrowserRouter basename="/calendar"/>

So <Link to="/today"/> will render <a href="/calendar/today">所以<Link to="/today"/>将呈现<a href="/calendar/today">

See: https://reacttraining.com/react-router/web/api/BrowserRouter/basename-string请参阅: https ://reacttraining.com/react-router/web/api/BrowserRouter/basename-string

put in package.json something like this:在 package.json 中放入如下内容:

"homepage" : " http://localhost:3000/subfolder ", “主页”:“ http://localhost:3000/subfolder ”,

and work fine on any public or local server.并在任何公共或本地服务器上正常工作。 Of course, subfolder must be your folder.当然,子文件夹必须是您的文件夹。

In our case, we did everything as described in Ambroise's answer , but got a blank page in production with no errors or warnings in the console.在我们的例子中,我们按照Ambroise 的回答中的描述做了所有事情,但是在生产中得到了一个空白页面,在控制台中没有错误或警告。 It turned out to be a problem with BrowserRouter - we got it working by setting BrowserRouter's basename like so:原来是 BrowserRouter 的一个问题——我们通过设置 BrowserRouter 的基本名称来让它工作,如下所示:

<BrowserRouter basename="/our_subfolder/" />

You can specify the public path in your webpack configuration along with use of react route basepath.您可以在 webpack 配置中指定公共路径以及使用 react route basepath。

Link to Public Path: https://webpack.js.org/guides/public-path/公共路径链接: https ://webpack.js.org/guides/public-path/

Note that public path will be both leading and trailing slashes / to be valid.请注意,公共路径将同时是前导和尾随斜杠 / 才有效。

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

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