vue-cli ui設計解析

前言

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機制

上述架構中承擔相當重要的部分就是plugin,就是由於它暴露的API容許了開發者能夠經過加強項目的配置和任務,也能夠分享數據和進程間的通訊,下面將從一個進入項目開始解析,插件是如何加載及應用。webpack

open project

源碼目錄: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()
複製代碼

load plugins

源碼目錄:cli-ui/apollo-server/connectors/plugins.jsweb

獲取一個project的path信息後,將獲取項目相關的pluginsvue-cli

// Load plugins
await plugins.list(project.path, context)
複製代碼

ui插件主要從三個地方獲取:express

  1. 從項目package.json裏獲取插件信息這裏能夠經過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做爲特殊插件優先加載

  1. 內置默認ui,位置在cli-ui/apollo-server/ui-default
  2. package信息中指定的自定義ui插件
// 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進行拓展

add client addons

客戶端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

// 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 widget

// 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…

相關文章
相關標籤/搜索