How to properly serve the create-react-app index from the server?

别等时光非礼了梦想. 提交于 2021-02-10 12:22:51

问题


I'm developing an application with create-react-app and all is going well, except for the fact that I would like to initially serve the index.html from the backend, and am running into trouble doing so.

The reason that I want to do this is so that I can inject some user-specific Javascript into the index.html page and also run various other queries when the user initially hits the page (similar to this person)

So, instead of connecting to localhost:3000 to view the app, I would instead connect to localhost:8080 and have the server serve this index.html file. (all other assets (js, css, images) would still be on localhost:3000)

One issue with doing this seems to be that the script tags are not included in the index.html file by default, and are instead generated by create-react-app. That is, say this is my index.html file:

<html lang="en">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

If I run npm start, and then inspect the source, it will instead be this (due to CRA runtime injections I presume):

<html lang="en">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <link rel="shortcut icon" href="/favicon.ico">
  </head>
  <body>
    <div id="root"></div>
  </body>
  <script src="/static/js/bundle.js"></script><script src="/static/js/0.chunk.js"></script><script src="/static/js/main.chunk.js"></script>
</html>

As a result, on the server, I'm currently trying something like this:

#[get("/")]
fn handle_index() {
    let scripts = r#"<script src="https://localhost:3000/static/js/bundle.js"></script>
                     <script src="https://localhost:3000/static/js/0.chunk.js"></script>
                     <script src="https://localhost:3000/static/js/main.chunk.js"></script>"#;

    let index_html = include_str!("../frontend/public/index.html");

    let document = format!(r#"<script type="application/javascript">
                                 window.APP_GLOBALS = { user_id: 5, color: "red" };
                              </script> {}{}"#, data, index_html, scripts);

    return document;
}

Because I'm not sure of any other way to inject those script tags. It looks like create-react-app only does it for my localhost:3000 page, and not the localhost:8080 page.

This seems to somewhat work. That is, the page loads, but there are two issues.

  1. Many of the asset URLs are now wrong. They are instead pointing to localhost:8080 instead of localhost:3000, and %PUBLIC_URL% URL likewise doesn't work (I suppose this is another process that is no longer occurring)

  2. The websocket autoreload dev server no longer works. It works when I navigate to localhost:3000, but not localhost:8080. When I edit a file and save, the page just turns white with no errors in the console.

I think all of these issues are due to the same cause: create-react-app normally preprocesses the index.html file in some way (converting %PUBLIC_URL%, adding those script tags, handling reload), but it is no longer doing this when the file is instead returned from the server.

What I'm wondering is how I can restore this functionality. Basically, have these script tags and %PUBLIC_URL% processes occur without my backend server having to attempt to do so.


回答1:


When you run npm start, you are telling CRA to make a development build using webpack. Webpack does all of the processing you see like injecting scripts and replacing %PUBLIC_URL%. You don't want your backend to serve the index.html in the public folder because that file hasn't been processed by webpack. Instead you need the backend to serve webpack's build output.

The npm start configuration is a development build, which is good for development but not production. (Also it doesn't save its output to the file system, so you couldn't even serve it from your backend if you wanted to. See CRA issue #1070). If you run npm run build, you get a production build in the build folder, which you should serve from your backend (and then you can make whatever injections you need).

The downside of this is that it takes longer to build, it doesn't rebuild automatically when you change your frontend files, and I'm not sure if the errors it gives are as useful as npm start. Thus you might want to use npm start when developing the frontend and npm run build when testing your backend. There are also certain projects like patch-package that would allow you to make npm start's build output stay in the file system so you can serve it, but I haven't tried any of them.

BTW - be careful with injecting scripts into the html from your backend. Consider something like setting cookies in your backend and reading those cookies in your frontend instead. This is safer, easier to debug, etc.



来源:https://stackoverflow.com/questions/59620477/how-to-properly-serve-the-create-react-app-index-from-the-server

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!