如何讓 uni-cli 建立的專案擁有執行自動開啟開發者除錯工具的能力

語言: CN / TW / HK

前言:

關於前端的IDE,流行的無非也就那麼幾款,但若要問那款編輯器最好用,那無疑是vscode開發的最舒適了,不得不說vscode的程式碼提示,引入跳轉,自動補全引入語句等功能,並且git支援很不錯,加上typescript後開發體驗真的是提升到了一個很高的檔次。

HBuilderX 在這些方面的支援真是太差了,只有內建的程式碼提示,沒有d.ts檔案的支援,自定義擴充套件功能少,使用typescript開發完全丟失了型別提示,使得typescript在編寫時發現問題的這個優勢完全丟失。

所以我們公司的多端程式都使用了uni-cli腳手架搭建的專案執行,在vscode中執行,但相比HBuilderX卻缺少了執行後自動開啟小程式的功能,那麼問題來了,HBuilderX都能做到,為什麼我們vscode做不到呢!

其實做這個很簡單,導致我一度懷疑HBuilderX為了推廣他自家的編譯器而不做這個功能...(事實上確實如此)目前我已經做成了一個第三方外掛,直接使用即可,該文章的主要目的是記錄當中所用到的技術,如怎麼自己做一個腳手架程式等。

我的筆記目錄:gitee.io/mao-blog

腳手架自動開啟小程式:open-devtools

微信小程式命令列v2

微信開發者工具提供了cli命令,可用於在外部使用cmd開啟和操控專案,這裡只使用部分指令,感興趣的同學可以去看官網文件

首先找到開發者工具的目錄下,cmd開啟當前目錄,我們建立一個小程式專案放在開發者工具的根目錄下,然後試著使用命令列開啟專案。

cd F:\softs\微信web開發者工具
cli open --project F:\softs\微信web開發者工具\demo
複製程式碼

那麼執行之後,就會發現開發者工具自動打開了程式,這裡需要注意,執行的路徑必選得是絕對路徑,不然是會報錯的。

npm 命令列呼叫 node 工具

這裡只記錄了我使用的方式,說的可能不是很全面,建議去看一下這篇文章,從0開始用node寫一個自己的命令列程式

# 初始化專案
npm init

# 修改 package.json 中bin欄位
"bin": {
    "open-dev": "./index.js"
}

# 新建 index.js
#!/usr/bin/env node
console.log('open-dev')
# `#!/usr/bin/env node` 的意思是讓系統自己去找node的執行程式,該行必不可少。

# 執行 npm link
npm link

# 執行腳手架工具
git-tool

# index.js 中 process.argv 可用來獲取命令列引數
# 注意 #!/usr/bin/env node 為是必須的
#!/usr/bin/env node
console.log('open-dev')
console.log(process.argv) # ['...', '...', ....]
複製程式碼

使用 shelljs 呼叫 cmd 命令

ShellJS是在Node.js API之上的Unix shell命令的可移植**(Windows / Linux / macOS)**實現。是基於Node.js API的封裝。其他API可以檢視官網:shelljs

const shell = require('shelljs')
// 進入目錄
shell.cp('F:\\softs\\微信web開發者工具')
// 呼叫命令, 這裡需要注意, 呼叫命令時需要在後面加上 --color=always 不然就沒有命令列顏色了
shell.exec('cli open --project F:\softs\微信web開發者工具\demo --color=always')
複製程式碼

獲取當前執行環境

我們來仔細的觀察一下 uni-cli 自帶的命令中,前面存在很長一大串的命令,那這個命令具體作用就是用於區分當前執行環境和型別的。如果想了解更多,可以去看一下 cross-env 的官方文件。

執行命令攜帶引數cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin

"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin open-devtools",
複製程式碼

將相當於在我們的命令jsprocess.env環境變數裡添加了兩個引數

const NODE_ENV = process.env.NODE_ENV // development
const UNI_PLATFORM = process.env.UNI_PLATFORM // mp-weixin 
複製程式碼

獲取 pageage.json 中的欄位

我們需要知道,微信開發者工具的路徑是不確定的,那麼需要在一開始先確定下來,我的思路是放在專案中的pageage.json儲存。

