【Parcel】Webpack 过时了吗?

前言

用了超过 2 年的 Webpack,挺认可它为工程化前端开发带来的贡献,它让我在很早的时候就开始使用新语言特性进行编码、使用 Target 到 JS 的方言开发前端、集成各种好用的周边工具、让自动化测试/发布变得简单,帮助我构建了不少的大型的前端项目(包括 Electron 客户端)。
不过,即使是如此完善并且彻底革新了旧前端开发模式的 Webpack 在今后的时代也极有可能要成为过去式了,也许很多人不会认同,但如果你体验一下本文的主角 Parcel 也许就会改变固有想法:其实 Webpack 也已经过时了。

Webpack 的问题

在介绍 Parcle 之前你需要了解 Webpack 的缺点,实际上 Webpack 的缺点挺多的(包括存在的问题和理念)…… 其中有两个我想大概是任何人都无法不承认的:慢以及配置复杂。

Webpack 的速度真的很慢,特别是集成了大量 loader 和 plugin 以后,包括导入资源的数量也会有影响。其速度已经慢到需要几十秒甚至更久来完成构建过程,这甚至已经超过了比其更加庞大得多的后端编译型语言的构建时长。
对于传统前端开发而言,根本没有“构建”这一过程,所有更改都是及时更新的。而 Webpack 过长的构建时间这一巨大反差其实已经算是对前端开发体验的严重负优化,即使是编译型语言也有增量编译一说呢,何况是打开浏览器就能看到新结果的前端开发?

然后是 Webpack 被诟病已久的配置复杂问题…… 其实我接触过的构建工具还算多的,包括 Java 的 Maven/Gradle、Scala 的 SBT、Ruby 的 Rake 等,甚至我自己还开发过 Go 语言的构建工具,哪怕是相对原始很多的 Makefile,也未必比得上 Webpack 的配置麻烦。
Webpack 自身提供和需要的设置其实并不多,多数都是对 loader 和 plugin 的配置,同样的也很少有构建工具能做到像 Webpack 生态这么完善的。虽说 Gradle 的插件也非常多,但是实际上一个项目不会用到几个插件,通常是项目类型所必须的插件,而 Webpack 会随着你使用的技术的增多的同时不断的需要添加新配置,而且冗余内容还特别多……

其实还有一个严重的缺点,Webpack 只允许使用 JS 作为入口和出口,这显然会造成一些麻烦(虽然这些麻烦可以被解决)。

细说 Webpack 的缺点

Webpack 之所以慢,其设计理念就是一方面原因。入口到出口的过程中会经过多少 loader 轮流处理?并且这些 loader 还互不知道彼此的存在……
假设你要项目中同时集成 Vue 和 React,那么你无法仅通过 .js 后缀来让 vue 和 babel-preset-react 的 loader 分别处理,所以它们会按照你的定义顺序将处理好的 vue 模块再经过 react 的 loader 处理一遍,或者以相反的顺序。如果你不特意的通过一定配置和约定避免的话,就产生了冗余的 loader 转换过程,造成时间浪费甚至产出错误的结果。
例如你可以通过给 Vue 的组件的 JS 文件命名约定为 *.vue.js 或者将 React 的相关文件约定为 *.react.js,然后分别配置 loader 的 test 规则以避免这种情况发生。虽然说一般情况单页应用项目不会出现同时集成 Vue 和 React 的情况,但是 Webpack 并不是只支持单入口/出口的,所以一个 Webpack 项目可能对应着多个单页应用,它们共享着一套 Webpack 配置。

值得一提的是前段时间 Webpack4 发布了,在更新日志上,开发者们高兴的宣布 Webpack 的速度提升了 XX,并称还有很高的提升空间。这表示什么?这不正表示当前的 Webpack 存在严重的性能问题吗?

在前端领域,虽然说例如 MVC 框架这种东西经常会被重复造轮子。就像本文的两个主角,打包工具也一样…… 不过有很多的“周边工具”是极少出现这种情况的。
例如说我要在项目中使用 SASS,作为前端开发我当然会使用 node-sass,除了它我还会用什么?类似的,我使用 ES6/ES7 等语言特性,我难道能不用 Babel?但是 Webpack 想不到这一点,它仍然坚持让你自行配置所有内容。

所以不得不吐槽一下…… 你就不能直接将主流且唯一性强的工具依赖插件(或者 loader)直接集成进来,让我们用户可以开箱即用?必须通过复杂又冗余的配置显示生态的强大和理念的先进?

Parcel

在说完 Webpack 深恶痛绝的一些毛病以后,再介绍 Parcel 会发现这家伙就是跟 Webpack 对着来啊:

Parcel 主打的优势的零配置,并且有很快的构建速度。注意是零配置,不是简单配置或者少配置,并且官方直接给出了比 Webpack 快十倍的测试结果数据。而且,Parcel 的入口并不限制为 JS,可以使用 HTML 作为入口引用其它资源作为间接入口。

在体验 Parcel 之前先安装它:

npm i -g parcel-bundler

这是一个 Parcel 的例子:

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
    <meta charset="UTF-8">
    <title>Parcel 入门</title>
</head>
<body>
<div id="root"></div>
<script src="src/entry.js"></script>
</body>
</html>

你只需要复制粘贴创建这个 HTML 文件,然后创建一个引用路径中的 JS 文件,最后执行:

parcel index.html

仅此而已,一个自带 webpack-dev-server 和配置好入口出口以及 html-template 插件的项目就这样集成好了。
不,上面当然是开玩笑的,Parcel 的实现跟 Webpack 一点关系都没有。但是上面那句话说明了对于 Webpack 而言要达到同等效果需要进行的配置(实际上 Webpack 要达到同样的效果所进行的配置远不止这么少)。

如果你要使用 Babel 和 ES2015,创建 .babelrc 即可:

{
  "presets": ["env"]
}

仅此而已,Parcel 会自动根据你对 Babel 的配置文件的配置进行对 Babel 的集成。注意 .babelrc 是 Babel 官方的配置文件,而不是 Parcel 的配置,所以此时仍然是零配置的,但是你已经可以随心所欲的在 entry.js 中使用 ES6 语法,你不必要关心输出结果。

集成 SASS?嗯,直接在 entry.js 中导入就行了:

import './style/sample.scss'

function action() {
    console.log('Hello world!')
}
(action)();

你甚至不用添加 node-sass 依赖,因为 Parcel 会自动完成。同样的,你不需要进行任何的手动集成,不需要关心输出结果。

使用 React?添加好依赖直接撸吧!

yarn add --dev react reacr-dom

该怎么组织 React 代码就怎么组织,不需要关心输出结果,不用手动集成你便发现浏览器已经展示出 React 框架正常工作的样子了。。。

上线生产?一个 build 指令叫你做人:

parcel build

在自动创建出来的 dist 目录中看看输出文件的源码,是不是发现资源压缩、 Hash 命名、URL 重写什么的都不用你操心?打开网页再看看 React 是不是已经工作在 Production 模式下了?

一切就是这么简单,这就是 Parcel。也许当前 Parcel 跟 Webpack 生态相比完备程度差一点,但是成长速度极快,并且已经完全够用了。更多用法请访问官网:https://parceljs.org

结束语

祝愿大家都能早日结束 Webpack 的苦海…… 当然,如果 Webpack 在以后也意识到约定和默认配置以及自动集成的重要性的话,哪怕是下下下个版本我也会保持一点点小小的期待。

但若仍然麻烦如初,只能说声再见再也不见了:)