Vue多組件倉庫開發(fā)與發(fā)布詳解
在開發(fā)組件時(shí),我們可能會(huì)期望一類組件放在同一個(gè)代碼倉庫下,就像element那樣,我們可以使用element提供的腳手架,也可以使用vue cli 3創(chuàng)建一個(gè)更‘新'的項(xiàng)目。
項(xiàng)目創(chuàng)建
通過vue cli 3創(chuàng)建項(xiàng)目,創(chuàng)建文件夾packages用于存放組件。
單個(gè)組件目錄
在packages下就是每一個(gè)組件,每個(gè)組件和單獨(dú)項(xiàng)目一樣,會(huì)有package.json、README.md、src、dist等文件及目錄。
如何演示/調(diào)試組件
在組件開發(fā)過稱中,我們需要對(duì)組件進(jìn)行展示,所以創(chuàng)建了examples文件夾,用于存放每個(gè)組件示例。
通過一個(gè)列表展示出所有的組件,點(diǎn)擊選擇當(dāng)前開發(fā)的組件,進(jìn)入對(duì)應(yīng)的example。
路由的根就是一個(gè)導(dǎo)航列表,然后每個(gè)組件對(duì)應(yīng)一個(gè)路由,通過一個(gè)配置文件的components.js來生成這個(gè)路由。
// 路由
import Navigation from "./Navigation";
import components from "./components";
let routes = components.map(component => ({
path: `/${component.name}`,
component: () => import(`../examples/${component.name}`)
}));
routes.unshift({
path: "",
component: Navigation
});
export default routes;
自動(dòng)化腳本
創(chuàng)建/編譯/發(fā)布
創(chuàng)建新的組件,需要修改components.js配置文件,在examples和packages下創(chuàng)建對(duì)應(yīng)目錄。
編譯/發(fā)布組件,因?yàn)閭}庫下會(huì)有多個(gè)組件,如果一次發(fā)布多個(gè),就需要進(jìn)入每個(gè)文件夾下執(zhí)行命令。
上面過程實(shí)現(xiàn)自動(dòng)化,有很多種方式,比如可以通過npm run <script>,可以直接通過node命令等。這里我參考element,采用了Makefile。
創(chuàng)建script文件夾,其中包括創(chuàng)建腳本new.js和構(gòu)建腳本build.js。
創(chuàng)建腳本
創(chuàng)建腳本主要就是目錄的創(chuàng)建與文件的寫入,其中可能需要注意的可能就是格式問題。
一種方式是在``之間,按照規(guī)范格式去完成寫入內(nèi)容,這樣做比較麻煩,而且可能面臨格式化要求修改問題。
另一種方式是在腳本中引入eslint,腳本中的eslint.CLIEngine可以根據(jù)配置文件(比如.eslintrc.js)格式化文件。需要注意的是需要比命令行中配置需要多添加fix: true配置, 如下
const CLIEngine = eslint.CLIEngine;
const cli = new CLIEngine({ ...require("../.eslintrc.js"), fix: true });
eslint在腳本中的使用方法,更具體的可以參考eslint文檔中Node.js API部分。
// scripts/new.js部分
...
components.push({
label: newName,
name: newName
})
const updateConfig = function(path, components) {
writeFile(path, `module.exports = ${JSON.stringify(components)}`).then(() => {
console.log("完成components.js")
// 格式化
CLIEngine.outputFixes(cli.executeOnFiles([configPath]))
})
}
const createPackages = function(componentName) {
try {
const dir = path.resolve(__dirname, `../packages/${componentName}/`)
// 創(chuàng)建文件夾
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
console.log(`完成創(chuàng)建packages/${componentName}文件夾`)
}
// 寫入README
if (!fs.existsSync(`${dir}/README.md`)) {
writeFile(
`${dir}/README.md`,
`## ${componentName}
### 使用說明
`
).then(() => {
console.log("完成創(chuàng)建README")
})
}
// 寫入package.json
if (!fs.existsSync(`${dir}/package.json`)) {
writeFile(
`${dir}/package.json`,
`{
"name": "@hy/${componentName}",
"version": "1.0.0",
"description": "${componentName}",
"main": "./dist/hy-${componentName}.umd.min.js",
"keywords": [
"${componentName}",
"vue"
],
"author": "",
"license": "ISC"
}
`
).then(() => {
console.log("完成創(chuàng)建package.json")
})
}
// 創(chuàng)建index.js
if (!fs.existsSync(`${dir}/index.js`)) {
writeFile(`${dir}/index.js`, `export {}`).then(() => {
console.log("完成創(chuàng)建index.js")
CLIEngine.outputFixes(cli.executeOnFiles([`${dir}/index.js`]))
})
}
} catch (err) {
console.error(err)
}
}
const createExample = function(componentName) {
try {
const dir = path.resolve(__dirname, `../examples/${componentName}/`)
// 創(chuàng)建文件夾
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
console.log(`完成創(chuàng)建examples/${componentName}文件夾`)
}
// 寫入index.vue
if (!fs.existsSync(`${dir}/index.vue`)) {
writeFile(
`${dir}/index.vue`,
`<template>
</template>
<script>
import { } from '../../packages/${componentName}/index'
export default {
components: {}
}
</script>
`
).then(() => {
console.log(`完成創(chuàng)建examples/${componentName}/index.vue文件`)
// 格式化index.vue
CLIEngine.outputFixes(cli.executeOnFiles([`${dir}/index.vue`]))
})
}
} catch (err) {
console.error(err)
}
}
...
構(gòu)建腳本
// build.js
...
async function build() {
for (let i = 0, len = components.length; i < len; i++) {
const name = components[i].name
await buildService.run(
"build",
{
_: ["build", `${root}/packages/${name}/src/index.js`],
target: "lib",
name: `hy-${name}`,
dest: `${root}/packages/${name}/dist`,
// 生成格式: umd格式會(huì)同時(shí)成功demo.html commonjs,umd,umd-min
formats: "commonjs,umd-min"
// clean: false
},
["--target=all", `./packages/${name}/src/index.js`]
)
}
}
...
Lerna
lerna是一個(gè)多包倉庫管理的工具,可以幫助創(chuàng)建、管理、發(fā)布多包倉庫中的包。
關(guān)于lerna我也沒有太深入得使用,只是用到了發(fā)布。首先在項(xiàng)目下執(zhí)行init初始化了項(xiàng)目,在每次commit之后,可以執(zhí)行publish。lerna會(huì)對(duì)應(yīng)代碼庫打tag,并發(fā)布到npm倉庫。
項(xiàng)目版本問題
0.0.1為不規(guī)范版本號(hào),最小應(yīng)該從1.0.0開始。npm publish無法發(fā)布,但是lerna publish可以發(fā)布。
導(dǎo)致結(jié)果安裝為固定版本號(hào),而不是以^開頭的版本號(hào)范圍。outdate可以檢測(cè)到有更新,無法通過update升級(jí)。
組件開發(fā)
組件開發(fā)主要是在packages/<component name>/src目錄下進(jìn)行,在example/<component name>/目錄下可以引入該組件src下的源文件,用一些數(shù)據(jù)來進(jìn)行開發(fā)測(cè)試。組件開發(fā)和項(xiàng)目中的組件開發(fā)基本相同。
作為組件庫中的組件,需要更多的考慮其通用性和易用性。不能為了通用而加入很多的屬性,而使其失去易用性;同樣也不能為了易用,而使其過于簡單,使用范圍過于局限。
對(duì)于每一個(gè)屬性、每個(gè)拋出去的方法,都需要認(rèn)真考慮其必要性。
唯一不同的地方可能需要注意的是導(dǎo)出的方式。
一種是直接導(dǎo)出組件,這種形式在使用時(shí)需要引入,并且在components中聲明,也就是局部注冊(cè)。
另一種是添加install方法后導(dǎo)出。這種形式需要調(diào)用vue.use方法,相當(dāng)于全局注冊(cè)。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue自動(dòng)路由-單頁面項(xiàng)目(非build時(shí)構(gòu)建)
這篇文章主要介紹了vue自動(dòng)路由-單頁面項(xiàng)目(非build時(shí)構(gòu)建),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
vue-quill-editor的使用及個(gè)性化定制操作
這篇文章主要介紹了vue-quill-editor的使用及個(gè)性化定制操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
教你60行代碼實(shí)現(xiàn)一個(gè)迷你響應(yīng)式系統(tǒng)vue
這篇文章主要為大家介紹了教你60行代碼實(shí)現(xiàn)一個(gè)迷你響應(yīng)式系統(tǒng)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2023-03-03
vue計(jì)時(shí)器的實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了vue計(jì)時(shí)器的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
vue3.0 CLI - 2.4 - 新組件 Forms.vue 中學(xué)習(xí)表單
這篇文章主要介紹了vue3.0 CLI - 2.4 - 新組件 Forms.vue 中學(xué)習(xí)表單的相關(guān)知識(shí),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2018-09-09
vue 設(shè)置proxyTable參數(shù)進(jìn)行代理跨域
這篇文章主要介紹了vue 設(shè)置proxyTable參數(shù)進(jìn)行代理跨域的相關(guān)資料,及代理跨域的概念原理,需要的朋友可以參考下2018-04-04
關(guān)于Vue項(xiàng)目跨平臺(tái)運(yùn)行問題的解決方法
這篇文章主要介紹了關(guān)于Vue項(xiàng)目跨平臺(tái)運(yùn)行問題的解決方法,特別記錄一下踩的坑,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09

