用rollup打包vue組件庫(kù)

前言

網(wǎng)上關(guān)于使用 rollup 打包 vue 組件的資料寥寥可數(shù),故記錄下 rollup 打包的踩坑之路弄痹,最終打包成類似 elementUI 的組件庫(kù)置蜀。

多倉(cāng)庫(kù)管理組件成本實(shí)屬太大,于是想做成npm包依賴減少維護(hù)成本接癌,選用的是rollup工具打包蕊玷。但如果有圖片不建議用rollup打包邮利,因?yàn)橐b的各種插件實(shí)在太多了,也不支持 require 語(yǔ)法(裝了 require 之類的庫(kù)也不能正確引入)垃帅,未知的坑略多延届,更適合打包純代碼文件...

附上 rollup 官方文檔,vue 官網(wǎng)也有教程可供參考

rollup 插件

先介紹后面會(huì)用到的一些 rollup 插件:

  • rollup-plugin-node-resolve --- rollup 無(wú)法識(shí)別 node_modules 中的包贸诚,幫助 rollup 查找外部模塊方庭,然后導(dǎo)入
  • rollup-plugin-commonjs --- 將 CommonJS 模塊轉(zhuǎn)換為 ES6 供 rollup 處理
  • rollup-plugin-babel --- ES6 轉(zhuǎn) ES5厕吉,讓我們可以使用 ES6 新特性來(lái)編寫代碼
  • rollup-plugin-terser --- 壓縮 js 代碼,包括 ES6 代碼壓縮
  • rollup-plugin-eslint --- js代碼檢測(cè)
  • rollup-plugin-require-context --- 使用 require.context 語(yǔ)法

安裝

npm install --global rollup

rollup 配置

初始化

lerna init(yarn init -y) 初始化包依賴后安裝 rollup 相關(guān)依賴械念,有些 rollup 插件需安裝新版本的(如 babel赴涵,commonjs等),則應(yīng)該安裝 @rollup/ 命名開頭的插件订讼。

yarn add @babel/core rollup rollup-plugin-node-resolve rollup-plugin-terser @rollup/plugin-babel @rollup/plugin-commonjs

如果打包文件包含 vuescss扇苞,image 這些類型的文件欺殿,則還需要安裝 rollup 相關(guān)的插件,否則 rollup 無(wú)法識(shí)別這些文件類型或者是其語(yǔ)法鳖敷。

yarn add @rollup/plugin-image rollup-plugin-scss rollup-plugin-vue @vue/compiler-sfc

用到 sass 還需要安裝 sass脖苏,sass-loadernode-sass 插件

然后新建一個(gè) rollup.config.js 文件定踱,把之前安裝的 rollup 插件引入棍潘,基礎(chǔ)配置如下:

// rollup.config.js
import resolve from "rollup-plugin-node-resolve"
import vue from "rollup-plugin-vue"
import babel from "@rollup/plugin-babel"
import commonjs from "@rollup/plugin-commonjs"
import image from "@rollup/plugin-image"

const config = {
  input: "./index.js", // 必須,入口文件
  output: { // 必須崖媚,輸出文件 (如果要輸出多個(gè)亦歉,可以是一個(gè)數(shù)組)
    exports: "named", // 輸出多個(gè)文件
    globals: {
      vue: "Vue" // 告訴rollup全局變量Vue即是vue
    }
  },
  plugins: [ // 引入的插件在這里配置
    resolve(),
    vue({
      css: true,
      compileTemplate: true
    }),
    babel({
      exclude: "**/node_modules/**"
    }),
    commonjs(),
    image()
  ]
}

export default config

external配置

我們?cè)谧约旱膸?kù)中需要使用第三方庫(kù),例如 lodash 等畅哑,又不想在最終生成的打包文件中出現(xiàn) lodash肴楷,這個(gè)時(shí)候我們就需要使用 external 屬性≤牛可根據(jù)實(shí)際情況自行選擇赛蔫。

