之前写了一篇关于webpack 如何使用的文章:webpack 单页面应用实战,并且写了一个 单页面应用的小项目 放到了github上。正巧公司前段时间用webpack 做了一个项目,项目不大,是基于单页面应用的。但是上线后才发现了一些问题,原来还是有一些要优化改进的地方。
webpack 单页面应用实战这篇文章基本已经满足了我们的需求。比如以下功能我们都已经实现:
将css从js中分离出来
使用loader加载css、图片等
使用插件生成html以便自动引用变更版本号的文件
配置公共js
js文件按需加载
配置开发环境
压缩js、css、html
给css、js、图片、字体等添加版本号
编译后自动打开浏览器
热替换
使用代理结合后端服务开发
编译时区分开发环境、生产环境、热替换环境
config 文件的合并
清空发布目录
看似不错,好像都已经实现了,但是具体到生产环境时还是有问题的。下面有几处优化(下面还是结合这个项目)。
优化-公共js版本号会变化的问题
这个问题在项目上线之前我没有发现,上线以后,有一次需求变化,我在改变其他js文件的时候,然后打包发布发现公共js的版本号发生了改变,最后检查下来,的确是公共js的内容发生了变化,所以对应的版本号发生了变化。原因就是webpack默认会把最重要的东西放到公共js里,这里面包含webpack启动应用程序的依赖项、模块与模块的依赖关系、以及文件的版本号等信息。所以一旦任意的js文件发生改变都会体现在公共js上。比如我们通过webpack构建后生成这样的文件:
再看下common.js 里大致包含什么内容(截取一小部分):
公共js版本号会变的问题在 github 上讨论了一段时间(点击这里),只不过之前没注意。有人用 webpack-md5-hash 插件实现了,但是感觉比较麻烦,最终还是感觉webpack 的贡献者实现的这种方式很简单,并且不需要额外的插件,在新版本的webpack中融合的很好。但是提供的这个demo太简单,在项目中我们还是要注意一些问题的。比如使用‘热替换’时就会报错。所以我们要做一些改变,我们只需要将之前配置公共js的地方:
// webpack.config.js
...
plugins:[
// 会把 ‘entry’ 定义的 common 对应的两个js 打包为 ‘common.js’
new webpack.optimize.CommonsChunkPlugin("common", 'js/[name].js', Infinity),
]
...
改为:
// webpack.config.js
...
new webpack.optimize.CommonsChunkPlugin(
devServer ?
{name: "common", filename: "js/common.js"}:
{names: ["common", "webpackAssets"]}
),
...
注意: ‘devServer’ 是一个标识变量,代表‘热替换’ ,如有疑惑看上一篇配置变量标识
改成这种设置以后,当时热替换模式的时候不对common.js做处理,如果是开发模式或者发布模式,会从common.js中将各个文件的版本号以及其他重要信息抽出来,放到‘webpackAssets.js’文件中(名称可以自定义)。生成的文件如下,会多出一个文件,这个文件只有几kb:
改成这种做法后,一旦其他的文件发生改变,都会在webpackAssets.js文件中得到体现,项目的发布升级,只要额外的将这个文件升级上去即可,而不用将公共js升级上去。这样的优化会非常有利于处理缓存的问题。
优化-设置模块目录
如果项目小不设置webpack请求的模块目录没关系,但是一般项目越来越大,webpack会查找很多无用的文件,这时候设置模块目录很有必要性,可以提高webpack编译的速度。即设置 resolve.root 属性。还有一个属性是 moduleDirectories,这两个的区别可以点这里。resolve.root 接收的参数是 node_modules 文件加的绝对路径。我们在之前的webpack.config.js 中增加这个配置项:
// webpack.config.js
...
resolve:{
root: [
path.resolve('./node_modules')
],
...
}
...
这样设置后,webpack编译速度会大大加快,不会每个文件夹都搜索一遍。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。