一、 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 codeNode.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);
}
})
}
]