需求
在平时纯前端的项目中我们习惯了 webpack-dev-server 和 hot module replacement 给我带来的开发方式的方便. 但是如果我们想在服务端渲染开发的时候同样拥有这种开发体验, 我们该如何?
我们先大概看下服务端渲染的简单例子:
- const express = require('express')
- const ReactDomServer = require('react-dom/server')
- const App = require('../src/app.js').default
- const App = express()
- App.get('*', function(req, res){
- const content = ReactDomServer.renderToString(App)
- const template = fs.readFileSync(path.join(__dirname, 'template.html'), 'utf-8')
- res.send(template.replace('<!--app-->', content))
- })
这里这个 App 其实就是我们平时看到的 ReactDom.render(, document.getElementById('id')) 中被渲染到页面的内容, 开发环境下这里是通过 webpack 打包自动把 JS 注入到页面执行后动态渲染的. 所以服务端渲染在开发过程中也可以借鉴这个思路读取内存中文件编译后在直接 res.send 到页面, 这样不用每次修改完代码前端去编译写入本地文件, 再去重启服务端读取新的代码, 这样虽然也行, 但毕竟费时费力.
大概的代码思路如下:
- const MemoryFileSystem = require("memory-fs")
- const mfs = new MemoryFileSystem()
- const serverCompile = webpack(webpackServerConfig)
- let serverApp
- // 将 webpack 输出系统自定义为内存中, 关键, 不然 webpack 默认将编译好的代码写入本地磁盘
- serverCompile.outputFileSystem = mfs
- serverCompile.watch({}, (err, stats) => {
- if(err) throw err
- // 将平时 webpack 编译的输出信息转为 JSON
- const info = stats.toJson()
- if (stats.hasErrors()) {
- info.errors.forEach(err => console.error(err))
- }
- if (stats.hasWarnings()) {
- info.warnings.forEach(err => console.error(err))
- }
- // 内存中的 bundlePath
- const bundlePath = path.join(
- webpackServerConfig.output.path,
- webpackServerConfig.output.filename
- )
- const bundle = mfs.readFileSync(bundlePath, 'utf-8')
- serverApp = requireFromString(bundle, 'server-entry.js')
- })
- // 上面读取的 bundle 是字符串, 我们需要将其转为我们平时代码中常见的模块方便输入输出, 这里我们利用 module 的构造函数
- function requireFromString(bundle, filename) {
- const Module = module.constructor;
- const m = new Module();
- m._compile(bundle, filename);
- return m.exports.default;
- }
- // 正常使用 serverApp
- App.get('*', function(req, res){
- const content = ReactDomServer.renderToString(serverApp)
- const template = fs.readFileSync(path.join(__dirname, 'template.html'), 'utf-8')
- res.send(template.replace('<!--app-->', content))
- })
官方中解释 webpack-dev-server 的原理就是这种, 毕竟内存中的读取比磁盘读取快多了 !
来源: https://juejin.im/entry/5c03b6b951882511a852a660