窺探 Vue CLI3 UI 內建外掛 - 關閉網路埠
Vue CLI3的圖形化介面增加一個好玩的工具,快速的關閉一個網路埠,挺貼心! vue ui

傻瓜式的工具可以先用,但最終要掌握原理哦。
關閉埠一般方法
在Mac上關閉埠
// lsof(list open files)是一個列出當前系統開啟檔案的工具 lsof -i tcp:8080 COMMANDPIDUSERFDTYPEDEVICE SIZE/OFF NODE NAME php54205 charlesyu3uIPv4 0x2d201a97d7761bfd0t0TCP localhost:8090 (LISTEN) // kill pid kill 54205 複製程式碼
使用windows dos關閉埠
// 查詢pid netstat -ano|findstr 8080 // 停止端口占用 taskkill /pid 13064 複製程式碼
Vue CLI3是怎麼實現的呢?
假設你已經使用 yarn 命令安裝了 Vue CLI3(本來想貼github原始碼地址,但我感覺用本地環境更好,多動手除錯程式碼是掌握知識的好途徑!)
開啟檔案: 你的使用者目錄/.config/yarn/global/node_modules/@vue/cli-ui/ui-defaults/widgets.js
module.exports = api => { const { registerWidget, onAction, setSharedData } = api.namespace('org.vue.widgets.') ... registerWidget({ id: 'kill-port', title: 'org.vue.widgets.kill-port.title', description: 'org.vue.widgets.kill-port.description', icon: 'flash_on', component: 'org.vue.widgets.components.kill-port', minWidth: 2, minHeight: 1, maxWidth: 2, maxHeight: 1, maxCount: 1 }) } setSharedData('kill-port.status', 'idle') onAction('actions.kill-port', async params => { const fkill = require('fkill') setSharedData('kill-port.status', 'killing') try { await fkill(`:${params.port}`) setSharedData('kill-port.status', 'killed') } catch (e) { console.log(e) setSharedData('kill-port.status', 'error') } }) 複製程式碼
這裡是kill-port這個外掛註冊的位置,外掛註冊實現的很優雅。
pid-from-port
和 fkill
實現了關閉埠的功能。
(Ps: 記住哦!以後寫腳手架的時候會用到的 )
當點選【終止】按鈕時,就會觸發這個事件: ../.config/yarn/global/node_modules/@vue/cli-ui-addon-widgets/src/components/KillPort.vue
... methods: { kill () { clearTimeout(this.$_statusTimer) this.$callPluginAction('org.vue.widgets.actions.kill-port', { port: this.port }) } } 複製程式碼
在事件執行之前先弄清三個問題:
-
- 這個檔案中並沒有$callPluginAction物件,這個物件在哪裡呢?
-
-
org.vue.widgets.kill-port.title
從哪裡來的呢?
-
-
- onAction 是怎麼工作的?
順藤摸瓜 找到安裝入口有個methods的mixin
../.config/yarn/global/node_modules/@vue/cli-ui/src/util/plugin-action.js
export default { install (Vue) { Vue.mixin({ methods: { async $callPluginAction (id, params) { const result = await this.$apollo.mutate({ mutation: PLUGIN_ACTION_CALL, variables: { id, params } }) return result.data.pluginActionCall :smiling_imp: ... 複製程式碼
這裡的 this.$apollo.mutate 是 apollo
的更新方法,variables 是 GraphQL 中的語法。
.config/yarn/global/node_modules/@vue/cli-ui/apollo-server/api/PluginApi.js
onAction: (id, cb) => this.onAction(namespace + id, cb) ... onAction (id, cb) { let list = this.actions.get(id) if (!list) { list = [] this.actions.set(id, list) } list.push(cb) } 複製程式碼
這裡的onAction會在後面被callAction邏輯呼叫。
問題二有點複雜, 資料來源是通過GraphQL從CDN上拉取的。
... "kill-port": { "title": "Kill port", "description": "終止佔用指定埠的程序", "input": { "placeholder": "輸入一個網路埠" }, "kill": "終止", "status": { "idle": "準備好終止", "killing": "終止程序中", "killed": "成功終止程序!", "error": "無法終止程序" } } 複製程式碼

org.vue.widgets.actions.kill-port
還記得上面 :smiling_imp:(這個emoji處返回的物件嗎) return result.data.pluginActionCall
在此處有一個整理的過程
.config/yarn/global/node_modules/@vue/cli-ui/apollo-server/schema/plugin.js
Mutation: { ... pluginActionCall: (root, args, context) => plugins.callAction(args, context), }, 複製程式碼
.config/yarn/global/node_modules/@vue/cli-ui/apollo-server/connectors/plugins.js
callAction 呼叫了 onAction 定義的邏輯,完成了關閉網路埠的功能。
async function callAction ({ id, params, file = cwd.get() }, context) { ... return { id, params, results, errors } } 複製程式碼
總結
這個功能本身並不複雜, 但Vue CLI3用了最新的技術棧,在工程化方面做的非常完美。