本地打包完的 server.bundle.js 运行时,浏览器拿到的 js 文件返回也是个 HTML

很绝望,还报了Unexpected token <的错误,js 文件返回的开头竟然是<!DOCTYPE HTML>,后来发现是因为设置的静态资源Static("dist")文件夹不对。

浏览器端和服务端的entry

client 使用hydrate,用来接收通过ReactDOMServer渲染的 HTML,并且 React 会复用服务端传回来的 HTML ,把事件绑定到已存在的文档上。

1
2
3
4
5
import React from "react";
import ReactDOM from "react-dom";
import App from "./src/App";

ReactDOM.hydrate(<App />, document.getElementById("root"));

server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { renderToString } from "react-dom/server";
import App from "./src/App";

// 产生html
const content = renderToString(<App />);
const template = fs.readFileSync(process.cwd() + "/dist/index.html", "utf-8");
const html = template.replace(
  "<!-- this will be replaced by render  -->",
  content
);
ctx.body = html;

ReactDOMServer 的 API:

  • renderToString: 返回 HTML 字符串,可以使用这个 API 来服务器端生成 HTML 并在首次请求时返回客户端。

  • renderToStaticMarkup: 与renderToString类似,只是这个方法不会生成 React 依赖的内部属性,如data-reactroot,这个方法适合生成静态页面,因为减少属性值可以节省一些字节,但是如果想生成之后会有交互的页面,不要使用这个方法。

  • renderToNodeStream: 返回一个Readable stream,并且输出一个 HTML 字符串,这个字符串和renderToString的返回就是一样的啦。区别在于这个 API 只在服务端可用,且renderToString是读取完所有的 HTML 之后再返回,而renderToNodeStream以“流”的形式塞给response对象,不会等所有的 HTML 都渲染出来才返回。

1
const content = renderToNodeStream(<App />).pipe(response);