一、 webpack 进阶用法的 SSR 打包、优化构建命令、构建异常和中断处理
- 页面打开过程,开始加载 ->
HTML
加载成功后开始加载数据 -> 数据加载成功后渲染成功开始、加载图片资源 -> 图片加载成功、页面可交互 - 服务端渲染
SSR
是什么,如下所示:
- 渲染:
HTML + CSS + JS + Data
-> 渲染后的 HTML
- 服务端:所有模版等资源都存储在服务端,内网机器拉取数据更快,一个
HTML
返回所有的数据
- 浏览器和服务器交互流程,请求开始 ->
server -> HTML template、data -> server render
-> 浏览器解析并渲染,用户呈现 -> 加载并指向 js
和其它资源 -> 页面完全可交互 - 客户端渲染
vs
服务端渲染,服务端渲染 SSR
的核心是减少请求,如下所示:
- 客户端渲染,请求是多个请求(
HTML
、数据等),加载过程是 HTML
和数据串行加载,渲染是前端渲染,可交互是图片等静态资源加载完成,JS
逻辑执行完成可交互 - 服务端渲染,请求是 1 个请求,加载过程是 1 个请求返回
HTML
和数据,渲染是服务端渲染,可交互是图片等静态资源加载完成,JS
逻辑执行完成可交互
SSR
的优势,减少白屏时间,对于 SEO
友好。SSR
代码实现思路,服务端使用 react-dom/server
的 renderToString
方法将 React
组件渲染成字符串,服务端路由返回对应的模版,客户端打包出针对服务端的组件,代码如下:
const express = require('express');
const { renderToString } = require('react-dom/server');
const SSR = require('../dist/search-server');
server(process.env.PORT || 3000);
function server (port) {
const app = express();
app.use(express.static('dist'));
app.get('/search', (req, res) => {
console.log('Server response template', renderToString(SSR));
res.status(200).send(renderMarkup(renderToString(SSR)));
});
app.listen(port, () => {
console.log('server is running on port;' + port);
});
}
function renderMarkup(html) {
return `
<!DOCTYPE html>
<html>
<head>
<title>服务端渲染</title>
<meta charset="utf-8" />
</head>
<body>
<div id="app">${html}</div>
</body>
</html>`;
}
webpack ssr
打包存在的问题,如下所示:
- 浏览器的全局变量,
Node.js
中没有 document、window
,组件适配将不兼容的组件根据打包环境进行适配,请求适配将 fetch
或者 ajax
发送请求的写法改成 isomorphic-fetch
或者 axios
- 样式问题,
Node.js
无法解析 css
,方案一是服务端打包通过 ignore-loader
忽略掉 CSS
的解析,方案二是将 styled-loader
替换成 isomorphic-style-loader
- 如何解决样式不显示的问题,使用打包出来的浏览器端
html
为模版,设置占位符,动态插入组件,代码如下:
<body>
<div id="root"></div>
</body>
- 首屏数据如何处理,服务端获取数据,替换占位符,代码如下:
<body>
<div id="root"></div>
</body>
- 当前构建时的日志显示,展示一大堆日志,很多并不需要开发者关注,对于统计信息
stats
,如下所示:
errors-only,none
,只在发生错误时输出minimal,none
,只在发生错误或有新的编译时输出none,false
,没有输出normal,true
,标准输出verbose,none
,全部输出
- 如何优化命令行的构建日志,使用
friendly-errors-webpack-plugin
,success
构建成功的日志提示,warning
构建警告的日志提示,error
构建报错的日志提示,stats
设置成 errors-only
,代码如下:
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name][chunkhash:8].js',
path: _dirname + '/dist'
},
plugins: [
new FriendlyErrorsWebpackPlugin()
],
stats: 'errors-only'
};
- 如何判断构建是否成功,如下所示:
- 在
CI/CD
的 pipline
或者发布系统需要知道当前构建状态 - 每次构建完成后输入
echo $?
获取错误码
- 构建异常和中断处理,如下所示:
webpack4
之前的版本构建失败不会抛出错误码 error code
Node.js
中的 process.exit
规范,0 表示成功完成,回调函数中,err
为 null
;非 0 表示执行失败,回调函数中,err
不为 null
,err.code
就是传给 exit
的数字
- 如何主动捕获并处理构建错误,
compiler
在每次构建结束后会触发 done
这个 hook
,process.exit
主动处理构建错误,代码如下:
plugins: [
function () {
this.hooks.done.tap('done', (stats) => {
if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') == -1 ) {
console.log('build error');
process.exit(1);
}
})
}
]