初探Parcel

昨天趁有点时间看了前不久很火的构建工具Parcel,这里说下初步使用的感受,尤其是将其放到实际项目中和Webpack进行比较。

一、前言

首先说下笔者目前的技术栈。最近的前端项目主要以管理后台为主,技术栈都是React.js这套,版本为较新的版本。Webpack构建工具体系由create-react-app脚手架初始化,在后文中我们称其为CRA。因CRA的默认打包功能不太适合规模较大的项目,笔者eject出打包相关的配置文件,在原基础上添加了额外功能:

1. 代码分割与模块异步懒加载

2. 模块按需加载

3. less以及postcss的支持

4. 字体文件的打包

5. JS模块热替换(原始只支持样式的热替换)

6. dev-server(Express)正向代理、HTTPS的启用以支持h/2协议

7. HappyPack多线程编译优化

等等

在此基础上,我又通过Yemoman将整套工程化方案和代码模板进封装成Generator,逐渐沉淀出了我们团队自己的脚手架。这套东西既继承了CRA在工程化方面的最佳实践,也满足了我们的业务要求,并能帮助我们快速地初始化新项目。

其中,前5项考虑到资源大小、首屏性能、样式的兼容以及书写的方便、整体开发的便捷性,是无论在dev或是production环境都会有的。

而第6项正向代理是因为笔者这个项目的底层是分布式文件存储系统 + 基于Cluster模块的Node.js集群 + MongDB分片式集群 + HA集群,dev环境是跑在Vagrant Centos7.x虚拟机集群里的,production环境是直接跑在Centos7里的,对操作系统以及机器硬件依赖大。数据流从文件存储系统底层传递到Node.js层再传递到Web前端,且Web前端和Node.js后端只有基于HTTP、Websocket的交互,在开发时出于工程化的考虑,直接和底层环境隔离,进而方便调试,无需到Vagrant起的虚拟机中部署修改后的前端代码,也无需Fiddler或者Charles代理服务端的文件到本地文件,或是依赖Jekins持续集成。只需要Webpack的dev-server代理到Node.js上层Nginx即可,在'npm start'后跟上协议 + 跑有Node.js服务的IP + Node.js进程监听的端口号即可,会将此参数传给dev-server的正向代理配置。

至于第7项,就是单纯为了提高编译速度而已,将某些loader的工作放到子线程(进程)中进行,最后返回结果给主线程(进程),让不同的loader可以并行处理资源。

由此可见,如果说你的项目很简单,CRA提供的初始功能即可满足需求,正是如此Facebook在Create-react-app中,直接把最基本的构建有关的文件都放到了node_modules中,只暴露出了命令,使用者根本不需要去维护构建有关的文件。如果说业务需求较复杂会对工程化要求高,如果CLI工具初始化的Webpack打包体系的初始功能不满足业务需求,也是需要额外加入很多东西的,并且需要我们手动去配置。

Webpack的功能确实强大,相对于Browserify来说,Webpack真的是大而全。但类似于字典的API文档和各种loader与plugin运用,无形中提高了整个工具链的技术门槛,对于大多数没有深入研究的开发者来说,只能是知道Webpack的基本用法和要点的概念,再用到具体的loader和plugin的时候再去查看文档,然后过一定时间不使用基本又会忘掉。对于初学者来说而要准确的说出某个loader或者plugin的功能和配置方法是有一定难度的。而且Webpack的每个大版本之间也存在一定的功能和API上的变化,当你熟悉了这个版本后,下一个版本就来了...... 有没有一种"铁杵磨成针"的感觉呢?

目前前端的开发模式、技术栈与工具链基本都相同,为什么不能在构建工具内部就给出能适配大多数业务需求的默认的配置而省去烦人的手动配置呢?所以Parcel号称的零配置的吸引力是很大的。

二、Parcel初探

笔者新起了一个demo项目,但功能复杂度模拟真实项目:

按照Parcel官方要求做了最基础的package.json和.babelrc配置,其他都应用零配置默认的项,不做额外配置。Parcel版本为1.9.3.

index.html为Parcel打包的入口,依赖src/index.js文件。

src文件夹为源资源目录:

src --
       |--  components      存放高度抽象的公用组件

   |--  redux      存放redux初始化、action、reducer

       |--  styleSheets      存放公共和各组件的样式less

       |--  views      存放业务视图组件

       |--  index.js      JS入口文件

路由、代码分割、Antd UI组件按需加载、Redux相关、样式等功能都支持。这是使用Parcel打包过程:

打包后的结果:

这是打包过程中对计算机硬件资源的利用:

 用笔记本开发的同学请注意散热...

三、使用Webpack打包同一个项目



笔者再起了一个项目,技术栈和上个段落中的项目相同,但使用前言中提到的Webpack工具链打包该项目。懒得修改index.html的目录,于是新建了public文件夹把index.html放进去,并删除了<script>引入,由'html-webpack-plugin'插件注入JS脚本依赖。

