我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文的主角依然是react ssr系列文章中的server.jsx,它启动了个express进程,然后给react项目进行脱水处理。并且使用renderToPipeableStream()输出到浏览器端,然后利用另外打包的内置hydrateRoot().js文件,来完成注水的过程。那么,问题来了:这个基于express的程序,如何使用原生的node,而不是esno来启动呢?这就是本文要讨论的问题。

苏南大叔:webpack+babel工具,如何编译ReactSSR的服务器端代码? - esnode-node
webpack+babel工具,如何编译ReactSSR的服务器端代码?(图2-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1express@4.21.1webpack-cli@5.1.4

前文回顾

在前面的文章里面,都是使用esno执行server.jsx文件的。参考文章:

本文的思路中,需求是把通过esno执行的文件,改成直接node执行。其实和下面这篇文章的思路,基本一致。目前的思路依旧是webpack打包,babel编译。

但是,由于要转换的程序是运行在服务器端的node,而不是运行在浏览器端的普通.js代码,因此在编译转换的时候,还是有些许区别的。主要体现在webpack.config.server.js文件上。

苏南大叔:webpack+babel工具,如何编译ReactSSR的服务器端代码? - webpack-build
webpack+babel工具,如何编译ReactSSR的服务器端代码?(图2-2)

webpack配置文件

基于create-react-appcra模版,新建一个webpack的配置文件。内容如下:

webpack.config.server.js:

const path = require("path");
// const nodeExternals = require('webpack-node-externals');
module.exports = {
  entry: "./server.jsx",
  output: {
    filename: "server.prod.js",
    path: path.resolve("./"),
  },
  target: "node",
  // devtool: 'source-map',
  externals: [
    // nodeExternals(),
  ],
  resolve: {
    extensions: [".js", ".jsx", ".ts", ".tsx", ".json"],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader", 
          options: {
            presets: [
              "react-app",
              "@babel/preset-env",
            ],
          },
        },
      },
    ],
  },
};

安装编译

可能需要新安装webpack-cli@babel/plugin-proposal-private-property-in-object,安装方式:

npm i webpack-cli --save-dev
npm i @babel/plugin-proposal-private-property-in-object --save-dev

配置新的package.json里面的命令:

//...
"scripts": {
  "build2": "cross-env NODE_ENV=production webpack --mode production --config webpack.config.server.js"
},
//...

执行命令,获得server.prod.js文件。

npm run build2

cross-env命令,参考文章:

执行文件

这个文件可单独放置于任何其它的node环境下,通过node的方式执行。

node server.prod.js

也可以配合nodemon伺服器执行。

nodemon --exec node server.prod.js

配置关键点

这个配置中,代码不长。但是,这里有两个关键点。

关键点之target

能编译成功,关键配置就是target设置为nodewebpack默认的target是浏览器端的.js文件构建,并不是为express这种运行在服务器端的.js文件,而准备的。

webpacktarget参数,参考官方的文档说明:

在本文中,需要对express相关代码进行编译合并。如果不设置targetnode,就可能会得到大量一系列的错误提示信息。可以参考下面的文章:

关键点之jsx

server.jsx文件,在使用webpack进行编译的时候,文件改名为server.js,也是完全没有问题的。这主要归功于webpack.config.js文件中,babel对于.jsx?$文件的处理。

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader", 
          options: {
            presets: [
              "react-app",
              "@babel/preset-env",
            ],
          },
        },
      },
    ],
  },
};
以正则角度来说的话,它指的就是.js.jsx两种文件。

配置优化点

下面属于配置优化点,非必须的修改。

优化之babel

从优化角度来说,.babelrc文件也可以移动到webpack.config.js文件中,这样更加明确一些。

options: {
  presets: [
    "react-app",
    "@babel/preset-env",
  ],
},

优化之mode

mode也可以移动到package.json里面的scripts命令里面。也可以和@babel/core所强加的NODE_ENV都放在一起,看起来更加明了。

webpack --mode production

对待第三方库

在上面的配置中,express/react/react-dom/react-router等等都统一打包到server.prod.js里面了。苏南大叔比较喜欢这种文件打包结果。

但是,正常来说,express/react-dom/react-router等,不应该被打包到可执行文件里面去。可以通过npm i再次安装。如果需求是这样的话,可以配置webpack.config.js里面的externals选项。

module.exports = {
  externals: [
    "express","react","react-dom","react-router"
  ],
}

还可以安装一个插件webpack-node-externals,直接大一统的进行设置。

//...
const nodeExternals = require('webpack-node-externals');
module.exports = {
  //...
  externals: [
    nodeExternals(),
  ],
}

结束语

本文的目的是,构建获得直接通过node执行的server.js。苏南大叔的react相关经验文章,可以参考下面的链接:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react    webpack