初探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里。比較簡單的起始項目推薦去嘗試。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。