探索 parcel(tree-shaking) 構(gòu)建 vue 插件

本次我們要做的是編寫一個(gè) vue 的 Tag 組件,使用 parcel 結(jié)合 tree-shaking 進(jìn)行打包浴麻。
本次要講的重點(diǎn)是用 parcel 構(gòu)建 vue,教大家如何去寫一個(gè)可以供別的使用的 vue 組件,并發(fā)布到 npm 上采盒。Tag 組件源碼分析不是這篇文章的重點(diǎn),重點(diǎn)是構(gòu)建思路蔚润。

首先說一下為啥使用 parcel 打包而沒用 webpack磅氨,出發(fā)點(diǎn)很簡單,為了用 parcel 而用 parcel嫡纠,哈哈~~~烦租!其實(shí) parcel 有一個(gè)優(yōu)點(diǎn)就是零配置打包,這次使用 parcel 真的是一行配置代碼沒寫除盏。叉橱。。 而且 parcel-bundler 是安裝到全局的者蠕,所以就是說在整個(gè)項(xiàng)目中都沒有構(gòu)建工具的痕跡(webpack 4也能做到。。夕土。)趟畏,parcel 會(huì)把你使用的工具都幫你配置好,不過得需要自己安裝包抡句。這是官網(wǎng) https://zh.parceljs.org/getting_started.html探膊,不過遺憾的是里面的 API 不全。待榔。逞壁。很多新版本更新的 api 沒有在文檔里說明,需要自己去 Google,比如本次要用到的 tree-shaking 配置:--experimental-scope-hoisting腌闯,在 api 里就沒有袭灯,在 https://medium.com/@devongovett/parcel-v1-9-0-tree-shaking-2x-faster-watcher-and-more-87f2e1a70f79 里面有詳細(xì)說明。

下面是項(xiàng)目目錄結(jié)構(gòu):

project
│   README.md
│   entry.js
│   package.json
│   .babelrc
│   .npmignore
│
└─── src
│   │   index.js
│   │   tag.vue
│   │
│   └─── fonts
│       │   iconfont.ttf
│       │   iconfont.woff
│   
└─── demo
│  │   App.vue
│  │   index.html
│  │   main.js
│   
└─── es
   │   index.js

因?yàn)榻M件比較簡單绑嘹,所以沒有使用 vue-cli 創(chuàng)建稽荧,直接 npm init,然后安裝需要的包
npm install vue -S
npm install vue-template-compiler babel-preset-env babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props -D

還有一些其他包工腋,parcel 有一個(gè) autoinstall 功能姨丈,是可以自動(dòng)去 install 項(xiàng)目中引用但是沒有下的包。
其中擅腰,vue-template-compiler 的作用是解析 .vue 文件的蟋恬,babel-preset-env 解析 es6 的語法,babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props 這三個(gè)是解析 vue 中的 jsx 語法用的趁冈。

.babelrc

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ],
  "plugins": ["transform-vue-jsx"]
}

entry.js:打包的入口文件歼争,暴露出 Tag 組件

import Tag from './src';
export default Tag;

src 文件夾:存放源代碼
src ---> index.js

import Tag from './tag';

function install (Vue) {
  if (install.installed) return;
  install.installed = true;
  Vue.component(Tag.name, Tag);
}

const SftcTag = {
  install,
  Tag
};

if (typeof window !== undefined && window.Vue) {
  window.Vue.use(SftcTag)
}

export default SftcTag