external:['lodash'] //告訴rollup不要將此lodash打包,而作為外部依賴

external 可跟 globals 配套使用泥张,如 react-redux 開源項(xiàng)目的 rollup 配置文件片段

  input: 'src/index.js',
  external: ['react', 'redux'],  // 告訴rollup呵恢,不打包react,redux;將其視為外部依賴
  output: { 
    format: 'umd', // 輸出 UMD格式,各種模塊規(guī)范通用
    name: 'ReactRedux', // 打包后的全局變量媚创,如瀏覽器端 window.ReactRedux 
    globals: {
      react: 'React',  // 跟external 配套使用渗钉,指明global.React即是外部依賴react
      redux: 'Redux'
    }
  },

jsx 配置

如果 vue 中有用到 jsx 語(yǔ)法,則還需增加插件钞钙,否則會(huì)無(wú)法識(shí)別 jsx 語(yǔ)法

yarn add @vue/babel-preset-jsx

開始在 .babelrc 折騰了好久晌姚,發(fā)現(xiàn)均無(wú)效,最后發(fā)現(xiàn)需要在 rollup.config.js 中配置 babel 預(yù)設(shè)歇竟。

    babel({
      presets: ["@vue/babel-preset-jsx"]
    })

入口文件配置

配置了 rollup.config.js 文件后挥唠,還需配置入口文件 index.js,這里以多組件為例焕议,單組件 vue 官網(wǎng)有示例宝磨,多組件則是參照 element-ui 框架的寫法弧关。

每個(gè)組件都要單獨(dú)用一個(gè)文件夾,放在 src 里(誰(shuí)讓我是潔癖吶)唤锉。文件夾里一個(gè)你自己寫的組件世囊,一個(gè) index.js,這個(gè) js 是用于向外暴露的窿祥。然后在 src 目錄下新建 index.js 用于匯總?cè)拷M件株憾。目錄如下:

├── src
|   ├── icon-font
|   |   ├── icon-font.vue
|   |   ├── index.js
├── index.js

然后在組件文件夾的 index.js 文件中如下配置:

import IconFont from "./icon-font.vue"

IconFont.install = function(Vue) {
  Vue.component(IconFont.name, IconFont)
}

export default IconFont

最后在匯總?cè)拷M件的 index.js 文件中如下配置:

// Import vue component
import IconButton from "./icon-button/index"
import IconFont from "./icon-font/index"
import IconTooltip from "./icon-tooltip/index"
import LayoutHeader from "./layout-header/index"
import LayoutSidebar from "./layout-sidebar/index"
import PageIntroduce from "./page-introduce/index"
import TextHiddenTooltip from "./text-hidden-tooltip/index"
import VTable from "./v-table/index"

const components = [
  IconButton,
  IconFont,
  IconTooltip,
  LayoutHeader,
  LayoutSidebar,
  PageIntroduce,
  TextHiddenTooltip,
  VTable
]

// will install the plugin only once
const install = function(Vue) {
  components.forEach(component => {
    Vue.component(component.name, component)
  })
}

if (typeof window !== "undefined" && window.Vue) {
  install(window.Vue)
}

// To allow use as module (npm/webpack/etc.) export component
export default { install, IconFont, TextHiddenTooltip }

// It's possible to expose named exports when writing components that can
// also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
// export const RollupDemoDirective = component;

可使用rollup-plugin-require-context插件的 require.context 語(yǔ)法改良,有需要參照使用方法的可移步至文末的 Q&A 模塊

打包命令配置

最后還需要在 package.json 文件中配置打包命令晒衩,配置后直接在命令窗口中執(zhí)行 yarn build 命令就可以打包了嗤瞎。

"scripts": {
    "build": "npm run build:umd & npm run build:es & npm run build:unpkg",
    "build:umd": "rollup -c --format umd --file dist/components.umd.js",
    "build:es": "rollup -c --format es --file dist/components.esm.js",
    "build:unpkg": "rollup -c --format iife --file dist/components.min.js"
  }

