过于复杂繁琐的 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 解决。