如何将构建的React应用部署到现有的Laravel网站作为子域名?

huangapple go评论69阅读模式
英文:

How to deploy a build react app in your existing Laravel site as subdomain?

问题

npm run build 我构建了一个简单的React应用;这是我在build/文件夹中看到的内容

jdoe@AIR  ~/Sites/react/alphabets/build   main ±  tree
.
├── asset-manifest.json
├── favicon.png
├── index.html
└── static
    ├── css
    │   ├── main.f05a5dc1.css
    │   └── main.f05a5dc1.css.map
    └── js
        ├── main.cec1e2e8.js
        ├── main.cec1e2e8.js.LICENSE.txt
        └── main.cec1e2e8.js.map

4 directories, 8 files

由于我还有一个部署的Laravel站点。

我以为我可以将它放入我的public/目录并像这样导航到它。

https://www.bunlongheng.com/react/alphabets/

我尝试将我的build/文件夹上传到服务器的public/react/alphabets/build目录。

当我访问它时,我看到没有错误,没有禁止访问,但是是一个白屏。

我需要一种尽可能简单地部署React项目的方式,因为我的目标是部署多个...例如:

mysite/react/first-project
mysite/react/second-project
mysite/react/third-project
mysite/react/forth-project

等等...

对我有什么提示吗?我知道我离成功很近。

英文:

npm run build

I build a simple react app; this is what I see in build/ folder

jdoe@AIR  ~/Sites/react/alphabets/build   main ±  tree
.
├── asset-manifest.json
├── favicon.png
├── index.html
└── static
    ├── css
    │   ├── main.f05a5dc1.css
    │   └── main.f05a5dc1.css.map
    └── js
        ├── main.cec1e2e8.js
        ├── main.cec1e2e8.js.LICENSE.txt
        └── main.cec1e2e8.js.map

4 directories, 8 files

Since

I also have a Laravel site that I deployed.