index.js 暴露出一個(gè)對象,包含有兩個(gè)屬性渗勘,Tag 是組件代碼沐绒,install 為了使用 vue.use 注冊 vue 插件。
重點(diǎn):install 中有一個(gè)小技巧旺坠,就是這個(gè)方法接受了 Vue 參數(shù)來注冊全局組件乔遮。沒有在文件中直接使用 import Vue from 'vue'; 的原因是這種引用的 vue 其實(shí)是 node_modules 中的 vue/dist/vue.runtime.esm.js,而我們需要利用 tree-shaking 將 vue 抽離出去的時(shí)候使用的 vue 應(yīng)該是 node_modules/vue/dist/vue.common.js取刃,所以需要使用不同 Vue 進(jìn)行注冊決定了 install 方法需要使用接收的 Vue 對象來注冊蹋肮。細(xì)心的童鞋一定會(huì)對 vue/dist/vue.common.js 有印象,因?yàn)樵谑褂?webpack 的 tree-shaking 的時(shí)候璧疗,使用 alias 配置 'vue$': vue/dist/vue.common.js坯辩,和這個(gè)道理是一樣的,只是 parcel 幫我們做了這件事崩侠。

因?yàn)榻M件源碼不是這篇文章的重點(diǎn)漆魔,所以 tag.vue 的源碼放在最后貼上。


下面是最重要的部分:parcel 打包啦膜!
首先全局安裝 parcel
sudo npm install -g parcel-bundler
不用任何配置文件有送!
在 package.json 中直接寫 scripts:

"scripts": {
  "demo": "parcel demo/index.html -p 8090 -d lib",
  "build": "rm -rf lib && parcel build entry.js -d lib --out-file sftctag.min.js --experimental-scope-hoisting",
  "build:nominify": "rm -rf lib && parcel build entry.js -d lib --out-file sftctag.min.js --no-minify --no-source-maps --experimental-scope-hoisting --no-cache"
},

然后直接運(yùn)行 npm run build,完事僧家!就是這么快雀摘!

打包結(jié)果

如果不使用 tree-shaking 打包的話就會(huì)把整個(gè)的 vue 源代碼也打進(jìn)去,會(huì)增加 65KB 體積八拱!加載一個(gè)包就會(huì)增加 65 KB阵赠,如果是 10 個(gè)這樣的包涯塔,那性能損失真的是太大了。

下面說一個(gè) build 命令里都干了哪些事:
rm -rf lib 每次打包刪除 之前的打包目錄
parcel build entry.js 執(zhí)行打包命令
-d lib 輸出目錄文件夾名
--out-file sftctag.min.js 打包文件名
--experimental-scope-hoisting 開啟 tree-shaking(parcel 1.9 版本新增特性)

build:nominify 用于查看打包出的源代碼清蚀,新加了幾個(gè)配置匕荸,也說明下:
--no-minify 不壓縮代碼
--no-source-maps 不使用 source-map
--no-cache 不使用 .cache

這樣整個(gè)組件就寫完了,parcel 針對這種很小的組件需求枷邪,確實(shí)是比 webpack 方便很多榛搔,但是對于大型項(xiàng)目,開始建議使用 webpack东揣,原因是 parcel 畢竟是小型大包工具很多定制化構(gòu)建都沒有支持践惑,另外現(xiàn)在parcel的相關(guān)資料確實(shí)不多也不深入。


demo 文件夾:引用 src 中的源碼嘶卧,做一個(gè)小 demo尔觉,一個(gè)是方便看源碼的人通過 demo 理解源碼。一個(gè)是在開發(fā)源碼時(shí)自己做調(diào)試芥吟。

demo ---> index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>sftable</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but sftable doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
  </body>
  <script src="./main.js"></script>
</html>

demo ---> main.js

import Vue from 'vue';
import App from './App.vue';
import Tag from '../src';

Vue.config.productionTip = false;

Vue.use(Tag);

new Vue({
  render: h => h(App),
}).$mount('#app');

demo ---> App.vue

