如何將Vue的composable和component經由Vite打包至npm平台,讓其他人可以載入使用
前言
想把團隊會重複使用到的composable和component打包至npm平台後重複使用,像是在Vue.js世界常遇到的VueUse、ElementPlus是如何做到套件打包,上網查相關資料將實作筆記整理出來。
建立Vue專案
1 | npm init vue@next [專案名稱] |
如下圖,專案名稱自行取名即可,但可以先到npm平台看一下,我們取名的名稱是否已經被別人命名走,如果有重複,最後套件部署上去會失敗喔,要特別留意。
筆者用fred-vue-library專案名稱示範。
基本上沒有額外需求,直接Enter(選No)到底即可。
建立composable (視需求)
什麼是composable?基本上就是跟js檔案很像,把裡面的共用邏輯打包出來,如果希望這個是有響應式的物件,那就需要使用到composable
如果想做composable再實作
- 至src資料夾底下建立composable資料夾
- src/composable資料夾內新增useMouse.js檔案,以下是官網composable範例用來呈現目前滑鼠所在的x和y座標
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
建立component (視需求)
- 先清空src/components資料夾內所有的vue檔案(因為我們不會用到)
- src/components資料夾內新增FButton.vue檔案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68<script>
export default {
name: "FButton",
props: {
size: {
type: String,
default: "middle",
},
type: {
type: String,
default: "default",
},
},
};
</script>
<template>
<button class="fred-btn" :class="[size, type]">
<slot></slot>
</button>
</template>
<style>
.fred-btn {
appearance: none;
border: none;
outline: none;
background: #fff;
text-align: center;
border: 1px solid transparent;
border-radius: 4px;
cursor: pointer;
}
.large {
width: 240px;
height: 50px;
font-size: 16px;
}
.medium {
width: 180px;
height: 50px;
font-size: 16px;
}
.small {
width: 100px;
height: 32px;
}
.default {
border-color: #e4e4e4;
color: #666;
}
.primary {
border-color: blue;
background: blue;
color: #fff;
}
.danger {
border-color: red;
color: red;
background: lighten(red, 50%);
}
</style>
其他配置(重要)
在src資料夾內新增index.js
此檔案是用來放最後套件進入的第一個入口,非常重要,所以要把我們上述步驟的composable和component整理在這個js檔裡面1
2
3
4
5
6
7
8
9
10
11
12
13
14import FButton from "./components/FButton.vue";
import { useMouse } from "./composable/useMouse.js";
export { FButton, useMouse }; //用來本地引入
//用來全域引入
const components = [FButton];
export default {
install: function (Vue, options = {}) {
components.forEach(component => {
Vue.component(component.name, component);
});
},
};- 把FButton, useMouse做輸出,未來在vue檔內做區域引入使用
- 因為composable比較少用全域引入,所以就沒有做了,範例只針對component也做全域引入(未來使用者在專案內可以在main.js用 .use()方式引入)
調整vite.config.js檔案內容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.js'),
name: 'FredVueLibrary',
fileName: (format) => `fred-vue-library.${format}.js`
},
rollupOptions: {
// 確保外部化處理那些你的庫中不需要打包的依賴
external: ['vue'],
output: {
// 為全局變量提供一個名稱
globals: {
vue: 'Vue'
}
}
}
}
})- src/index.js就是上一個步驟做的檔案,作為套件的entry(入口)
調整package.json檔案內容
- P.S.要記得先到npm平台先進行註冊,要記得使用者名稱以及信箱,要填入到author欄位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31{
"name": "fred-vue-library",
"version": "1.0.0",
"type": "module",
"main": "./dist/fred-vue-library.umd.js",
"module": "./dist/fred-vue-library.es.js",
"exports":{
".": {
"import": "./dist/fred-vue-library.es.js",
"require": "./dist/fred-vue-library.umd.js"
},
"./style.css": "./dist/style.css"
},
"files": [
"dist"
],
"author": "fredchang <spadej03727@gmail.com>",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"less": "^4.2.0",
"vue": "^3.3.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"vite": "^4.4.5"
}
}- 如為第一次發布,version設為1.0.0即可,但如果後續有更新,要再發布,就一定要大於最新一次的發布版本。
- exports欄位內,import我是填入es.js方式,因為現在前端幾乎都是使用ES6方式import套件,所以就比較不會用到umd的格式了,如有興趣了解差異,再自行研究。
- 要留意如果你的package.json裡面有private欄位記得設為false,或直接刪掉即可。否則無法發佈到npm平台。
- 將src/App.vue內容預設內容清空,留下以下配置即可
1
2
3
4
5
6
7<script setup>
</script>
<template>
<div>
</div>
</template>
準備npm發布
登入npm
1
npm login
如果不確定登入狀態,可以確認一下身分(沒其他可能就可跳過)
1
npm whoami
先把剛剛實作的程式先build出來
1
npm build
如果發布前想先試試看套件能否順利載入可以用以下指令
1
npm link [套件名]
所以如果像示範的則填入npm link fred-vue-library
可藉由此指令,在本地引入看正不正常。
需特別注意這個有cache問題,所以還是npm publish發布出去引入看結果最準發布
1
npm publish
建立其他專案安裝套件
請依照這篇文章開頭處找建立Vue專案章節,建置其他專案
先安裝Vite所需套件
1
npm i
建立我們剛剛發布的專案
1
npm i fred-vue-library
這邊請自行換成自己的套件名
在App.vue引入相關模組,可跟著我修改如下
1
2
3
4
5
6
7
8
9
10
11
12
13<script setup>
import { useMouse, FButton } from "fred-vue-library";
import "fred-vue-library/style.css";
const { x, y } = useMouse();
</script>
<template>
<div>
<FButton size="large" type="primary">測試按鈕</FButton>
{{ x }},{{ y }}
</div>
</template>fred-vue-library請自行換成自己發布的套件名稱。
此為區域引入方式,把專案運行起來
1
npm run dev
呈現成果
(補充)使用全域引入component
main.js調整如下1
2
3
4
5
6
7
8
9import { createApp } from 'vue'
import App from './App.vue'
import "fred-vue-library/style.css";
import FredVueLibrary from "fred-vue-library"
const app = createApp(App)
app.use(FredVueLibrary).mount('#app')然後把App.vue區域引入component也拿掉,css檔也拿掉,更改如下
1
2
3
4
5
6
7
8
9
10
11
12
13<script setup>
import { useMouse } from "fred-vue-library";
const { x, y } = useMouse();
</script>
<template>
<div>
<FButton size="large" type="primary">測試按鈕</FButton>
{{ x }},{{ y }}
</div>
</template>這樣也跟上一點的呈現結果相同,要不要用全域就看個人了,我個人比較喜歡區域引入,對於目前這個頁面載入了哪些元件比較清楚。
小結
- 透過這個整理,更熟悉Vite打包Vue元件相關過程。
- 一直踩到npm link的雷,所以建議部署還是以npm publish為主,這樣檢查套件是否正常運作最準確。
全部程式碼:Github Repo