實作自己的 npx 指令

tags: 環境設定 Webpack
category: Programming
description: 實作自己的 npx 指令
created_at: 2022/02/07 13:30:00

cover image


前言

新年快樂,從過年前就在想每次做 Side Project 都要初始化一些環境設定很麻煩,例如 eslintprettierjsconfig...之類的, eslint 可以使用 npx 幫忙初始化倒是還好,但 prettier 總要自己下 install 還要寫 prettierrc 就算了,還要去改 eslintrc每次做一次忘一次,於是就想說既然 eslint 都提供了一個 npx 指令去做初始化,那我是不是也可以做一個指令來幫助自己?

於是就趁過年連假做了一下,在今天整理一下怎麼做 npx 指令。

而這個是成品:https://github.com/LaiJunBin/lai-cmd


事前準備

  • 裝好 Node.js

建立空專案

開啟一個空的資料夾,然後切進去初始化專案

$ npm init -y

然後順便 promote 一下自己的 cmd,可以下

$ npx lai-cmd init js

去幫你設定好 eslint + prettier + jsconfig,這時只要你的 vscode,有安裝 EsLint 的擴充功能和相應的設定,應該就會運作正常。


開始寫第一個 npx 指令

先建立 index.js 並放入最簡單的 Hello World

console.log('Hello World.')

然後到 package.json 加入 binkey

{
  // ...
  "bin": {
    "lai-npx": "index.js"
  },
  // ...
}

那個 bin 物件中, key 是未來在 npx 後面要接的東西,以這邊來說就是

$ npx lai-npx

就會去執行 index.js

但在執行之前必須先下指令安裝,不然會找不到(因為並不在 npm 上面)

$ npm i -g

要移除的話

$ npm uni -g

但是實際去跑會出現錯誤,這是因為沒辦法直接跑 js, 所以要讓 js 跑在 node 環境上,要在第一行加上

#! /usr/bin/env node

也就是完整變成

#! /usr/bin/env node

console.log('Hello World.')

再去跑一次指令,就會正常印出 Hello World. 了。

但是這樣子測試起來挺麻煩的,每次都要先 uninstallinstall,所以我做了一些處理。


先整理一下檔案目錄

這邊我打算這樣子規劃

  • bin/index.js: 進入點,只負責去 call build 的程式
  • build/index.js: webpack build output
  • src/index.js: 你的主程式

安裝相依套件

$ npm i -D webpack webpack-cli @babel/eslint-parser @babel/preset-env babel-loader

修改 package.json

{
  // ...
  "scripts": {
    "dev": "webpack --mode=development",
    "watch": "webpack --mode=development --watch",
    "build": "webpack --mode=production"
  },
  "bin": {
    "lai-npx": "bin/index.js"
  },
  // ...
}

回顧一下檔案

bin/index.js

#! /usr/bin/env node

require('../build/index').run()

src/index.js

const run = () => {
  console.log('Hello World')
}
module.exports = { run }

再來去執行 Webpack 編譯後,直接執行 node bin/index.js,就可以進行測試。

再來需要的就是一套製作 CLI 的框架,雖然也可以自己實作,不過既然已經有現成的那就直接用吧,有閒在自己實作當練習

這邊使用的是: https://github.com/tj/commander.js/

安裝

$ npm i commander

寫個簡單的 Hello <something> 範例

const { program } = require('commander')

const run = () => {
  program
    .command('hello')
    .description('Print Hello <something>.')
    .argument('<something>', 'a string')
    .action((something) => console.log(`Hello ${something}.`))

  program.parse(process.argv)
}

module.exports = { run }

這時直接去執行會出現一個錯誤,是因為用到 async 時在轉譯的時候需要 regeneratorRuntime,可以一樣透過 npm 安裝

$ npm i regenerator-runtime

然後在前面加上一行 require

require('regenerator-runtime/runtime')
// ...

再去執行之後會看到預設的 help 訊息

Usage: index [options] [command]

Options:
  -h, --help         display help for command

Commands:
  hello <something>  Print Hello <something>.
  help [command]     display help for command

可以看到現在有一個 hello <something> 的指令,當你輸入 node bin\index.js hello world 會得到 Hello world.

這時你就可以照你的習慣去切分你的程式碼做開發。


發布

發布之前還是先做一下檢查,先

$ npm i -g

看一下在本地的 npx 正不正常

發布前準備

  • 你需要一個 npm 帳號

再來下

$ npm login

登入完成後

$ npm publish

這樣你的套件就會出現在 npm 網站上了!

接著就可以在 npx 執行你的指令。




最後更新時間: 2022年02月07日.