<template>
  <div id="app">
    <div class="container">
      <sftc-tag>標(biāo)簽一</sftc-tag>
      <sftc-tag type="success">標(biāo)簽二</sftc-tag>
      <sftc-tag type="info">標(biāo)簽三</sftc-tag>
      <sftc-tag type="warning">標(biāo)簽四</sftc-tag>
      <sftc-tag type="danger">標(biāo)簽五</sftc-tag>
    </div>

    <div class="container">
      <sftc-tag closable>標(biāo)簽一</sftc-tag>
      <sftc-tag closable type="success" @close="handleClose">標(biāo)簽二</sftc-tag>
      <sftc-tag closable type="info">標(biāo)簽三</sftc-tag>
      <sftc-tag closable type="warning">標(biāo)簽四</sftc-tag>
      <sftc-tag closable type="danger">標(biāo)簽五</sftc-tag>
    </div>

    <div class="container">
      <sftc-tag closable>默認(rèn)標(biāo)簽</sftc-tag>
      <sftc-tag size="medium" closable>中等標(biāo)簽</sftc-tag>
      <sftc-tag size="small" closable>小型標(biāo)簽</sftc-tag>
      <sftc-tag size="mini" closable>超小標(biāo)簽</sftc-tag>
    </div>

    <div class="container">
      <sftc-tag v-for="item in list" :key="item" closable type="success" @close="handleClose">標(biāo)簽{{ item }}</sftc-tag>
    </div>
  </div>
</template>

<script>

export default {
  name: 'App',
  data () {
    return {
      list: [1, 2, 3, 4, 5]
    }
  },
  methods: {
    handleClose() {
      this.list.pop();
    },
  },
}
</script>

<style>
.container {
  margin-bottom: 30px;
}
</style>

下一步是發(fā)布 npm 包侦铜,具體發(fā)布 npm 包的方法我就不多介紹了,網(wǎng)上配置文章很多钟鸵,下面主要說一下 package.json 中的 module 字段配置钉稍,Tag 組件的 module 配置是: es/index.js,下面是 index.js 的代碼:

export { default } from '../lib/sftctag.min.js';
export * from '../lib/sftctag.min.js'
import '../lib/sftctag.min.css'

很簡單就是暴露出了 js 源碼并引入需要的 css 文件
package.json 中引入 module 是為了擁抱 ES2015 中的 ES Module携添,所以也可以享受 tree-shaking 的特性嫁盲,之前 package.json 一直用 main 字段做入口文件篓叶。具體解釋可以參考這篇文章:《package.json 中的 Module 字段是干嘛的》


使用 Tag 組件方法:

import Vue from 'vue'
import SftcTag from 'sftctag'
Vue.use(SftcTag)
<sftc-tag>標(biāo)簽</sftc-tag>

因?yàn)?Tag 組件依賴使用者項(xiàng)目的 vue 烈掠,所以使用 Tag 組件前必須先引入 vue ,否則會(huì)報(bào)錯(cuò)缸托。

使用方法和相關(guān) API左敌,最好都寫到 README.md 中,方便使用者閱讀俐镐。


總結(jié):現(xiàn)在 Google 上 parcel 的資源并不多矫限,更別說度娘了。佩抹。叼风。但是其實(shí) parcel 的構(gòu)建思想和 webpack 很多都是歸一的,所以可以對比著去探索棍苹,寫完 Tag 組件之后對 parcel 有了一個(gè)大致了解无宿,并對如果寫一個(gè) vue 插件需要注意哪些點(diǎn)也有了清晰的思路。學(xué)會(huì)了 Tag 組件的構(gòu)建過程之后枢里,下一步就是寫其他的業(yè)務(wù)組件了孽鸡,比如 Table蹂午、Form 等等。


推薦一個(gè) parcel 的可視化包內(nèi)容占用比的插件:parcel-plugin-bundle-visualiser
和 webpack 的 webpack-bundle-analyzer 很相似

parcel-plugin-bundle-visualiser


最后貼在 Tag 組件源碼
src ---> tag.vue

