騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

寫在前面

小小的前端有大大的夢想。做一個屬於我們自己的 UI 組件庫應該是個不錯的小目標了。那。。。組件是什麼?我想應該不用多說,在日常開發中我們天天與之打交道,你所寫的每一個 vue 文件都可以當做是一個組件,只不過通用性有所區別而已。組件寫得多了,隨著時間的推移,你就會有寫一個組件庫的衝動了。其實更多的為了提升 B 格,當和別人談論的時候,你說你寫過一個 UI 庫,別人就覺得你可能有點吊。好了,不吹 B,趕緊擼吧

源碼地址:github.com/lgq627628/x…

知識前置

我們可能習慣了在一個 vue 裡面引入組件的方式,所以先這裡要鞏固一下全局引入組件的方式。舉個栗子,一般我們的用法是這樣的:

import Loading from '../components/loading'
// 方法一:name 是組件的名字
Vue.component(Loading.name, Loading)
// 方法二:前提是 Loading 有提供 install 這個方法
Vue.use(Loading);
複製代碼

上面兩種方式都可以用來全局註冊組件,但是參數不一樣,選擇哪種方法都可以,但要留意一下第二種方法,這種方法需要組件本身有個 install 的方法。額。。。為啥要有 install 的方法?這個你就當做是規定就好,你用人家的框架就得遵循人家的規則。扯犢子吧,其實是因為執行 Vue.use 的時候會執行裡面的 install 方法,所以我們需要寫個 install。對此你不用較真,寄人籬下是這樣的,哦不對‍♀️,應該是站在大神的肩膀上。

搭建目錄

快速創建項目

這步應該不用多說吧,執行一下 vue create xr-ui(前提是你安裝了 vue-cli3),然後看自己喜好選擇一些配置,幾下回車之後一個清爽的初始項目就有了。這裡我沒有選擇用 typescript(主要是我還沒習慣用它),所以選用 typescript 的同學們注意啦,可能寫法會有少許不同,有勞大夥看著改下吧。

修改目錄結構

  1. 把 src 目錄名字改成 examples,這是用於展示組件示例的
  2. 在根目錄下新建一個 packages 文件夾,這是用來放組件的
騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫


  1. 你可能會問為什麼要建這樣的目錄結構,問得好,原因很簡單,因為別人是這樣做的,所以借鑑(模仿)羅。。。我們可以看到 Element 的源碼也是這樣的結構:
騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫


當我們水平不夠的時候,模仿是一種強大的學習能力。

添加配置文件

小改了一下目錄之後,你會驚奇的發現項目運行不了了。沒關係,這很正常,畢竟 src 都不見了,路徑啥的肯定得報錯。所以現在我們來解決這個問題。 在根目錄下新建一個 vue.config.js 文件(新項目是沒有這個文件的),並寫入以下內容:

const path = require('path')
module.exports = {
// 修改 pages 入口
pages: {
index: {
entry: 'examples/main.js', // 入口
template: 'public/index.html', // 模板
filename: 'index.html' // 輸出文件
}
},
// 擴展 webpack 配置
chainWebpack: config => {
// @ 默認指向 src 目錄,這裡要改成 examples
// 另外也可以新增一個 ~ 指向 packages
config.resolve.alias
.set('@', path.resolve('examples'))
.set('~', path.resolve('packages'))
// 把 packages 和 examples 加入編譯,因為新增的文件默認是不被 webpack 處理的
config.module

.rule('js')
.include.add(/packages/).end()
.include.add(/examples/).end()
.use('babel')
.loader('babel-loader')
.tap(options => {
// 修改它的選項...
return options
})
}
}
複製代碼

上面的註釋應該都寫的挺明瞭,主要就是修改別名、修改入口文件以及把新文件加入 webpack 編譯這幾個步驟。然後我們再運行一下程序就可以跑得通了。至於為什麼這麼配置、或者怎麼配置,不瞭解的同學可以去 Vue Cli 官網看下,上面寫的是清清楚楚、明明白白,然而我也只是懂那麼一兩個配置而已,還沒學會 webpack 的套路,因為常常是用的時候看一眼,一陣子不用就又忘了,沒辦法‍♀️腦子不行。

編寫組件

一個組件庫沒有組件怎麼行呢,所以我們要先寫個 test 組件(你可以隨便寫,這不重要)。ok,我們先在 packages 目錄下新建一個 test 文件夾,再在 test 文件夾下下面新建一個 src 文件夾,在 src 文件夾下面新建一個 test.vue 組件,大概長下面這樣子:


<template>

{{ num }}

/<template>

