近期在公司把 PC-WWW 项目从之前比较复杂的脚本改成了webpack,随后因为看到webpack2发布了正式版本又升级到了 webpack2。效果非常好。
为什么使用 webpack
webpack 是一款非常非常强大的前端资源处理工具,可以把所有前端需要的资源统一处理。比如js文件,css文件,甚至图片,字体文件,html文件。通过一个个独特的 loader 来对文件进行一些处理。
比如可以通过 babel-loader 对使用ES2015+的js代码进行编译处理,改成浏览器可以理解的es5甚至是es3的语法。通过css-loader对css文件进行一些处理,比如hash掉class名,通过stylus-loader将stylus语法的文件转成css语法,通过file-loader对图片进行处理,等等等等。
还有更强大的功能么?当然是有的。
可以通过配置publicPath将静态资源文件直接改成cdn路径。通过html插件将资源文件直接写入html。仅仅通过一个-p
参数实现生产环境的配置。通过react-hot-loader
实现热重载。通过postcss-loader对css文件进行添加前缀,变量支持等处理。
webpack 使得前端开发变得更加工程化,更加合理,更加舒适,更具有灵活性。
为什么升级 webpack2
既然 webpack1 已经很好用了,为什么还要费大力气升级 webpack2,而且坑也比较多。
主要是因为两个原因:
如果哪位读者做过服务端渲染就会知道,路由的异步加载需要用到 require.ensure,但是这在服务端没有,所以需要 polyfill,很麻烦。而升级到 webpack2 的话就不需要处理这些,用自带的 import
即可。
webpack2 用了 Treeshaking。可以分析引用文件,进而不加载不需要的文件,有效减少文件的大小,减少一定的加载时间,提升用户体验。
就最后的结果来看,服务端渲染正常,而前端js代码文件明显减少,效果很好。
结构
整个结构分为这么几个部分:
一个基础配置模块,用以把通用的配置抽离出来。
一个开发配置项,一个服务端配置项,还有一些特殊的配置脚本
因为yarn拥有更快的安装速度,比较推荐yarn,如果不熟悉,可以看一下这篇文章了解一下
dev
由于使用了react-hot-loader,需要在entry加上一些配置
react-hot-loader 是用来热加载组件的,简单来说修改组件以后可以自动在局部刷新,而不用整个页面刷新。可以减少等待时间,使得整个过程没有之前整页刷新那样痛苦。
至于output的配置也是比较正常的,有一点需要注意的是尽量使用 path.resolve
来解析路径。
output 的作用是告诉 webpack 应该将文件输出在哪里,以什么样的名字输出
module 是主要的文件处理规则,需要处理的文件在这里定义规则:.css文件需要用css-loader来处理这样的规则。所以 module 的地方配置项变了很多,需要一些调整:
这个module因为dev和server两个部分都要用,所以把它写成了一个func放在base中。至于做成函数而不是配置项是因为css需要在服务端渲染的时候需要切换成另一套配置。
getCssLoader 的作用是根据不同的参数,返回不同的css配置文件:在服务端渲染阶段,只用生成名字即可,无须将内容输出,而在浏览器中不仅需要生成对应的名字,而且也需要将文件输出,使得样式可见。
因为上面定义了 getModules, 所以现在只要调用就可以得到相应的module配置了,这样webpack就知道如何处理对应的文件:
plugins 是一些插件的配置, 而新版取消了几个配置,这些插件目前感觉是比较合适的:
其作用分别是热更新插件,配置项插件,相同文件打包插件,环境变量定义插件,HTML处理插件,css样式提取插件
还有resolve配置,也就是少写点儿后缀名:
devServer是在开发阶段用到的一些配置,也需要进行一部分设置:
这里的proxy作用是对请求进行拦截,转发至另外的服务器。在这个配置中通用的做法是把请求转到mock server上。可以根据自己的需要进行配置,如果有多个配置项推荐写成一个函数调用:
到这里,整个开发环境的配置就完成了。可以通过写入npm script来进行调用,这样就又可以少打几个字:
server
项目中用到了server render,所以还需要对服务端代码进行打包。打包过程分为两个部分,分为客户端打包和服务端打包。之所以分为两个部分是因为两个部分需求不同,客户端需要代码压缩,需要css文件输出,需要把外部文件打包出来。而服务侧代码则不同,完全拒绝代码压缩,css不需要文件输出,外部node模块直接引用,而无需打包。
在客户端的打包配置如下:
在服务端渲染的时候用了ejs
作为模板,里面用了一些语法,所以需要include,这里不给出具体的实现了,作用就是把一些需要include的文件加载进来。
服务端的打包比较类似,不过要加上target和一些output的改变, 还有一定要注意不要打包到 public 目录下,这个文件是不能让用户访问得到的:
这里的getExternals是把整个node_modules
作为externals:
最后的导出需要导出一个数组,webpack是可以接受的:
同样写入到npm scripts中
注意事项
其实之前漏掉了一个很重要的配置:.babelrc
根据官网说是要把 es2015 设置成这样,因为webpack会自动识别并处理:
经过我亲身实践,没错,它是骗你的。
这个点说出来全是泪:有时候要加上modules: false
,而有时候不需要。我在mac下是需要加,而Ubuntu又不能加。版本更新依旧如此。
所以这个地方,你可能需要靠猜了,加modules: false
试试,如果报错类似于exports is not defined
这样的错误就去掉再试试。
变成类似于这样的就可以了:
这个插件也改了配置,需要传入对象。还有,注意不要拼错单词 😑
webpack2推荐使用import()
异步加载脚本,然而用的时候有时候会报错类似于import and export may only appear at the top level
这样的问题,解决方法是这样的:
然后加入如下内容到.babelrc中:
如果你碰到了类似于这样的报错:parseQuery should get a string as first argument
,恭喜你,你可能又踩坑了,解决方案是更新一下loader-utils
,这个问题贼坑,我在Ubuntu上没碰到,@可诚 在Mac上碰到了。
解决方法是更新一下这个包
如果你还用了一大堆postcss的插件,那么你可能需要更新到一个新的postcss.config.js
中了。
类似于这样的:
服务端渲染需要用到match,找了很多资料,都是当做同步函数使用的,然而实际上是异步的. 所以在使用的时候一定要注意。一定要注意!一定要注意!
关于服务端渲染请参考这篇文章的实现:教你如何搭建一个超完美的服务端渲染开发环境
如果你还有问题
如果你还有问题,公司的配置我不能开放出来,但是推荐你去看看我另一个项目的配置文件,少了服务端渲染的部分,但是服务端渲染所需要注意的地方在这篇文章中有了一些说明。应该不会有什么问题了的。
AnnatarHe-graduation-project/exam-online-fe
babel-polyfill
这是一个babel用于兼容低版本浏览器的包,里面又引用了core.js,包括了很多es6,7实现的一些方法的实现,这个包挺大的。如果项目中没有用到其中的一些函数,可以选择部分加载。
详细请看这里, 选择项目中用到的函数加载好了。
结论
如果不在意webpack2的无限大坑文档,其实升级之后的打包效果比较好的。
我们项目原来的三个主要文件分别是(未gzip压缩, 未去除babel-polyfill):
vendor: 283kb
bundle: 147kb
css: 18.5kb
经过webpack2的打包降成了:
vendor: 216kb
bundle: 177kb
css: 21.9kb
总共降低了37kb.
效果还是有的。
推荐你也快升(cai)级(keng)吧~😊