<script>
  export default {
    name: 'sftcTag',
    props: {
      text: String,
      closable: Boolean,
      type: String,
      hit: Boolean,
      disableTransitions: Boolean,
      color: Boolean,
      size: String
    },
    methods: {
      handleClose(event) {
        event.stopPropagation();
        this.$emit('close', event);
      }
    },
    computed: {
      tagSize() {
        return this.size;
      }
    },
    render(h) {
      const classes = [ 'sftc-tag', this.type ? `sftc-tag--${this.type}` : '',
        this.tagSize ? `sftc-tag--${this.tagSize}` : '',
        {'is-hit' : this.hit}
      ];
      const tagEl = (<span class={classes} style={{backgroundColor: this.color}}>
        { this.$slots.default }
        {
          this.closable && <i class="sftc-tag__close sftc-icon-close" on-click={this.handleClose}></i>
        }
      </span>);

      return this.disableTransitions ? tagEl : <transition name="sftc-zoom-in-center">{ tagEl }</transition>;
    },
  };
</script>

<style>
  /* font */
  @font-face {
    font-family: sftc-icons;
    src: url(fonts/iconfont.woff?t=1545101934831) format("woff"), url(fonts/iconfont.ttf?t=1545101934831) format("truetype");
    font-weight: 400;
    font-style: normal
  }

  [class*=" sftc-icon-"],
  [class^=sftc-icon-] {
    font-family: sftc-icons !important;
    speak: none;
    font-style: normal;
    font-weight: 400;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    vertical-align: baseline;
    display: inline-block;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale
  }

  /* tag */
  .sftc-icon-close:before {
    content: "\e601"
  }

  .sftc-tag {
    background-color: rgba(64, 158, 255, .1);
    display: inline-block;
    padding: 0 10px;
    height: 32px;
    line-height: 30px;
    font-size: 12px;
    color: #409EFF;
    border-radius: 4px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    border: 1px solid rgba(64, 158, 255, .2);
    white-space: nowrap
  }

  .sftc-tag .sftc-icon-close {
    border-radius: 50%;
    text-align: center;
    position: relative;
    cursor: pointer;
    font-size: 12px;
    height: 16px;
    width: 16px;
    line-height: 16px;
    vertical-align: middle;
    top: -1px;
    right: -5px;
    color: #409EFF
  }

  .sftc-tag .sftc-icon-close::before {
    display: block
  }

  .sftc-tag .sftc-icon-close:hover {
    background-color: #409EFF;
    color: #fff
  }

  .sftc-tag--info,
  .sftc-tag--info .sftc-tag__close {
    color: #909399
  }

  .sftc-tag--info {
    background-color: rgba(144, 147, 153, .1);
    border-color: rgba(144, 147, 153, .2)
  }

  .sftc-tag--info.is-hit {
    border-color: #909399
  }

  .sftc-tag--info .sftc-tag__close:hover {
    background-color: #909399;
    color: #fff
  }

  .sftc-tag--success {
    background-color: rgba(103, 194, 58, .1);
    border-color: rgba(103, 194, 58, .2);
    color: #67c23a
  }

  .sftc-tag--success.is-hit {
    border-color: #67c23a
  }

  .sftc-tag--success .sftc-tag__close {
    color: #67c23a
  }

  .sftc-tag--success .sftc-tag__close:hover {
    background-color: #67c23a;
    color: #fff
  }

  .sftc-tag--warning {
    background-color: rgba(230, 162, 60, .1);
    border-color: rgba(230, 162, 60, .2);
    color: #e6a23c
  }

  .sftc-tag--warning.is-hit {
    border-color: #e6a23c
  }

  .sftc-tag--warning .sftc-tag__close {
    color: #e6a23c
  }

  .sftc-tag--warning .sftc-tag__close:hover {
    background-color: #e6a23c;
    color: #fff
  }

  .sftc-tag--danger {
    background-color: rgba(245, 108, 108, .1);
    border-color: rgba(245, 108, 108, .2);
    color: #f56c6c
  }

  .sftc-tag--danger.is-hit {
    border-color: #f56c6c
  }

  .sftc-tag--danger .sftc-tag__close {
    color: #f56c6c
  }

  .sftc-tag--danger .sftc-tag__close:hover {
    background-color: #f56c6c;
    color: #fff
  }

  .sftc-tag--medium {
    height: 28px;
    line-height: 26px
  }

  .sftc-tag--medium .sftc-icon-close {
    -webkit-transform: scale(.8);
    transform: scale(.8)
  }

  .sftc-tag--small {
    height: 24px;
    padding: 0 8px;
    line-height: 22px
  }

  .sftc-tag--small .sftc-icon-close {
    -webkit-transform: scale(.8);
    transform: scale(.8)
  }

  .sftc-tag--mini {
    height: 20px;
    padding: 0 5px;
    line-height: 19px
  }

  .sftc-tag--mini .sftc-icon-close {
    margin-left: -3px;
    -webkit-transform: scale(.7);
    transform: scale(.7)
  }

  /* transition */
  .sftc-zoom-in-center-enter-active,
  .sftc-zoom-in-center-leave-active {
    transition: all .3s cubic-bezier(.55,0,.1,1);
  }
  .sftc-zoom-in-center-enter,
  .sftc-zoom-in-center-leave-active {
    opacity: 0;
    transform: scaleX(0);
  }