I thought I could drop it in my `public/ and navigate to it like so.

https://www.bunlongheng.com/react/alphabets/

I tried SCP my build/ it to public/react/alphabets/build in my server.

When I go to it, I see no error, no forbidden, but a white screen.

I need a way to deploy react projects as simply as possible since my goal is to deploy more than one... ex.

mysite/react/first-project
mysite/react/second-project
mysite/react/third-project
mysite/react/forth-project

and so on... 

& leave my main site as it...

Any hints for me ? I know I am close.

答案1

得分: 1

你的标题说作为子域名,但你的示例URL是子目录/子文件夹。所以我认为你的意思是如何将React应用程序构建为子目录。

空白页面意味着资源未加载,因为资源路径使用了根路径(/)。要更改基本路径,你只需在路由器中添加 basename

<Router basename={'/react/alphabets/build'}>
  <Route path='/' component={Home} />
</Router>

还需要在 package.json 中添加 homepage。例如:

{
  "name": "react-example",
  "homepage": "/react/alphabets/build",
}

或者另一种方法是将public/react/alphabets/build/static 移动/复制到 public/static/

英文:

Your title said as subdomain, but your example URLs are subdirectory/subfolder. So I assume you meant how to build react app as subdirectory.

the blank page mean the resource is not loaded because the resource path is using root path(/). To change the base path, you just need to add basename to your router :

&lt;Router basename={&#39;/react/alphabets/build&#39;}&gt;
  &lt;Route path=&#39;/&#39; component={Home} /&gt;
&lt;/Router&gt;

and also you need to add homepage to package.json. example:

{
  &quot;name&quot;: &quot;react-example&quot;,
  &quot;homepage&quot;: &quot;/react/alphabets/build&quot;,

or another way you need to move/copy public/react/alphabets/build/static to public/static/

答案2

得分: 1

如果你想要一个子域名(例如https://alphabets.bunlongheng.com),你需要编辑路由模块,因为所有的SPA都在根目录上工作得很好。

如果你想要在你的域名下创建一个路由(例如https://alphabets.bunlongheng.com/react/alphabets),在Laravel方面更容易,因为你只需要复制构建内容,但你需要覆盖默认的假设,即你的应用程序是在不同级别的服务器根目录上托管的:模块绑定器和客户端路由。

模块绑定器

我个人在我的项目中使用 https://vitejs.dev/,但一个非常流行的绑定器是 https://create-react-app.dev/

这个绑定器链接文件时会引用根目录!!

访问 https://www.bunlongheng.com/react/alphabets/ 并打开开发工具,我们可以在控制台错误中看到网页正在搜索 https://www.bunlongheng.com/static/css/main.f05a5dc1.css,但该文件实际上位于 https://www.bunlongheng.com/react/alphabets/static/css/main.f05a5dc1.css

请查阅你的绑定器文档以修复此问题。如果你使用的是 CRA,这是关于绝对和相对引用的文档

客户端路由

如果你的下一个项目将使用像 React Router 这样的客户端路由,你需要在客户端路由上配置一个基准路径文档

英文:

If you want a subdomain (ex https://alphabets.bunlongheng.com) you need to edit routing module, all SPA is working fine becouse you are working on the root.

If you want a route into your domain (ex https://alphabets.bunlongheng.com/react/alphabets) is easier on Lavarel side because you just need to copy build content, but you need to override the default assumption that your app is hosted at the server root at different level: module bundler and client side routing.

Module Bundler

I personally use https://vitejs.dev/ in my projects but a very popular bundler is https://create-react-app.dev/.

The bundler links file referring to the root!!

Visiting https://www.bunlongheng.com/react/alphabets/ and opening the dev tools we can see on console errors that the webpage is searching for https://www.bunlongheng.com/static/css/main.f05a5dc1.css but the file is on https://www.bunlongheng.com/react/alphabets/static/css/main.f05a5dc1.css

Please check your bundler documentation to fix this. If you are using CRA this is the docs for absolute and relative reference.

Client side routing

If your next project will use a client side routing like react router, you will need to configure a basename on client router docs

答案3

得分: 1

以下是您要翻译的内容:

确保在您的 package.json 中如下所示:

// package.json 
{
  "name": "alphabets",
  "homepage": "alphabets",
  // ....
}

注意:使用 sed 自动更新主页。

  • 在项目根目录(即 package.json 所在位置)创建一个名为 .env 的文件,并在该文件中写入以下内容:
REACT_APP_BASENAME=react/alphabets

注意:最好使用 cross-env 或其他替代方法(dotenv ...)来进行构建处理。

REACT_APP_BASENAME= 设置为空值,或者删除 homepage,或者将其设置为 /,如果您想在本地主机上运行。

  • 更新您的 BrowserRouter 以解决白屏问题,按照以下方式操作:
import React from "react";
import { BrowserRouter } from "react-router-dom";

const baseName = process.env.REACT_APP_BASENAME ?? "";

const App: React.FC<> = () => {
  return (
    <>
      <BrowserRouter basename={baseName}>
        ....
      </BrowserRouter>
    </>
  );
}

export default App;
  • 将构建文件移动到:
mv ~/Sites/react/alphabets/build/* ~/Sites/react/alphabets/
英文:

Make sure in ur package.json like:

// package.json 
{
  &quot;name&quot;: &quot;alphabets&quot;,
  &quot;homepage&quot;: &quot;alphabets&quot;,
  ....
}

> Note: Use sed to update homepage automatically.

  • Create a file called .env at your project root (where package.json is located),
    and write in this file:
REACT_APP_BASENAME=react/alphabets

> Note: is better to use cross-env or any other alt (dotenv ...) on your build proccess.

> Put empty value for REACT_APP_BASENAME= and remove homepage or put / if you want to run on localhost.

  • Update your BrowserRouter to fix white screen issue, follow:
import React from &quot;react&quot;;
import { BrowserRouter } from &quot;react-router-dom&quot;;

const baseName = process.env.REACT_APP_BASENAME ?? &quot;&quot;;

const App: React.FC&lt;&gt; = () =&gt; {
  return (
    &lt;&gt;
      &lt;BrowserRouter basename={baseName}&gt;
        ....
      &lt;/BrowserRouter&gt;
    &lt;/&gt;
  );
}

export default App;
  • Move build files to:
mv ~/Sites/react/alphabets/build/* ~/Sites/react/alphabets/

答案4

得分: 1

HTML标准将允许您在Laravel或任何其他提供商上实现所需的静态托管行为。

INDEX.HTML

首先添加一个像这样的base元素。默认情况下将其设置为/,或者在部署时将其设置为像/spa/这样的值:

<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>

        <base href='/spa/' />
        <title>Demo App</title>

        <link rel='stylesheet' href='bootstrap.min.css'>
        <link rel='stylesheet' href='app.css'>
    </head>
    <body>
        <div id='root' class='container'></div>

        <script type='module' src='vendor.bundle.js'></script>
        <script type='module' src='app.bundle.js'></script>
    </body>
</html>

REACT

React对基于路径的路由提供了很好的支持,正如上面也提到的。当React应用程序启动时,您可以从index.html的运行时值初始化React路由:

const props = {
    viewModel: new AppViewModel(),
};

const baseElement = document.querySelector('base') as HTMLElement;
const base = baseElement?.getAttribute('href') || '/';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render (
    <ErrorBoundary>
        <BrowserRouter basename={base}>
            <App {...props} />
        </BrowserRouter>
    </ErrorBoundary>
);

然后,您可以像这样定义路由,您的代码无需意识到完整的URL形式为/spa/products

<Routes>
    <Route path='/products/:id' element={<ProductsView {...productsProps} />} />
    <Route path='/*' element={<HomeView {...homeProps} />} />
</Routes>

然后,您可以使用其他React导航功能,例如以下方式,以从子文件夹开始的路径:

import {useNavigate, useLocation} from 'react-router-dom';

const navigate = useNavigate();
const currentPath = useLocation().pathname;

navigate("/products");

<Link to="/products">View Products</Link>

部署

您只需在部署步骤中编辑index.html。如果需要,可以通过一些脚本来自动化此过程:

const oldData = fs.readFileSync('index.html', 'utf8');
var regex = new RegExp("href='/'", 'g');
const newData = oldData.replace(regex, "href='/spa/'");
fs.writeFileSync('index.html', newData, 'utf8');

我的演示SPA使用上述技术,我通过将静态内容放入AWS Cloudfront或基于Docker的环境中进行部署。它也可以在Laravel上运行。

英文:

The HTML standards will enable the static hosting behavior you want, on Laravel or any other provider.

INDEX.HTML

First add a base element like this. Set it to / by default, or set it to a value like /spa/ when deployed:

&lt;!DOCTYPE html&gt;
&lt;html lang=&#39;en&#39;&gt;
    &lt;head&gt;
        &lt;meta charset=&#39;utf-8&#39;&gt;
        &lt;meta name=&#39;viewport&#39; content=&#39;width=device-width, initial-scale=1, shrink-to-fit=no&#39;&gt;

        &lt;base href=&#39;/spa/&#39; /&gt;
        &lt;title&gt;Demo App&lt;/title&gt;

        &lt;link rel=&#39;stylesheet&#39; href=&#39;bootstrap.min.css&#39;&gt;
        &lt;link rel=&#39;stylesheet&#39; href=&#39;app.css&#39;&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div id=&#39;root&#39; class=&#39;container&#39;&gt;&lt;/div&gt;

        &lt;script type=&#39;module&#39; src=&#39;vendor.bundle.js&#39;&gt;&lt;/script&gt;
        &lt;script type=&#39;module&#39; src=&#39;app.bundle.js&#39;&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;

REACT

React has some nice support for path based routing, as selllami also pointed out above. When the React app starts, you can initialize React routes from the index.html runtime value:

const props = {
    viewModel: new AppViewModel(),
};

const baseElement = document.querySelector(&#39;base&#39;) as HTMLElement;
const base = baseElement?.getAttribute(&#39;href&#39;) || &#39;/&#39;;

const root = ReactDOM.createRoot(document.getElementById(&#39;root&#39;) as HTMLElement);
root.render (
    &lt;ErrorBoundary&gt;
        &lt;BrowserRouter basename={base}&gt;
            &lt;App {...props} /&gt;
        &lt;/BrowserRouter&gt;
    &lt;/ErrorBoundary&gt;
);

You can then define routes like this, and your code needs no awareness that the full URLs are of the form /spa/products:

&lt;Routes&gt;
    &lt;Route path=&#39;/products/:id&#39; element={&lt;ProductsView {...productsProps} /&gt;} /&gt;
    &lt;Route path=&#39;/*&#39;            element={&lt;HomeView {...homeProps} /&gt;} /&gt;
&lt;/Routes&gt;

You can then use other React navigation features, such as these, with paths beginning from the subfolder:

import {useNavigate, useLocation} from &#39;react-router-dom&#39;;

const navigate = useNavigate();
const currentPath = useLocation().pathname;

navigate(&quot;/products&quot;);

&lt;Link to=&quot;/products&quot;&gt;View Products&lt;/Link&gt;

DEPLOYMENT

You just need to edit the index.html as part of a deployment step. This can be automated by some script if required:

const oldData = fs.readFileSync(&#39;index.html&#39;, &#39;utf8&#39;);
var regex = new RegExp(&quot;href=&#39;/&#39;&quot;, &#39;g&#39;);
const newData = oldData.replace(regex, &quot;href=&#39;/spa/&#39;&quot;);
fs.writeFileSync(&#39;index.html&#39;, newData, &#39;utf8&#39;);

My demo SPA uses the above techniques, and I deploy it by dropping static content into either AWS Cloudfront or Docker based environments. It would also work on Laravel.

huangapple
  • 本文由 发表于 2023年1月6日 10:39:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75026414.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定