{
    "devtoolsConfig":{
        "weixin": "F:\\softs\\微信web開發者工具"
    }
}
複製程式碼

腳手架實開發

那麼有了這些基本的東西,基本的思路已經有了,實現功能具體路線為

基本路徑與開發者工具的路徑 》》執行開發者工具》》呼叫對應自身專案執行命令

// index.js
#!/usr/bin/env node
const fs = require("fs")
const path = require("path")
const shell = require('shelljs')
const utils = require(path.resolve(__dirname, './src/utils'))

// 執行專案路徑讀取, 這裡需要注意當安裝依賴時, 當前路徑為xxx/node_module/xxx, 所以需要回退兩層
const PRESET_PATH = path.resolve(__dirname, '../../')
const PACKAGE_PATH = path.resolve(PRESET_PATH, './package.json')

// 當前執行環境變數與執行命令, getRunPresetExec是我封裝的方法, 可以獲取當前對應的執行命令
// 例如 development|mp-weixin 則對應 -> npx cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --color=always
const NODE_ENV = process.env.NODE_ENV
const UNI_PLATFORM = process.env.UNI_PLATFORM
const EXEC_CODE = utils.getRunPresetExec(NODE_ENV, UNI_PLATFORM)

// 微信專案原始碼路徑, 這裡對於專案中的小程式原始碼路徑
const EXEC_CODE_TYPE = NODE_ENV === 'development' ? 'dev' : 'build'
const WEIXIN_PRESET_PATH = path.resolve(PRESET_PATH, `dist/${EXEC_CODE_TYPE}/mp-weixin`)

// 獲取開發者工具目錄(pageage.json)
const PACKAGE_CONFIG = JSON.parse(fs.readFileSync(PACKAGE_PATH).toString())
const DEVTOOLS_CONFIG = PACKAGE_CONFIG.devtoolsConfig || {}
const WEIXIN_DEVTOOLS_PATH = DEVTOOLS_CONFIG.weixin

// 如果呼叫環境是微信
if (UNI_PLATFORM === 'mp-weixin') {
  // 先遞迴寫入, 防止無內容導致除錯工具報錯
  // 這裡需要注意, 不能直接寫入檔案, 需要先建立好完整的目錄
  // 不然會直接報錯, 這裡的mkdirsSync是我封裝的遞迴建立目錄的方法
  utils.mkdirsSync(WEIXIN_PRESET_PATH)
  const writeFileStr = JSON.stringify({ appid: 'touristappid', projectname: 'open-devtools' }, null, "\t")
  fs.writeFileSync(path.resolve(WEIXIN_PRESET_PATH, './project.config.json'), writeFileStr, { flag: 'w' })
  // 開啟小程式專案
  const openDevToolsShell = `cli open --project ${WEIXIN_PRESET_PATH} --color=always`
  shell.cd(WEIXIN_DEVTOOLS_PATH)
  // 開啟完畢後, 執行編譯工具
  shell.exec(openDevToolsShell, () => {
    shell.cd(PRESET_PATH)
    shell.exec(EXEC_CODE)
  })
  // 返回當前條件, 阻止程式碼執行
  return false;
}

// 如上方程式碼沒有執行, 則直接執行執行專案命令
shell.cd(PRESET_PATH)
shell.exec(EXEC_CODE)
複製程式碼
// utils/index.js
const fs = require("fs")
const path = require("path")
// 獲取當前執行命令
exports.getRunPresetExec = (env = 'development', type = 'h5') => {
  const watch = env === 'development' ? '--watch' : ''
  return `npx cross-env NODE_ENV=${env} UNI_PLATFORM=${type} vue-cli-service uni-build ${watch} --color=always`
}

// 遞迴建立檔案
exports.mkdirsSync = (dirname) => {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    if (exports.mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
}
複製程式碼

總結

這次也是自己嘗試寫了個命令列工具,當然,結合多種需求場景,可以發揮出很大的作用,不過如今無論是create-react-app,還是vue-cli的封裝都十分完善了,但我們也需要知道是如何實現的,才能當遇到這種常見的時候可以變通。

覺得還可以的就去 open-devtools 點給start