优化博客开发环境和页面响应
之前博客使用的是gulp
+ gulp-webpack
构建前端开发环境,存在无法支持热更新、无法自动同步文件hash等问题,因此在v0.5.0
版本对整个静态资源开发环境进行了重构,比较完整地实现了node服务端渲染项目中的前端开发环境,下面是整个开发环境的实现整理。
此次版本更新主要进行了下面工作
- 优化开发环境和部署流程
- 优化页面响应
优化开发环境
在之前的版本,为了解决SEO的问题,进行了同构渲染,带来的一个问题是无法像SSR那样利用vue-cli比较舒适的前端开发环境,这个版本主要需要解决这个问题
理一下对于环境的需求
- 在开发环境下,进行模块开发,支持scss、es6、热更新等基础功能
- 在生产环境下,代码合并压缩、页面资源路径自动修改hash
乍一看直接使用webpack就可以解决这些需求,遇见的问题是:同构渲染的页面模板是后台渲染的,利用html-webpack-plugin
无法及时为控制器提供需要渲染的模板,之前尝试输出后台模板,折腾过一次失败的HTML模块化尝试,后面发现这种通过webpack输出模板然后交给后端渲染不是一个很聪明的做法(除非是输出一个纯粹的html文件)
公司的项目一直在使用fis3进行打包,fis3有一个十分有用的特性:静态资源映射表,在这篇文章中,给出了基于资源映射表的模块化方案设计示例。
fis静态资源管理的核心是map表(文件中带__RESOURCE_MAP__标记的会自动替换成map表),里面记录了资源的请求地址、依赖等关键信息,可以根据项目需求添加更多的信息到其中。无论是哪种后端资源管理方案,都是通过读取map表来管理资源
同步打包后的模板资源文件路径
根据这个思路,如果webpack也输出了这个静态资源映射表,就可以在后台项目中读取到,然后将对应的资源引用(script、link标签等)输出到模板中,完成webpack的输出文件和模板需要的静态资源之间的桥接,从而绕开html-webpack-plugin
插件的引入。
因此,我们的问题就只有一个:在webpack打包时输出对应的map.json
,为了实现这个功能,改写了npm run build
脚本,相关代码位于/scripts/build.js
下,核心逻辑如下
let config = require("../static/webpack.config")({production: true})
const bundler = webpack(config)
bundler.run((err, stats) => {
let assets = stats.toJson().assets
let outputFile = getOutputFileName(assets)
outputFile = getOutputFilePath(outputFile, config.output.path)
createOutputMap(outputFile)
})
每次后台项目每次启动时都会访问map.json
,然后将资源路径埋入页面上
// render.js
let isProduction = process.env.NODE_ENV === 'production' // 是否为生产环境
let isDevelopment = process.env.NODE_ENV === 'development' // 是否为开发环境
// 获取生产环境的资源路径
function getProdResource() {
try {
return require("./map.json")
} catch (e) {
console.log("未检测到webpack输出文件,执行npm run build")
throw e;
}
}
// 获取本地开发环境webpack资源路径
function getDevResource() {
// ..
}
let staticResource = isProduction ? getProdResource() : getDevResource()
module.exports = {
staticResource,
isProduction,
isDevelopment
}
由于webpack输出的是一个完整的bundle文件,因此也不再需要requirejs和seajs等工具,因此在输出的map.json
中,我们甚至不需要资源的依赖信息,只需要获取输出文件名即可。
根据map.json,我们可以确保在页面上访问到正确的资源,而重新打包编译的hash值会立即更新在map.json
中,程序启动时重新获取相关输出,并映射到模板的静态资源标记即可。
开发环境时热更新
在常规的webpack项目中,通过webpack-dev-server
启动热更新服务器,在webpack.config.js
中配置devServer
,然后使用webpack-dev-server --inline
启动即可
{
entry: {
index: path.resolve(__dirname, './index.js'),
},
devServer: {//配置此静态文件服务器,可以用来预览打包后项目
contentBase: path.resolve(__dirname, './'),//开发服务运行时的文件根目录
host: 'localhost',//主机地址
port: 8080,//端口号
compress: true, //开发服务器是否启动gzip等压缩
}
}
此时,只需要在页面上引入localhost:8080/index.js
路径,就可以实现开发环境热更新了,因此这个需求实现就比较简单,判断开发环境,然后开发环境输出webpack-dev-server
服务器对应的虚拟资源即可
回到上面的render.js
,补充getDevResource
方法的实现
// render.js
function getDevResource() {
let webpackConfig = require("../../static/webpack.config")({development: true})
let {port} = webpackConfig.devServer
return {
css: `//localhost:${port}/index.css`,
js: `//localhost:${port}/index.js`
}
}
由于整个博客的页面数量较少,且采用同构渲染,因此只配置了一个入口文件;在多页面项目中,只需要稍微对map.json
文件进行修改,即可按url分配对应模板所需的静态资源了。
小结
通过webpack,解决了开发环境所需要的大部分需求,而map.json
的解决了打包时输出和后台模板之间的同步问题。 此外此次版本更新升级webpack到了v4.26,部分配置与之前还是有一点差别。
下面是目前版本的一些指令,通过区分了开发环境和生成环境
开发环境
# 启动静态资源服务器
npm run static
# 启动spervisor服务器
npm run dev
生产环境
# 静态资源打包
npm run build
# 启动服务器
npm run start
优化页面响应
服务器访问速度一直提升不上去,切换页面也经常需要加载好几秒钟,此次进行了静态资源打包的升级,增加了文件hash值,因此可以配置nginx缓存。
考虑到博客更新频率不是很高,因此将域名下所有url都配置了一天的缓存。现在通过浏览器缓存访问博客,响应速度比较快,除了首次进入的页面,基本不会展示loading动画
server {
listen 80;
server_name www.shymean.com;
root /usr/share/nginx/ShyMean/;
index index.html index.htm;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
expires 1d;
access_log off;
add_header Cache-Control "public";
}
}
当然,关于站点的响应速度优化,仅仅配置nginx缓存是远远不够的,除开服务器硬件的限制,其他的优化方案也会陆续跟进,如
- 静态资源部署至七牛云服务器
- 字体图标体积优化
- 样式、脚本文件懒加载
由于整个博客网站同构渲染的特殊性,与传统的服务端渲染及现在的单页面应用响应优化均有一些差异,因此后续优化方案会继续整理在博客中。
其他
增加demo页面
整理了一些练手项目,放在demo页面
升级https
将博客站点升级到了https,相关记录:升级博客到HTTPS。
部署脚本优化
由于服务器性能比较差,npm install
和npm run build
时经常遇见问题,因此决定远程机器上仅做部署处理,不再执行打包功能。
function deploy() {
let shell = require('shelljs');
let version = shell.exec('lsof -i:3000', {silent: true}).stdout;
let rePid = /\s(\d+)\s/.exec(version)
let pid = rePid && rePid[1]
let script = [
"git pull origin master",
// "npm run build",
"forever stop 0",
( pid && `kill ${pid}`) || 'echo 1',
`forever start -c "npm run start" ./`
]
shell.exec(script.join(";"));
}
小结
距离上次博客站点的更新(从SSR转换为同构渲染)已经过去了很长一段时间,这次的优化主要重构了前端的开发环境,为后续的性能优化和部署做一个铺垫。
你要请我喝一杯奶茶?
版权声明:自由转载-非商用-保持署名和原文链接。
本站文章均为本人原创,参考文章我都会在文中进行声明,也请您转载时附上署名。