在開發(fā)組件過(guò)程中,手動(dòng)打包文件再聯(lián)調(diào)很浪費(fèi)時(shí)間听系,可以在 package.json 文件中增加監(jiān)聽文件變動(dòng)自動(dòng)打包的配置贝奇,同理,配置后直接執(zhí)行 yarn dev 命令即可監(jiān)聽靠胜。

"scripts": {
    "dev": "npm run dev:umd & npm run dev:es & npm run dev:unpkg",
    "dev:umd": "rollup -c -w --format umd --file dist/components.umd.js",
    "dev:es": "rollup -c -w --format es --file dist/components.esm.js",
    "dev:unpkg": "rollup -c -w --format iife --file dist/components.min.js"
  }

發(fā)布

最后就可以到 npm 網(wǎng)站發(fā)布了~~附上 github 例子

項(xiàng)目中引入組件

發(fā)布好 npm 包后掉瞳,可以在項(xiàng)目中全局引入或局部引入組件,這里以我封裝的組件庫(kù)為例浪漠。

全局引入

在項(xiàng)目中的 main.js 中引入即可陕习,引入組件和全局樣式:

import Components from "@monorepo/components"
import "@monorepo/assets/src/scss/global.scss"
import "@monorepo/assets/src/scss/element-var.scss"
Vue.use(Components)

局部引入

在任意 vue 文件中引入:

import Components from "@monorepo/components"

Q & A

關(guān)于小伙伴的提問(wèn),統(tǒng)一在這里回復(fù):
Q:"組件庫(kù)是基于 elementUI 封裝的址愿,不需要引入 elementUI 嗎衡查?"
A:npm 包是不需要引入的,因?yàn)轫?xiàng)目中會(huì)全局安裝并引入 elementUI必盖,所以這里不需要重復(fù)引入拌牲,但是需要在封裝庫(kù)中的 package.json 文件中寫上 elementUI 這個(gè)依賴:

"devDependencies": {
    "@femessage/element-ui": "^2.17.0"
  }

Q:不知如何使用 require.context 優(yōu)化主入口的引入方法
A:在 index.js 中代碼思路大致如下:

const requireCxt = require.context("./src", true, /.vue/)
const components = {}

requireCxt.keys().map((item, index) => {
  const component = requireCxt(item)
  return (components[component.default.name] = component.default)
}, {})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市歌粥,隨后出現(xiàn)的幾起案子塌忽,更是在濱河造成了極大的恐慌,老刑警劉巖失驶,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件土居,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嬉探,警方通過(guò)查閱死者的電腦和手機(jī)擦耀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涩堤,“玉大人眷蜓,你說(shuō)我怎么就攤上這事√ノВ” “怎么了吁系?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵德召,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我汽纤,道長(zhǎng)上岗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任蕴坪,我火速辦了婚禮肴掷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘背传。我一直安慰自己呆瞻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布续室。 她就那樣靜靜地躺著,像睡著了一般谒养。 火紅的嫁衣襯著肌膚如雪挺狰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天买窟,我揣著相機(jī)與錄音丰泊,去河邊找鬼。 笑死始绍,一個(gè)胖子當(dāng)著我的面吹牛瞳购,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亏推,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼学赛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了吞杭?” 一聲冷哼從身側(cè)響起盏浇,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芽狗,沒(méi)想到半個(gè)月后绢掰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡童擎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年滴劲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顾复。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡班挖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芯砸,到底是詐尸還是另有隱情聪姿,我是刑警寧澤碴萧,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站末购,受9級(jí)特大地震影響破喻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盟榴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一曹质、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧擎场,春花似錦羽德、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至站欺,卻和暖如春姨夹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矾策。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工磷账, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贾虽。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓逃糟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蓬豁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绰咽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345