vue-cli 3.x帶來了ui控制檯的體驗,讓不熟悉cli命令的開發者可以更快的上手,同時提供了強大的插件拓展機制,能夠以項目緯度定製本身的ui命令。近期也準備爲架構方案提供ui的可視化配置,對vue-cli中ui的設計邏輯進行了必定的瞭解,特此記錄,歡迎你們進行斧正html
總體架構圖搬運自vue-cl官網 前端
node端用的apollo-graphql,前端毫無疑問是vue(- -)運行vue ui
能夠啓動本地server,server相關參數和服務端啓動細節,不是本文討論範圍,就不做贅述了,啓動代碼詳見:vue
github.com/vuejs/vue-c… github.com/Akryum/vue-…node
上述架構中承擔相當重要的部分就是plugin,就是由於它暴露的API容許了開發者能夠經過加強項目的配置和任務,也能夠分享數據和進程間的通訊,下面將從一個進入項目開始解析,插件是如何加載及應用。webpack
源碼目錄:cli-ui/apollo-server/connectors/project.jsgit
vue-cli ui是以項目爲緯度進行管理的,在建立/導入項目並進行相應項目後,將獲取項目相關的信息(path),並存儲項目信息用做下次默認打開github
// load plugins
...
// Save for next time
context.db.set('config.lastOpenProject', id).write()
複製代碼
源碼目錄:cli-ui/apollo-server/connectors/plugins.jsweb
獲取一個project的path信息後,將獲取項目相關的pluginsvue-cli
// Load plugins
await plugins.list(project.path, context)
複製代碼
ui插件主要從三個地方獲取:express
這裏能夠經過vuePlugins.resolveForm指定到其餘目錄
let pkgContext = cwd.get()
// Custom package.json location
if (pkg.vuePlugins && pkg.vuePlugins.resolveFrom) {
pkgContext = path.resolve(cwd.get(), pkg.vuePlugins.resolveFrom)
pkg = folders.readPackage(pkgContext, context)
}
pkgStore.set(file, { pkgContext, pkg })
let plugins = []
plugins = plugins.concat(findPlugins(pkg.devDependencies || {}, file))
plugins = plugins.concat(findPlugins(pkg.dependencies || {}, file))
複製代碼
findPlugins經過正則規則/^(@vue/|vue-|@[\w-]+/vue-)cli-plugin-/來過濾dependencies和devDependencies中的插件@vue/cli-service做爲特殊插件優先加載
// load custom ui pulgins
const { pkg, pkgContext } = pkgStore.get(file)
if (pkg.vuePlugins && pkg.vuePlugins.ui) {
const files = pkg.vuePlugins.ui
if (Array.isArray(files)) {
for (const file of files) {
runPluginApi(pkgContext, pluginApi, context, file)
}
}
}
複製代碼
拿到plugins後,將開始逐個容許插件,這裏會涉及到一個重要的api PluginApi
,它是整個插件機制運行的核心,提供hooks供插件添加配置、任務、視圖等,源碼位於cli-ui/apollo-server/api/PluginAPI.js
// run plugin api
function runPluginApi(id, pluginApi, context, filename = 'ui') {
...
try{
// 核心邏輯將pluginApi做爲參數傳給各個模塊插件
module(pluginApi)
} catch(e) {
}
}
複製代碼
經過運行三類插件,使得插件能夠經過pluginApi進行拓展
客戶端addons經過pluginApi的addClientAddon添加
//插件中註冊
module.exports = api => {
api.addClientAddon({
id: 'org.vue.webpack.client-addon',
path: '@vue/cli-ui-addon-webpack/dist'
})
}
複製代碼
對應客戶端則會加載/_addon/org.vue.webpack.client-addon/index.js生產環境下
,而完成這一邏輯的主要依賴,如下幾部分的設置
// 服務端保存添加的addon
pluginApi.clientAddons.forEach(options => {
clientAddons.add(options, context) //保存addons信息 並監聽變化響應接口
})
// 服務端設置,express插件cli-ui/cli-ui/apollo-server/server.js
module.exports = app => {
...
app.use('/_addon/:id/*', clientAddons.serve)
...
}
// 插件包打包設置,配置vue.config.js
module.exports = {
...clientAddonConfig({ // clientAddonConfig爲默認開發設置,源碼在cli-ui/index.js
id: 'org.vue.webpack.client-addon', //id做爲文件加載標識
port: 8096 // port用做開發模式下服務的端口
})
}
複製代碼
最終客戶端經過接口加載對應的addon腳本文件,如今你能夠在視圖中使用addon
api.describeTask({
/* ... */
// 額外的視圖 (例如 webpack dashboard)
// 默認狀況下,這是展現終端輸出的 'output' 視圖
views: [
{
// 惟一的 ID
id: 'org.vue.webpack.views.dashboard',
// 按鈕文字
label: 'Dashboard',
// 按鈕圖標 (material-icons)
icon: 'dashboard',
// 加載的動態組件,會用 ClientAddonApi 進行註冊
component: 'org.vue.webpack.components.dashboard'
}
],
// 展現任務詳情時默認選擇的視圖 (默認狀況下就是 output)
defaultView: 'org.vue.webpack.views.dashboard'
})
複製代碼
而這裏的org.vue.webpack.components.dashboard其實就是對應咱們加載的addon裏面註冊的vue組件
...
ClientAddonApi.component('org.vue.webpack.components.dashboard', WebpackDashboard) //ClientAddonApi經過注入到windows做爲全局變量使用,用於組件註冊和加載
...
複製代碼
// Add views
for (const view of pluginApi.views) {
await views.add({ view, project }, context)
}
複製代碼
加載自定義視圖,這裏是指經過api.addView來添加的視圖,具體方式能夠參見:cli.vuejs.org/zh/dev-guid…
這裏須要注意addView裏面的id和name均須要經過addClientAddon註冊過
// Register widgets
for (const definition of pluginApi.widgetDefs) {
await widgets.registerDefinition({ definition, project }, context)
}
複製代碼
註冊widget,能夠爲項目dashboard頁面添加自定義的ui插件,經過registerWidget來進行註冊
module.exports = api => {
const { registerWidget, onAction, setSharedData } = api.namespace('org.vue.widgets.')
registerWidget({
id: 'welcome',
title: 'org.vue.widgets.welcome.title',
description: 'org.vue.widgets.welcome.description',
icon: 'mood',
component: 'org.vue.widgets.components.welcome', //這裏的component也必須是已經在addon裏面註冊過的組件
minWidth: 3,
minHeight: 4,
maxWidth: 3,
maxHeight: 4,
maxCount: 1
})
}
複製代碼
經過各類視圖、wigdet的初始化定義,在客戶端請求信息接口後,根據獲取到的信息渲染對應的內容。除了插件機制外,cli-ui還有許多地方值得借鑑,好比經過node-ipc實現進程間通訊、經過ShareData的設計實現不一樣server數據和客戶端數據的實時同步,後續有機會將會繼續分享
最後獻上官方cli-ui插件開發連接:cli.vuejs.org/zh/dev-guid…