窺探 Vue CLI3 UI 內建外掛 - 關閉網路埠

CharlesYu01發表於2019-01-22

Vue CLI3的圖形化介面增加一個好玩的工具,快速的關閉一個網路埠,挺貼心! vue ui

窺探 Vue CLI3 UI 內建外掛 - 關閉網路埠

傻瓜式的工具可以先用,但最終要掌握原理哦。

1.關閉埠一般方法

在Mac上關閉埠

// lsof(list open files)是一個列出當前系統開啟檔案的工具
lsof -i tcp:8080 
COMMAND   PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
php     54205 charlesyu    3u  IPv4 0x2d201a97d7761bfd      0t0  TCP localhost:8090 (LISTEN)
// kill pid
kill 54205

// lsof -p PID 檢視目錄
複製程式碼

使用windows dos關閉埠

// 查詢pid
netstat -ano|findstr 8080
// 停止埠占用
taskkill /pid 13064
複製程式碼

守護程式

平時我也會經常隨意開啟一些埠, 只要掌握怎麼開關這些埠有時候是提高生產力的一種辦法,下面再說 4 種常用的守護程式方式

通用守護程式

  • nohup
# 忽略所有結束通話(SIGHUP)訊號。 後臺執行,你關掉終端也會繼續執行
nohup command &
nohup /root/start.sh &  
複製程式碼

hup 終端結束會話時的訊號 參考資料

  • screen
#screen是Linux視窗管理器,使用者可以建立多個screen會話,每個screen會話又可以建立多個window視窗,
#每一個視窗就像一個可操作的真實的ssh終端一樣。

screen -S yourname -> 新建一個叫yourname的session
screen -ls -> 列出當前所有的session
screen -r yourname -> 回到yourname這個session
screen -d yourname -> 遠端detach某個session
screen -d -r yourname -> 結束當前session並回到yourname這個session
複製程式碼

下面兩個是node守護程式

  • forever
# 啟動
# 最簡單的啟動方式
forever start ./bin/www  
# 指定forever日誌輸出檔案,預設路徑~/.forever
forever start -l forever.log ./bin/www  
# 需要注意,如果第一次啟動帶日誌輸出檔案,以後啟動都需要加上 -a 引數,forever預設不覆蓋原檔案
forever start -l forever.log -a ./bin/www 
#指定node.js應用的控制檯輸出檔案和錯誤資訊輸出檔案
forever start -o out.log -e err.log ./bin/www  
# 監聽當前目錄下檔案改動,如有改動,立刻重啟應用,不推薦的做法!如有日誌檔案,日誌檔案是頻繁更改的
forever start -w ./bin/www  

# 重啟
forever restart ./bin/www  #重啟單個應用
forever restart [pid]  #根據pid重啟單個應用
forever restartall  #重啟所有應用

# 停止(和重啟很類似)
forever stop ./bin/www  #停止單個應用
forever stop [pid]  #根據pid停止單個應用
forever stopall  #停止所有應用

# 檢視forever守護的應用列表
forever list
複製程式碼
  • pm2
pm2 start app.js #最簡單的啟用一個應用
pm2 stop app_name|app_id #停止
pm2 delete app_name|app_id #刪除
pm2 restart app_name|app_id #重啟
pm2 stop all #停止所有
pm2 list #檢視所有的程式
pm2 status #檢視所有的程式狀態
pm2 describe app_name|app_id #檢視某一個程式的資訊
複製程式碼

2.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-portfkill 實現了關閉埠的功能。

(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
      })
    }
  }
複製程式碼

在事件執行之前先弄清三個問題:

    1. 這個檔案中並沒有$callPluginAction物件,這個物件在哪裡呢?
    1. org.vue.widgets.kill-port.title 從哪裡來的呢?
    1. 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 ?
...            
複製程式碼

這裡的 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上拉取的。

https://unpkg.com/vue-cli-locales@3.3.0/locales/zh.json

...
  "kill-port": {
          "title": "Kill port",
          "description": "終止佔用指定埠的程式",
          "input": {
            "placeholder": "輸入一個網路埠"
          },
          "kill": "終止",
          "status": {
            "idle": "準備好終止",
            "killing": "終止程式中",
            "killed": "成功終止程式!",
            "error": "無法終止程式"
          }
        }
複製程式碼

窺探 Vue CLI3 UI 內建外掛 - 關閉網路埠

org.vue.widgets.actions.kill-port

還記得上面 ?(這個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用了最新的技術棧,在工程化方面做的非常完美。

相關文章