下一代零配置打包工具 Parcel 初体验

1,942 阅读5分钟
原文链接: zhuanlan.zhihu.com

过于复杂繁琐的 webpack 配置一直是前端项目里的一个痛点,而新一代的“零配置”打包器 parcel 正在解决这个问题,春节回来之后的这几天我尝试把手上的业务迁移到 parcel 构建,下面就是一些踩坑心得。

先说结论:

  • parcel 极其适合小型单页 React 页面的打包构建,真的是完全零配置
  • 对于 vue,目前 parcel-plugin-vue 存在一些坑(详细请看这个 issue),现在已经修复,但 parcel-plugin-vue 还未更新。
  • 对于大型多页的项目,parcel 打包构建没有问题,但目前 parcel 1.6.2版本还不支持 CommonsChunk 和 Tree Shaking,对于 alias 的支持在下个版本才会加入,所以构建出来的 js 体积还比较大。

快速上手

先从一个极简的 React 应用开始,首先当然是先安装:

npm i parcel-bundler -g

然后你可以随便写一个 React 的 Hello World:

<!-- index.html -->
<html>
<body>
    <div id="root"></div>
    <script src="./index.js"></script>
</body>
</html>
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
  <h1>Hello, parcel!</h1>,
  document.getElementById('root')
);

我们这里用到了 ES6 语法,以及 JSX,但与 webpack 不同的是,我们不需要额外地配置一堆 loader 和插件,不需要区分开发/生产环境的构建配置。

为了这段 ES6/JSX 的代码能跑起来,只需要安装一些 babel 插件就可以了:

npm install babel-preset-env
npm install babel-preset-react

然后写一个 .babelrc:

{
  "presets": ["env", "react"]
}

然后,就可以跑起一个自带 HMR,支持 ES6/JSX 语法等等高阶特性的本地开发环境:

parcel index.html

对于常见的图片、less文件什么的,parcel 当然是天生支持的,无需任何配置:

// 来一张图片
import yourImage from '123.png';
// 来一个 less 文件
import 'index.less';
ReactDOM.render(
  <img src={yourImage} />,
  document.getElementById('root')
);

构建也很简单:

parcel build index.html

使用 Parcel 构建 Vue 项目

与 React 稍有不同的是,我们要额外安装一个 parcel-plugin-vue 来支持对于 .vue 文件的加载:

npm i parcel-plugin-vue

然后就非常简单了:

<!-- index.html -->
<html>
<body>
    <div id="root"></div>
    <script src="./index.js"></script>
</body>
</html>
// index.js
import Vue from 'vue'
import App from './index.vue'
new Vue({
  el: '#root',
  render: h => h(App)
})
<!-- index.vue -->
<style lang="less" scoped>
    div {
        font-size: 50px;
        text-align: center;
    }
</style>

<template>
  <div>hello {{text}}!</div>
</template>

<script>
    export default {
        data() {
            return {
                text: 'parcel'
            }
        }
    }
</script>

跑起来:

parcel index.html

我们这里使用了 .vue 文件,里面包含了 less 方言、es6 语法,而这些都不需要额外的配置。

vue 项目的一些坑

1、报错 Uncaught TypeError: Cannot read property 'add' of undefined

我们上面的例子使用的是 parcel 1.6.2 以及 parcel-plugin-vue 1.5.0,有可能会遇到这个错误,这个错误本质上是 parcel-plugin-vue 中错误地重写了 parcel 的一处方法导致的,现在已经得到修复(详情请看这个issue),不过目前 parcel-plugin-vue 还没发布修复后的新版本,可能要再等几天。

2、报错 Unknown Version 6.2 of samsung

在一些旧项目中可能会遇到,这是由于本地 browserlist 依赖的 caniuse-lite 版本太旧导致的,更新 caniuse-lite 可以解决:

npm i caniuse-lite

生产环境中使用 parcel 的正确姿势

1、本地开发环境

parcel 打开开发环境其实很简单:

parcel xxx.html

但在大多数项目中,我们更偏向于使用项目内安装的 parcel,而不是全局安装的 parcel,所以我们会写一个 npm script,然后 npm run dev

{
    "scripts": {
        "dev": "parcel xxx.html"
    }
}

但项目内有可能会存在多个页面,为每个页面都写一个 npm scripts 会很麻烦,所以我们可以配合 npm scripts 的参数来解决:

{
    "scripts": {
        "dev": "parcel" // 这里不写页面名
    }
}

然后

npm run dev -- /path/to/xxx.html

注意 -- 和路径之间有一个空格,这样 npm 就会把路径识别为 parcel 的参数。

2、多页面项目的构建

parcel 目前还不支持多入口,所以只能一页一页地构建,我们可以通过 shell 脚本来自动解决。

例如,我们的项目结构是这样的:

src
└── page
    ├── page1
        ├── index.html
        └── index.js 
    ├── page2
        ├── index.html
        └── index.js 
    ├── page3
        ├── index.html
        └── index.js 
    └── page4
        ├── index.html
        └── index.js

那么我们可以写一个 build.sh 作为构建脚本:

# 先清空 dist
rm -rf dist
mkdir dist

# 对 page 文件夹下的每一个 name 都进行构建
cd ./src/page
for name in $(ls)
do
    echo building $name ...
    npm run parcel:build -- src/page/$name/index.html -d dist/$name --detailed-report
done

注意我们这里使用了 parcel:build 这个命令:

{
    "scripts": {
        "parcel:build": "parcel build"
    }
}

使用 parcel 构建的优劣总结

优点:

  • 零配置真的爽,爽啊爽啊就是爽,用了就回不来了,完全告别几百行复杂的 webpack 配置。
  • 构建速度比 webpack 快很多,内置了大量 webpack 配起来十分蛋疼的东西(比如 HMR、dev server、各种 loader)。
  • 完全可以应对大型项目的开发及构建。

缺点:

  • webpack 的一些高阶特性还不支持,比如 CommonsChunk、Tree Shaking、多入口文件、自定义构建出的文件名、内联小尺寸的图片、内联css等,所以构建出来的资源体积都比较大。
  • 目前对于大型项目的构建还需要额外写 shell 脚本(但我真的觉得比写 webpack 构建简单太多了)。
  • 还处在快速迭代期,特殊情况下可能会有奇怪的报错,需要自行 debug 解决。