结果如下:

 

这是打包过程中对计算机硬件资源的利用:

四、有区别处的对比

1. 打包速度

首先当前版本Parcel在速度上绝对比Webpack未使用HappyPack时要快上很多,从计算机CPU使用率可以看出,笔者计算机CPU是i7 4770HQ 4c/8t,在执行Parcel构建时,8个线程均被使用上了,虽然超线程技术产生的额外线程的是引用率并比不上物理核心,但已经很不错了。第二次使用Parcel打包后,可以看到速度较上次还有明显提升,这是因为第一次打包生成了.cache目录的原因,可以记录上一次打包的状态。反观Webpack仅仅只能使用4个物理核心的线程,对核心线程的利用率也并不高,对超线程技术支持不友好,而且耗时很长,拖拖拉拉,当然使用上了HappyPack后会有一定改善。

其次,Parcel在处理AST的时候,只会解析一次AST,后续的转换都是在该AST上。而Webpack每个loader之间是不知道彼此的,每个loader的操作都必须要解析一次AST。

以上这些大概能解释Parcel打包速度快的原因。

2. 打包质量

在零配置下Parcel似乎没有类似于TreeShaking的按需引用技术,而导致打包出来的资源大小要大很多。总所周知,Webpack的TreeShaking能够抖掉引入包中并未真正使用的模块,但是parcel并没有,我们在disk文件夹下的src.js的下,发现了如下代码:

笔者只在代码中引用了Button组件,但是整个Antd UI库的所有组件都被打包进来了,这个srcjs文件异常庞大。如果说我们在loadsh的时候,引入了全部loadash,看在它不大的份上还情有可原,但是整个UI库的引入,导致大小提升到了4Mb,以及和使用Webpack打包出的main.js(200KB)做比较,就难以接受了。

3. 使用场景的支持性

在纯的web前端项目中,Parcel似乎没有什么问题和报错,而当我们打包Node.js项目时,会产生因为有些require写法不支持而报错等问题,当然打包后端醒目可能不是Parcel的目的。而Webpack在这方面做得较好,支持构建的应用较为丰富得多,基本上使用JS的各种项目都支持。

五、通过HappyPack给Webpack打包加速

直接上个代码例子:

没有使用的HappyPack的情况:

使用以后,需要在plugins配置下增加对应的HappyPack实例:

加入HappyPack后,在打包时,CPU使用率较之前高出很多,打包速度有明显提升。

但是笔者在HappyPack实际使用中还遇到了两个问题:

1. 对图片资源的打包,会使图片资源数据被破坏,导致图片资源无法正常使用。这个问题笔者在HappyPack的Github项目Issue里也看到有人提出过,但并没有找到明确的解决办法。

2. 对extract-text-webpack-plugin支持不好,这个插件本身就是很不稳定的一个插件。

当然以上问题可能和笔者所使用的Webapck有关的loader和plugin自身有关联。

六、总结

Parcel的零配置打包着实让人眼前一亮,但是限制还是很多的,并且为了零配置而抛弃掉了很多灵活配置,导致对打包过程和资源输出有自定义需求的时候还必须自己去修改或者使用额外的插件。那么这样一来岂不是又回到了Webpack等的老路上去了。总之如果没有太复杂的自定义的构建业务需求、也没有引用某些重型UI库,使用Parcel能够让整个打包过程很清爽,反之请使用Webpack。当然这也不是必须的,因为又会有谁在不停地打包开发环境的代码呢?

如果觉得Webpack构建太慢,可以使用HappPack增加多进程处理以达到模拟多线程的目的,充分利用计算机CPU超线程技术的功能(如果支持的话)。但HappyPack并不能完美适配所有loader或plugin,比如url-laoder就不行,HappyPack在处理image类型的时候,一定会出错,编译出来的图片不能使用,编码错乱,原因就是HappyPack传给url-loader的数据是string类型的而不是二进制buffer,导致出错。所以这一点也不能忽视。

而且一般大型项目,也会直接使用CLI脚手架工具搭建环境,像React.js官方的create-react-app一样,构建相关的文件都没有暴露出来的,提供可以直接使用的'npm start'、'npm run build'等命令。如果你不需要自定义修改,从某种程度来说脚手架工具就是零配置的。新的Webpack4.0大版本也支持零配置,如果你不需要额外的自定义功能的话。我们的项目其实就是在create-react-app基础上增加了我们需要的东西,并通过Yeoman封装了generator作为种子项目,其中包含了所有的自动化工具、编码架构、公共库、示例代码,这一套东西有助于我们可以基于一套最佳实践的模板快速地起新项目,而不是把之前的项目copy一份,把业务代码剔除掉,再进行使用的这种很low的方式。

所以Parcel还需打磨,它还不具备让开发者放弃现有构建工具的吸引力。

原文地址:https://www.cnblogs.com/rock-roll/p/9240766.html