初探parcel及如何简单写plugin
前言
入了前端坑,哪有不研究下打包工具的。但本人还是拖了好久才把webpack作了较全面的了解,webpack确实是十分灵活,这得益于其较多的配置项,特别在resolve
里,能达成某些奇特的结果。其外,loader解析文件,plugin注入钩子,修改打包过程。可以说,webpack是十分万能,再复杂的项目也能够驾驭。但是,这些复杂的配置,对于初学者是十分不友好的,即使是再简单的项目,还是要写出一个基本的配置项,这时候往往要到官网去复制粘贴,有时忘记的某个配置项的作用,又要重新找(2018/1/15了解到webpack4.0终于要增加默认配置了issue)。即使你是较了解webpack了,但还有各种优化坑等你,不然开发构建慢、打包出来的js块十分大,没有懒加载、无法清理缓存。
前一段时间,parcel出来,号称零配置,开箱即用(其实有时还是要写配置文件,不过是主要是针对某些plugin,如:typescript)。除零配置之外,还号称在某些情况能大大加快打包速度,理由是针对一个文件只会编译一次,即使是由多个plugin,这是使用的AST的好处。还有一个比较符合我们前端的设计,入口文件就是html。
使用
node的版本请必须的8以上,在源码及其他人提供的plugin源码中,都能容易看到对node是否8以上的版本的判断,低于8的话往往是会报错的,因为基本都使用了async
的语法。
使用parcel,开发时就基本只需要使用以下两个命令:
- 开发:
parcel index.html
- 打包:
parcel build index.html
目前官方已针对各大框架写了例子,还有推荐的各种plugin,地址:awesome-parcel。
各例子其实也十分简洁,没有配置项,只是在package.json里帮你加好打包需要的plugin。
再复杂的例子的话,如vue+typescript的话要自己去加plugin,这个我刚好找到一个vue+typescript
想自己从头敲学习的话,可以看这个all-you-need-to-know-about-parcel
编译过程及plugin
对于如此友好的打包文件,当然是要了解下其过程,还有plugin的编写,方便以后确实需要自己去修改plugin或写自己的plugin的时候。
在源码的src里,cli.js
是脚本命令入口,在里面会导入真正的编译入口Bundler.js
,并构建对象
const bundler = new Bundler(main, command);
打包前bundler.start是一定会运行的,其中就会加载并注册plugin,怎么加载的呢?就是把package.json
的plugin依赖都加载了。
let deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
for (let dep in deps) {
if (dep.startsWith('parcel-plugin-')) {
let plugin = await localRequire(dep, this.mainFile);//加载
await plugin(this);//注册
}
}
所以我们需要什么plugin,只要把其加入到package.json
里就好,虽然可以发现放在生产依赖里也行,但这些明显是开发使用的,还是放在开发依赖中比较好,而且优先级也更高,不会被覆盖。
接着我们进入到plugin,官网内置的plugin其实都在parcel-bundler\src\assets里,只是不叫plugin,他们都继承于parcel-bundler\src\Asset.js里的Asset,其中parse
方法就给用来自定义编译内容的。
默认会注册以下插件(是根据文件扩展名去使用对应的插件):
this.registerExtension('js', './assets/JSAsset');
this.registerExtension('jsx', './assets/JSAsset');
this.registerExtension('es6', './assets/JSAsset');
this.registerExtension('jsm', './assets/JSAsset');
this.registerExtension('mjs', './assets/JSAsset');
this.registerExtension('ml', './assets/ReasonAsset');
this.registerExtension('re', './assets/ReasonAsset');
this.registerExtension('ts', './assets/TypeScriptAsset');
this.registerExtension('tsx', './assets/TypeScriptAsset');
this.registerExtension('coffee', './assets/CoffeeScriptAsset');
this.registerExtension('json', './assets/JSONAsset');
this.registerExtension('yaml', './assets/YAMLAsset');
this.registerExtension('yml', './assets/YAMLAsset');
this.registerExtension('gql', './assets/GraphqlAsset');
this.registerExtension('graphql', './assets/GraphqlAsset');
this.registerExtension('css', './assets/CSSAsset');
this.registerExtension('pcss', './assets/CSSAsset');
this.registerExtension('styl', './assets/StylusAsset');
this.registerExtension('less', './assets/LESSAsset');
this.registerExtension('sass', './assets/SASSAsset');
this.registerExtension('scss', './assets/SASSAsset');
this.registerExtension('html', './assets/HTMLAsset');
这样就比较明白如何简单写出一个plugin了,首先项目名需要parcel-plugin-
来作开头。
新建自己的asset文件,并导入继承Asset
的对象,并编写parse
方法;
最后plugin入口index.js:
module.exports = function (bundler) {
bundler.addAssetType('你针对的文件扩展名', require.resolve('你的asset文件'));
};
最后
parcel的热度确实比当年的webpack高,但目前来看,其生态还不完善,即使是官网推荐的plugin,里面的某些功能也是表示在实验中的,不建议现有比较复杂的项目从webpack迁移到parcel里。比较简单的起始项目推荐去尝试。
你们的赞赏是我的无限动力