之前學習了怎么在npm上傳自己的模塊,現在可以開發自己的腳手架了。
1、結構介紹
模塊目錄基本結構如下:
/bin # ------ 命令執行文件
/lib # ------ 工具模塊
/template # ------ 模板
package.json
可以先不用在意這個結構。
2、實現命令行的操作
1)新建package.json
$ md my-cli // 創建插件項目文件夾
$ cd my-cli // 進入新建項目目錄
$ npm init -y // 創建package.json文件
根目錄下得到package.json文件,修改如下:
{
"name": "my-cli",
"version": "1.0.0",
"description": "",
// "main": "index.js",
"bin": { // main入口修改為bin入口
"my-cli": "./bin/cli.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
2)新建入口文件cli.js
根目錄新建./bin/cli.js文件,如下:
#!/usr/bin/env node
console.log("my-cli");
此時根目錄運行如下:
$ node ./bin/cli.js
my-cli
得到my-cli的信息,表示運行成功。
文件開頭的 #!/usr/bin/env node 是必須的。詳情見https://www.npmjs.cn/files/package.json/#bin
3)使用commander開發命令行工具
生產環境安裝commander,如下:
$ npm i commander -S
注冊命令行
./bin/cli.js文件修改如下:
#!/usr/bin/env node
const program = require('commander'); // npm i commander -S
program.version('0.0.1')
.usage('<command> [項目名稱]')
.command('init', 'init')
.parse(process.argv)
此時需要新增./bin/cli-init.js文件如下:
#!/usr/bin/env node
console.log('init');
此時根目錄運行如下:
$ node ./bin/cli.js init
init
得到init的信息,表示命令行工具注冊成功。
獲取命令行輸入的內容
./bin/cli-init.js文件修改如下:
#!/usr/bin/env node
const program = require('commander')
const path = require('path')
program.usage('<project-name>').parse(process.argv)
let projectName = program.args[0] // 根據輸入,獲取項目名稱
let rootName = path.basename(process.cwd()); // 獲取當前進程的根目錄名稱
console.log(projectName, rootName);
驗證:
$ node ./bin/cli.js init my-project
my-project my-cli
官方中文文檔:Commander開發命令行工具
4)使用inquirer命令行交互工具
生產環境安裝inquirer,如下:
$ npm i inquirer -S
./bin/cli-init.js文件修改如下:
#!/usr/bin/env node
const program = require('commander')
const path = require('path')
const inquirer = require('inquirer') // 新增引入inquirer
program.usage('<project-name>').parse(process.argv)
let projectName = program.args[0]
let rootName = path.basename(process.cwd());
console.log(projectName, rootName);
// 新增命令行交互
inquirer.prompt([
{
name: 'projectName', // 參數名稱
message: '項目的名稱', // 信息提示
default: projectName // 默認值
}, {
name: 'projectVersion',
message: '項目的版本號',
default: '0.0.1'
}, {
name: 'projectDescription',
message: '項目的簡介',
default: `A project named ${projectName}`
}
]).then(answers => {
console.log(answers); // 打印輸入參數
})
運行,輸出如下:
$ node ./bin/cli.js init my-project
my-project my-cli
? 項目的名稱 my-project
? 項目的版本號 0.0.1
? 項目的簡介 A project named my-project
{
projectName: 'my-project',
projectVersion: '0.0.1',
projectDescription: 'A project named my-project'
}
以上,就得到了幾個重要的參數:項目名稱、項目更目錄名稱、用戶錄入參數。簡單的實現了,node命令行的操作。
3、腳手架本地運行和測試
目前一直是$ node ./bin/cli.js init my-project的方式在運行腳本,體驗并不好,沒有腳手架的使用效果。我們現在可以進行本地包的運行和測試了。
1)安裝my-cli腳手架到全局
my-cli根目錄運行如下:
$ npm link
此時腳手架被安裝到全局,可以使用了。
推薦閱讀:npm link的使用
npm unlink // 卸載link安裝
2)新建一個項目
在其它目錄下新建一個項目如下:
$ md my-project // 創建項目文件夾
$ cd my-project // 進入項目文件夾
$ my-cli init my-project // 運行腳手架
my-project my-project
? 項目的名稱 my-project
? 項目的版本號 0.0.1
? 項目的簡介 A project named my-project
{
projectName: 'my-project',
projectVersion: '0.0.1',
projectDescription: 'A project named my-project'
}
得到如上信息,代表腳手架運行成功!
這篇文章的目的是為學習,為了最簡單的理解腳手架是怎么工作,用什么實現的,所以這里是沒有做校驗邏輯。
4、復制模板文件到項目
只是單文件的復制,使用node的fs就能完成,但模板文件一般都是文件夾的多文件復制,所以我使用mvdir模塊來復制文件夾,很好用。
1)新建模板文件
my-cli根目錄下,新建template文件夾,新建模板文件package.json,也可以是任意你想復制的文件。
my-cli/template/package.json文件如下:
{
"name": "{{projectName}}",
"version": "{{projectVersion}}",
"description": "{{projectDescription}}",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
{{}}內的是模板變量占位符。
2)mvdir復制模板文件
my-cli根目錄安裝mvdir,如下:
$ npm i mvdir -S
./bin/cli-init.js文件修改如下:
……
const mvdir = require('mvdir') // 引入模塊
……
]).then(answers => {
console.log(answers);
// 使用mvdir復制template文件夾內容到my-project項目的.download-temp文件夾下。.download-temp為臨時文件夾,編譯模板后會刪除。
mvdir(path.join(__dirname, '../template'), '.download-temp', { copy: true }).then((err) => {
if (err) {
console.log(err);
} else {
console.log('復制成功');
}
});
})
my-project項目根目錄下,運行:
$ my-cli init my-project
得到復制成功,就可在項目下看到復制的模板文件。
目前模板文件很小,所以放在了npm包里。如果模板文件很大,不適合放在npm包里的時候,可以將模板文件放在git上,然后使用download-git-repo工具,下載git上的模板文件到.download-temp的臨時文件夾下。
5、使用Metalsmith編譯模板文件
metalsmith就是一個靜態網站生成器,可以用在批量處理模板的場景。handlebars是metalsmith的超集。
生產環境安裝metalsmith和handlebars,如下:
$ npm i metalsmith handlebars -S
./bin/cli-init.js文件修改如下:
……
const Metalsmith = require('metalsmith') // 引入靜態網站生成器
const Handlebars = require('handlebars') // 引入模板引擎
const rm = require('rimraf').sync
……
} else {
console.log('復制成功');
const src = `${process.cwd()}/.download-temp`;
Metalsmith(process.cwd())
.metadata(answers) // 全局元數據
.clean(false) // 是否刪除
.source(src) // 編譯來源路徑
.destination('.') // 編譯目標路徑
.use((files, metalsmith, done) => { // 自定義插件
const meta = metalsmith.metadata()
Object.keys(files).forEach(fileName => {
const t = files[fileName].contents.toString()
files[fileName].contents = Buffer.from(Handlebars.compile(t)(meta))
})
done()
})
.build(err => {
rm(src)
if(err) {
console.log(err);
} else {
console.log('腳手架運行成功');
}
})
}
……
my-project下運行:
$ my-cli init my-project
得到“腳手架運行成功”的提示,至此npm腳手架的基本功能就完成了。
目前還沒有使用lib文件夾,后續的開發中,需要對用戶輸入的校驗、模板編譯文件的篩選、異步操作隊列化等功能,都可封裝到lib工具模塊中使用,減小bin文件的體積,提高可復用性。
擴展閱讀:metalsmith-api、handlebars
本人基于此文章《基于node.js的腳手架工具開發經歷》學習,學習后重新整理思路,編寫此文章留作筆記。