學習
node.js
生成文件、執行腳本,使用CI
持續集成,自動構建工具以後,想要玩玩本身寫點東西試試css
- 命令行參數獲取使用commander.js
- 命令行交互使用Inquirer.js
- 目錄樹生成使用treer
代碼:github地址html
目錄結構:前端
D:\node-test
...
├─index.js
├─sh
| └sh1.js
├─scripts
| └generateComponent.js
├─components
| ...
| ├─run-sh.js
...
複製代碼
D:\node-test
├─ components
├─ components-dir-tree1.json
├─ file.2.js
├─ file.bakeup.js
├─ file.js
├─ index.js
├─ log.js
├─ node-test-dir-tree.json
├─ run-sh.js
├─ test
└─ aa
├─ bb.js
└─ cc
└─ timeFormat.js
├─ index.js
├─ json
├─ a.json
└─ b.json
├─ package-lock.json
├─ package.json
├─ README.md
├─ scripts
└─ generateComponent.js
└─ sh
└─ sh1.js
複製代碼
package.json:
{
...
"scripts": {
"create:comp": "node scripts/generateComponent --path",
},
...
}
複製代碼
--path
能夠自行設置,獲取的時候[path]
將做爲key
存到program
node
const program = require('commander'); // 命令參數處理
program
.version('0.0.1')
.option('-l --path [path]', 'list of customers in CSV file')
.parse(process.argv);
// node scripts/generateComponents --path inputName
const inputName = program.path;
log('\ninputName: ',inputName);
複製代碼
name
:字段名, 調用then的回調參數值裏能夠找到匹配的name,message
:提示信息,questions數組內一個子對象的type
能夠是:
react
(如下摘抄自Inquirer.js)git
confirm
: yes/no,type, name, message, [, default] 屬性input
: 鍵盤輸入,type, name, message, [, default, filter, validate, transformer] 屬性.number
: type, name, message, [, default, filter, validate] 屬性.rawlist
: 相似於ol標籤,有序列表,type, name, message, choices, [, default, filter] 屬性list
: 相似於ul標籤,無序列表,type, name, message, choices, [, default, filter] 屬性checkbox
: 多選,type, name, message, choices, [, default, filter, validate] 屬性expand
: 展開menu,type, name, message, choices, [, default] 屬性password
: type, name, message, mask, [, default, filter, validate] 屬性.editor
: type, name, message, mask, [, default, filter, validate] 屬性.
const questions = [
{
type: "confirm",
name: "override",
message: "是否覆蓋?"
}
];
inquirer.prompt(questions).then(res => {
if (res.override) {
log('\n文件將被覆蓋!');
resolve(path);
} else {
log('\n不覆蓋已有文件!');
}
});
複製代碼
更多的屬性:github
{
/* Preferred way: with promise */
filter() {
return new Promise(/* etc... */);
},
/* Legacy way: with this.async */
validate: function (input) {
// Declare function as asynchronous, and save the done callback
var done = this.async();
// Do async stuff
setTimeout(function() {
if (typeof input !== 'number') {
// Pass the return value in the done callback
done('You need to provide a number');
return;
}
// Pass the return value in the done callback
done(null, true);
}, 3000);
}
}
複製代碼
const fs = require('fs');
const path = require('path');
const program = require('commander'); // 命令參數處理
const inquirer = require('inquirer'); // 選擇
const chalk = require('chalk');
const log = (...text) => console.log(...text);
const componentDir = path.resolve(__dirname, '../components');
const newComp = ` const fs = require('fs'); const path = require('path'); console.log('這是一個自動生成的component'); `;
// npm scripts不能接收參數
// 下面須要 node 運行傳入參數
program
.version('0.0.1')
.option('-l --path [path]', 'list of customers in CSV file')
.parse(process.argv);
// node scripts/generateComponents --path inputName
const inputName = program.path;
log('\ninputName: ',inputName);
const questions = [
{
type: "confirm",
name: "override",
message: "是否覆蓋?"
}
];
mkdir(componentDir + `\\${inputName||'noname'}`)
.then(path => {
log('\n開始生成文件...');
return new Promise((resolve) => {
fs.writeFile(path+'\\index.js', newComp, 'utf-8', err => {
if (err) throw err;
log(`\n${path}\\index.js 文件建立成功!\n`);
resolve();
});
});
}).catch(err => {
throw err;
});
// 建立目錄
function mkdir(path) {
return new Promise((resolve) => {
if (fs.existsSync(path)) {
log(`\n${path}: 文件夾已存在`);
// 命令行交互
inquirer.prompt(questions).then(res => {
if (res.override) {
log('\n文件將被覆蓋!');
resolve(path);
} else {
log('\n不覆蓋已有文件!');
}
});
} else {
fs.mkdirSync(path);
log('\n文件夾建立成功!');
resolve(path);
}
})
}
module.export = {
mkdir
}
複製代碼
$ npm run create:comp aa
> test@1.0.0 create:comp D:\node-test
> node scripts/generateComponent --path "aa"
inputName: aa 文件夾建立成功! 開始生成文件... D:\node-test\components\aa\index.js 文件建立成功! 複製代碼
$ npm run create:comp aa
> test@1.0.0 create:comp D:\node-test
> node scripts/generateComponent --path "aa"
inputName: aa D:\node-test\components\aa: 文件夾已存在 ? 是否覆蓋? No 不覆蓋已有文件! 複製代碼
使用
child_process
子進程的exec
執行腳本shell
如下內容,摘抄自Node.js 中文網
默認狀況下,
stdin
、stdout
和stderr
的管道在父Node.js
進程和衍生的子進程之間創建。 這些管道具備有限的(和平臺特定的)容量。 若是子進程在沒有捕獲輸出的狀況下寫入超出該限制的stdout
,則子進程將阻塞等待管道緩衝區接受更多的數據。 這與shell
中的管道的行爲相同。 若是不消費輸出,則使用{ stdio: 'ignore' }
選項。npm
child_process.spawn()
方法異步地衍生子進程,且不阻塞Node.js
事件循環。child_process.spawnSync()
方法則以同步的方式提供等效功能,但會阻止事件循環直到衍生的進程退出或終止。json
爲方便起見,
child_process
模塊提供了child_process.spawn()
和child_process.spawnSync()
的一些同步和異步的替代方法。 注意,這些替代方法中的每個都是基於child_process.spawn()
或child_process.spawnSync()
實現的。
child_process.exec()
: 衍生一個shell
並在該shell
中運行命令,當完成時則將stdout
和stderr
傳給回調函數。child_process.execFile()
: 相似於child_process.exec()
,除了它默認會直接衍生命令且不首先衍生shell
。child_process.fork()
: 衍生一個新的Node.js
進程,並經過創建 IPC 通訊通道來調用指定的模塊,該通道容許在父進程與子進程之間發送消息。child_process.execSync()
:child_process.exec()
的同步版本,會阻塞Node.js
事件循環。child_process.execFileSync()
:child_process.execFile()
的同步版本,會阻塞Node.js
事件循環。 對於某些用例,例如自動化的shell
腳本,同步的方法可能更方便。 可是在大多數狀況下,同步的方法會對性能產生重大影響,由於它會中止事件循環直到衍生的進程完成。
package.json:
{
...
"scripts": {
"sh": "node components/run-sh.js",
},
...
}
複製代碼
使用npm命令時,需如上所示,在上面
package.json
中scripts
配置好
const fs = require('fs');
const isDir = dir => fs.statSync(dir).isDirectory();
/** * 返回相關的shell腳本 */
// 打印指定目錄
function ls(dir=null) {
if (dir) {
log('dir: ', dir);
return `cd ${dir} && ls`;
}
return "ls";
}
/** * 構建前端項目 * @param {項目路徑} dir * @param {執行的 npm 命令} cmd */
function buildFE(dir, cmd) {
if (!dir || !isDir(dir) || !cmd) return;
log('build-dir: ', dir);
return `cd ${dir} && ${cmd}`;
}
module.exports = {
ls,
buildFE
}
複製代碼
// exec 執行shell命令
const { exec } = require('child_process');
const path = require('path');
require('./log');
const timeFormat = require('./timeFormat');
const { ls, buildFE } = require('../sh/sh1.js');
// console.log('sh: ',sh);
const shdir = path.resolve(__dirname, '../sh');
// 打印指定路徑目錄
//exec(ls('/code/react-t1'), (err, stdout, stderr) => {
// if (err) throw err;
// if ( stderr) log('stderr: ', stderr);
// // 執行的命令所打印的內容
// log('stdout: ', stdout);
// let nowTime = timeFormat({timestamp: new Date(), hasTime: true });
// log('time: ', nowTime);
//})
let nowTime = timeFormat({timestamp: new Date(), hasTime: true });
log('start--time: ', nowTime);
exec(buildFE('/code/react-t1', 'npm run build'), (err, stdout, stderr) => {
if (err) throw err;
if ( stderr) log('stderr: ', stderr);
// 執行的命令所打印的內容
log('stdout: ', stdout);
nowTime = timeFormat({timestamp: new Date(), hasTime: true });
log('end--time: ', nowTime);
})
複製代碼
$ npm run sh
> test@1.0.0 sh D:\node-test
> node components/run-sh.js
==log== start--time: 2019-05-08 16:29:24
==log== build-dir: /code/react-t1
==log== stdout:
> react-t1@0.1.0 build D:\code\react-t1
> node scripts/build.js
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
62.73 KB docs\static\js\4.1fe71077.chunk.js
48.9 KB docs\static\js\7.70929cf8.chunk.js
14.3 KB docs\static\js\3.fe3cf9bc.chunk.js
13.3 KB docs\static\js\0.e70acbb7.chunk.js
3.22 KB docs\static\js\1.6f7cac0f.chunk.js
3.05 KB docs\static\js\2.ba0e413c.chunk.js
1.94 KB docs\static\js\main.eb84215c.chunk.js
1.48 KB docs\static\js\runtime~main.ff53614d.js
634 B docs\static\css\main.fde90119.chunk.css
592 B docs\static\js\8.d5307ac7.chunk.js
438 B docs\static\js\9.1544082f.chunk.js
434 B docs\static\css\0.451ae571.chunk.css
The project was built assuming it is hosted at ./.
You can control this with the homepage field in your package.json.
The docs folder is ready to be deployed.
Find out more about deployment here:
https://bit.ly/CRA-deploy ==log== end--time: 2019-05-08 16:29:31 ==log== stderr: { parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }. 複製代碼