</style>

這塊就不做多解釋了彬碱,按照 element 的 Tag 寫的豆胸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市巷疼,隨后出現(xiàn)的幾起案子晚胡,更是在濱河造成了極大的恐慌,老刑警劉巖嚼沿,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搬泥,死亡現(xiàn)場離奇詭異,居然都是意外死亡伏尼,警方通過查閱死者的電腦和手機(jī)忿檩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爆阶,“玉大人燥透,你說我怎么就攤上這事”嫱迹” “怎么了班套?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長故河。 經(jīng)常有香客問我吱韭,道長,這世上最難降的妖魔是什么鱼的? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任理盆,我火速辦了婚禮,結(jié)果婚禮上凑阶,老公的妹妹穿的比我還像新娘猿规。我一直安慰自己,他們只是感情好宙橱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布姨俩。 她就那樣靜靜地躺著,像睡著了一般师郑。 火紅的嫁衣襯著肌膚如雪环葵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天宝冕,我揣著相機(jī)與錄音张遭,去河邊找鬼。 笑死猬仁,一個(gè)胖子當(dāng)著我的面吹牛帝璧,可吹牛的內(nèi)容都是我干的先誉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼的烁,長吁一口氣:“原來是場噩夢啊……” “哼褐耳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起渴庆,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铃芦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后襟雷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刃滓,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年耸弄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咧虎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡计呈,死狀恐怖砰诵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捌显,我是刑警寧澤茁彭,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站扶歪,受9級特大地震影響理肺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜善镰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一妹萨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧媳禁,春花似錦眠副、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霍弹。三九已至毫别,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間典格,已是汗流浹背岛宦。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耍缴,地道東北人砾肺。 一個(gè)月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓挽霉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親变汪。 傳聞我的和親對象是個(gè)殘疾皇子侠坎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1 Webpack 1.1 概念簡介 1.1.1 WebPack是什么 1、一個(gè)打包工具 2裙盾、一個(gè)模塊加載工具 3...
    Kevin_Junbaozi閱讀 6,665評論 0 16
  • 第497天鍛煉实胸,今天上班,看彭小六《洋蔥閱讀法》番官。 ——每天一薦:“《南方周末》官方公眾號:‘南方周末’庐完。”
  • 一個(gè)人的快樂徘熔,不是因?yàn)樗麚碛械亩嗝徘且驗(yàn)樗?jì)較的少。
    舞云端閱讀 231評論 0 0
  • 放暑假了酷师,我和媽媽去市場買菜生音。市場里可熱鬧了,有的在大聲吆喝窒升,有的在細(xì)心挑選自己喜歡的菜缀遍,還有的在討價(jià)還價(jià)。...
    能耐我何閱讀 160評論 0 0
  • 游俞源村感懷 周光華 人在蒼天星象中饱须, 神奇布局伯溫公域醇。 樹搖古井波光滟, 日映長塘云影空蓉媳。 耕讀詩書勤不斷譬挚, 漁...
    劍南123閱讀 270評論 0 0