现在开启一个新的系列,主要是对前端常见的知识点从较高层次谈一下理解,不会过多深究细节。
概览
根据打包使用场景的区分,环境可以分为开发环境和生产环境,在各个环境的我们想达到的目的不一样,因此要做的事也不一样。
开发环境主要用来进行项目的开发,对我们最重要的是修改后立刻生效以及方便debug的sourceMap,生产环境的打包是为了部署上线投入使用,因此需要好的访问性能,比如需要压缩和合并以减少http请求。
我们这里主要关心的是开发环境,在webpack和rollup中,开发和生产的主要流程相似,开发环境每次修改也会像生产一样执行一次打包,只是会有一些优化。
而在vite的开发环境,除了首次运行时对第三方依赖就行预构建(比如将cmj等转化为esm,将暴露很多模块的依赖合并以减少网络请求数)外,源码的首次和修改后的更新都主要由浏览器的原生module系统进行必要的转换更新(不需要像生产那样打包),因此速度快得多。
两种打包器
最常见的两种打包器是webpack和rollup,思路都是从入口出发,处理各种依赖后,输出到出口文件中,然后在我们的html文件中引用。
这两个打包器的最大区别是webpack为了兼容各种模块系统,在最终的bundle中添加了自己实现的加载和解析模块的runtime,rollup用将不同模块按顺序排列解决依赖关系,重命名解决全局作用域问题,因此最终的size会比后者大。
其他的,webpack和rollup在功能上已经很相近了,具体可以参考bundlers.tooling.report/。 对两者的选择通常的结论是打包app用webpack,打包library用rollup,在实际的使用中,可能有两点需要注意的,
一个是rollup本身比较简单,这也是很多人吐槽webpack的点,但是简单意味着实现较为复杂的功能时需要自己到处找插件或者自己写插件,而webpack对大部分场景都提供了现成的实现,比如没有开箱即用的hmr,官方推荐使用另一个兼容的打包器Nollup来对开发环境提供支持。
另一个是遇到问题时rollup的参考资料比较少。
webpack的开发环境
webpack提供了几种方式来避免修改源码后手动打包,比如
- watch模式可以自动打包,但需要手动刷新浏览器
- 启动一个服务器,比如express,并借助一些插件,比如使用webpack-dev-middleware将打包后的文件输出到内存而不是硬盘,再加上webpack-hot-middleware,它会维持一个Server Sent Events连接,客户端监听服务端消息推送并结合webpack hmr api实现模块热替换。可参考这里。
- webpack提供了一个上一项的现成实现,webpack-dev-server可以直接使用。
react的hmr
从前面第二种方法说起,如果只是使用了对应的插件,每次修改会将组件的局部state重置(如果是全局的状态,比如redux,依然会保存),因此还要引入react-hot-loader。
对vue等其他框架也有对应的插件,可以按需添加。
rollup的开发环境
rollup侧重于生产环境,开发环境可以用serve作为服务器,用live-reload进行修改后自动刷新浏览器。
打包library
打包app的目的是生成可以部署上线的代码,侧重于线上性能,打包library是生成提供给其他项目使用的依赖,因此有两点不同
- 需要对外暴露接口,包括选择某种类型的模块系统,webpack常用的是umd,本身不提供es module,rollup支持各种类型,可以选择es或其他,注意package.json中module和main的设置
- 因为lib只是用户的依赖之一,因此可以将lib的部分依赖置为external,就下载对应依赖的工作交给使用者来减少打包体积。