<style><br>.xr-test {<br> width: 100px;<br> height: 100px;<br> line-height: 100px;<br> border-radius: 50%;<br> font-size: 30px;<br> text-align: center;<br> background: #24292e;<br> color: white;<br>}<br>/<style>
複製代碼

應該都能看懂吧,不過多解釋。⚠️這裡主要強調一點,就是 name 這個名字尤為重要,我就在這個坑裡呆了挺久。首先它是必須要寫的,為啥呢,你可以把它理解為 id,具有唯一標識組件的作用,將來我們可是要通過這個 name 來找到和判定這是什麼組件,所以你寫的所有組件應該是不重名的;其次這個 name 就是我們最終的標籤名,比如這裡我們的 name 是 XrTest,到時候我們寫的標籤就長這樣 <xr-test>,就像 Element 一樣,name 是 ElButton,用的時候就是 <el-button>。

暴露組件

讓我們在 packages/test 下面新建一個 index.js 文件,具體代碼如下:

// 為組件提供 install 方法,供組件對外按需引入
import XrTest from './src/test'
XrTest.install = Vue => {
Vue.component(XrTest.name, XrTest)
}
export default XrTest
複製代碼

這步的精髓就在於給組件擴展一個 install 方法,至於為什麼要擴展這個方法,文章開頭已經說到了,是因為 Vue.use() 的需要,use 會默認調用 install 方法安裝,僅此而已。接著我們在 packages 下面也新建一個 index.js 文件,注意和上面那個 index.js 區別開,上面那個是針對單個組件安裝的,這個是針對所有組件全局安裝的,先看代碼:

import XrTest from './test'
// 所有組件列表
const components = [
XrTest
]
// 定義 install 方法,接收 Vue 作為參數
const install = function (Vue) {
// 判斷是否安裝,安裝過就不繼續往下執行
if (install.installed) return
install.installed = true
// 遍歷註冊所有組件
components.map(component => Vue.component(component.name, component))
// 下面這個寫法也可以
// components.map(component => Vue.use(component))
}
// 檢測到 Vue 才執行,畢竟我們是基於 Vue 的
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export default {
install,
// 所有組件,必須具有 install,才能使用 Vue.use()
...components
}
複製代碼

這步的主要作用就是統一導出所有組件及暴露 install 方法。之前的 index.js 只是安裝單個組件,而現在這個 index.js 是循環安裝所有組件,具體使用就看你是不是要按需引用了。這裡給個目錄結構方便大家觀看:

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

因為這步挺重要的,所以建議好好停下來理解消化一下。。。

當然你可能會問道,為什麼這樣建目錄?還能什麼原因,因為 Element 是這樣(如下圖),所以我們這樣寫,僅此而已。

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

組件測試

ok,組件寫完了,接下來我們就在 examples 下面測試一下,看看能不能引用成功。 首先在 examples 下的 main.js 中引入剛剛寫好的包,就像下面這樣:

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

然後把 examples/views 下面的 Home.vue 裡面的內容刪了,寫入自己標籤組件,就像下面這樣:

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

好了,最後讓我們運行一下項目 yarn serve,看看效果,嗯,還湊合吧。庫模式打包

在 vue-cli3 中我們通過以下命令可以將一個單獨的入口打包成一個庫:

// target: 默認為構建應用,改為 lib 即可啟用構建庫模式
// name: 輸出文件名
// dest: 輸出目錄,默認為 dist,這裡我們改為 lib
// entry: 入口文件路徑
vue-cli-service build --target lib --name lib [entry]
複製代碼

要注意的是在庫模式中,打包出來的庫中是不包含 Vue 的。 然後我們修改一下 package.json 文件,就像下面這樣:

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

接著執行 npm run lib 就能生成庫啦,看看左側的目錄是不是多了個 lib 文件夾,那個就是我們要發佈的東西。

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

補充下,lib 目錄下面的 js 之所以有好幾種,是因為有兩種規範(common 和 umd)、是否壓縮(min)和映射(map)的區別,暫且知道有這麼回事就行,不用深究。發佈到npm

萬事俱備,只欠發佈。

  1. 完善一下 README.md 文檔,這個隨便寫兩句就好
  2. 修改一下 package.json 文件:
{ 
"name": "xr-ui",
"version": "0.3.0",
"description": "基於 vue-cli3 的 UI 組件庫",
"main": "lib/xr-ui.umd.min.js", // 這是 lib 目錄下的其中一個
"keywords": "xr-ui",
"private": false,
"license": "MIT"
}
複製代碼
  1. 在根目錄下新建一個 .npmignore 文件,內容和 .gitignore 差不多:
# 這是複製 .gitignore 裡面的
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files

npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
# 以下是新增的
# 要忽略目錄和指定文件
examples/
packages/
public/
vue.config.js
babel.config.js
*.map
*.html
複製代碼

最後執行 npm login 登入 npm 賬號,再執行 npm publish 發佈即可,就這麼簡單的兩步就可以,過一會在 npm 上就能搜到了。當然前提是你有個 npm 賬號,沒有的話去註冊一個吧,很 easy 的,然後還要搜下你的 npm 包名是否有人用,有的話就換一個。

小試牛刀

終於,歷盡千辛萬苦,我們可以引用自己寫的庫拉,想想就牛叉。別激動,讓我們試驗一下,用 vue create new 另起一個新項目,然後 npm i xr-ui -S,可以在 node_modules 裡面看到我們的包大概長這樣:

騰訊前端大牛首次分享-基於 vue-cli3 打造屬於自己的 UI 庫

然後在 main.js 引入:import Vue from "vue"
import XrUI from 'xr-ui'
import 'xr-ui/lib/xr-ui.css'
Vue.use(XrUI)
複製代碼

這樣我們就能在頁面中引入組件啦,哈哈哈哈,賊開心,喜上眉梢。。。

<xr-test>
複製代碼

小結

想想如果你為團隊維護一個組件庫,那是多麼牛叉的事情。當然,好記性不如爛鍵盤,看懂並不代表掌握,只有自己體驗過才是真的難忘,額。。怎麼突然抒情了起來。

最後還是強調一點吧,水平不夠的時候,模仿是一種必備的技能,就像我。不過沒關係,這只是個過程,當你寫了幾年的代碼後,總會有一些自己的想法,然後也能慢慢沉澱出一些屬於自己的東西,我們只是站在巨人的肩膀上前行。

鏈接:https://juejin.im/post/5c95c61f6fb9a070c40acf65

希望能給大家帶來收穫,如果覺得有收穫歡迎轉發+關注+評論。你們的支持是我更新最大的動力!


分享到:


相關文章: