前言
入了前端坑,哪有不研究下打包工具的。但本人還是拖了好久才把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里。比較簡單的起始項目推薦去嘗試。