1、基本逻辑
npm start执行前执行node ./bin/wb-handle
"scripts": {
"wb": "node ./bin/wb-handle; npm start"
},
wb-handle源码,删除deleteNodeModules配置的最后一级目录文件
#!/usr/bin/env node --max-old-space-size=4096 --optimize-for-size --max_old_space_size=4096 --optimize_for_size
"use strict";
var deleteNodeModules = "abab/efg";
var fs = require("fs");
function deleteFolderRecursive(path) {
if( fs.existsSync(path) ) {
fs.readdirSync(path).forEach(function(file) {
var curPath = path + "/" + file;
if(fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
deleteFolderRecursive(`./node_modules/${deleteNodeModules}`)
2、推包到npm
接下来我们代码推包到npm使用
{
"name": "wb-handle",
"version": "1.0.2",
"description": "delete mode_modules file",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"wbhandle": "./bin/wb-handle.js"
},
"keywords": [
"node"
],
"author": "wangb",
"license": "ISC"
}
wb-handle.js改进代码,可以在项目package.json配置deleteModule自动删除nodel_modules中的包
#!/usr/bin/env node --max-old-space-size=4096 --optimize-for-size --max_old_space_size=4096 --optimize_for_size
"use strict";
const path = require('path');
var fs = require("fs");
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
var packagePath = resolveApp("package.json")
var packageJson = require(packagePath);
var deleteModule = packageJson && packageJson.deleteModule;
if (!deleteModule) {
console.log("请在package.json中输入deleteModule");
return;
}
function deleteFolderRecursive(path) {
if( fs.existsSync(path) ) {
fs.readdirSync(path).forEach(function(file) {
var curPath = path + "/" + file;
if(fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
deleteFolderRecursive(`./node_modules/${deleteModule}`)
3、使用
yarn add wb-handle -D
配置项目命令
"scripts": {
"start": "wbhandle;react-scripts start --port 3000",
},
4、继续改进可以读取命令行参数执行指令
#!/usr/bin/env node --max-old-space-size=4096 --optimize-for-size --max_old_space_size=4096 --optimize_for_size
"use strict";
const path = require("path");
var fs = require("fs");
const args = process.argv.slice(2);
const scriptIndex = args.findIndex((x) => x === "delete");
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
if (script.indexOf("delete") !== -1) {
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
var packagePath = resolveApp("package.json");
var packageJson = require(packagePath);
var deleteModule = packageJson && packageJson.deleteModule;
if (!deleteModule) {
console.log("请在package.json中输入deleteModule");
return;
}
function deleteFolderRecursive(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(function (file) {
var curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
// recurse
deleteFolderRecursive(curPath);
} else {
// delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
}
deleteFolderRecursive(`./${deleteModule}`);
}
5、创建delete和copy命令
Wb-handle.js代码
#!/usr/bin/env node --max-old-space-size=4096 --optimize-for-size --max_old_space_size=4096 --optimize_for_size
"use strict";
const path = require("path");
var fs = require("fs");
const args = process.argv.slice(2);
const scriptIndex = args.findIndex((x) => x === "delete");
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
var packagePath = resolveApp("package.json");
var packageJson = require(packagePath);
if (script.indexOf("delete") !== -1) {
var deleteModule = packageJson && packageJson.deleteModule;
if (!deleteModule) {
console.error("请在package.json中输入deleteModule");
return;
}
if (Array.isArray(deleteModule)) {
deleteModule.forEach((item) => {
require("../script/delete")(`./${item}`);
});
} else {
require("../script/delete")(`./${deleteModule}`);
}
} else if (script.indexOf("copy") !== -1) {
var copy = packageJson && packageJson.copyModule;
if (Array.isArray(copy)) {
copy.forEach((item) => {
// 复制文件
require("../script/copy")(`./${item.from}`, `./${item.to}`);
});
} else {
console.error("copy必须是数组格式");
}
}
script/copy代码如下
const path = require("path");
var fs = require("fs");
var copyFile = function (srcPath, tarPath, cb) {
var rs = fs.createReadStream(srcPath);
rs.on("error", function (err) {
if (err) {
console.error("read error", srcPath);
}
cb && cb(err);
});
var ws = fs.createWriteStream(tarPath);
ws.on("error", function (err) {
if (err) {
console.error("write error", tarPath);
}
cb && cb(err);
});
ws.on("close", function (ex) {
cb && cb(ex);
});
rs.pipe(ws);
};
var copyFolder = function (srcDir, tarDir, cb) {
fs.readdir(srcDir, function (err, files) {
var count = 0;
var checkEnd = function () {
++count == files.length && cb && cb();
};
if (err) {
checkEnd();
return;
}
if (!fs.existsSync(tarDir)) {
fs.mkdirSync(tarDir);
}
files.forEach(function (file) {
var srcPath = path.join(srcDir, file);
var tarPath = path.join(tarDir, file);
fs.stat(srcPath, function (err, stats) {
if (stats.isDirectory()) {
fs.mkdir(tarPath, function (err) {
if (err) {
console.error(err);
return;
}
copyFolder(srcPath, tarPath, checkEnd);
});
} else {
copyFile(srcPath, tarPath, checkEnd);
}
});
});
//为空时直接回调
files.length === 0 && cb && cb();
});
};
// 复制文件
function wbCopyFile(orgfilepath, desdirpath) {
if (fs.lstatSync(orgfilepath).isDirectory()) {
// 目录到指定目录
copyFolder(orgfilepath, desdirpath);
} else {
// 文件到指定目录
if (fs.existsSync(orgfilepath)) {
if (!fs.existsSync(desdirpath)) {
fs.mkdirSync(desdirpath);
fs.copyFileSync(
orgfilepath,
`${desdirpath}/${path.basename(orgfilepath)}`
);
} else {
fs.copyFileSync(
orgfilepath,
`${desdirpath}/${path.basename(orgfilepath)}`
);
}
} else {
console.error(
Date().toString() +
"FolderAndFileOperation_copyFile: org file not existed." +
" org path: " +
orgfilepath.toString()
);
}
}
}
module.exports = wbCopyFile;
script/delete代码如下
var fs = require("fs");
function deleteFolderRecursive(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(function (file) {
var curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
// recurse
deleteFolderRecursive(curPath);
} else {
// delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
}
module.exports = deleteFolderRecursive;
6、支持创建模版文件
wb-handle代码修改为下面
#!/usr/bin/env node --max-old-space-size=4096 --optimize-for-size --max_old_space_size=4096 --optimize_for_size
"use strict";
const path = require("path");
var fs = require("fs");
const args = process.argv.slice(2);
const scriptIndex = args.findIndex(
(x) => x === "delete" || x === "copy" || x === "tem"
);
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
var packagePath = resolveApp("package.json");
var packageJson = require(packagePath);
if (script.indexOf("delete") !== -1) {
var deleteModule = packageJson && packageJson.deleteModule;
if (!deleteModule) {
console.error("请在package.json中输入deleteModule");
return;
}
if (Array.isArray(deleteModule)) {
deleteModule.forEach((item) => {
require("../script/delete")(`./${item}`);
});
} else {
require("../script/delete")(`./${deleteModule}`);
}
} else if (script.indexOf("copy") !== -1) {
var copy = packageJson && packageJson.copyModule;
if (Array.isArray(copy)) {
copy.forEach((item) => {
// 复制文件
require("../script/copy")(`./${item.from}`, `./${item.to}`);
});
} else {
console.error("copy必须是数组格式");
}
} else if (script.indexOf("tem") !== -1) {
const list = args.findIndex((x) => x === "list");
const nameIndex = args.findIndex((x) => x.indexOf("name=") !== -1);
if (nameIndex === -1) {
console.error("template必须输入name=");
return;
}
const nameArr = args[nameIndex].split("=");
const name = nameArr[1];
if (list !== -1) {
require("../script/template")(name, true); // 列表
} else {
require("../script/template")(name, false); // 视图
}
}
新增template.js
var fs = require("fs");
const path = require("path");
function firstToUpper(str) {
return str.trim().toLowerCase().replace(str[0], str[0].toUpperCase());
}
function create(name, list) {
var template;
var templateModel;
var templateDir = path.resolve(__dirname, '../template');
if (list) {
template = fs.readFileSync(templateDir +"/template.list.tsx");
templateModel = fs.readFileSync(templateDir + "/template.model.ts");
} else {
template = fs.readFileSync(templateDir +"/template.tsx");
templateModel = fs.readFileSync(templateDir +"/template.model.ts");
}
var templateStr = template
.toString()
.replace(/ModuleName/g, firstToUpper(name))
.replace(/moduleName/g, name);
var templateModelStr = templateModel
.toString()
.replace(/ModuleName/g, firstToUpper(name))
.replace(/moduleName/g, name);
if (list) {
fs.writeFileSync("./" + name + ".list.tsx", templateStr);
} else {
fs.writeFileSync("./" + name + ".tsx", templateStr);
}
fs.writeFileSync("./" + name + ".model.tsx", templateModelStr);
}
module.exports = create;
7、支持创建通用模版
模版里支持配置的变量
/**
* 模版里支持配置的变量
* T_Name (name会自动转首字母大写)
* T_name
* T_classname
* T_id
* T_key
* T_content
*/
实现
#!/usr/bin/env node --max-old-space-size=4096 --optimize-for-size --max_old_space_size=4096 --optimize_for_size
"use strict";
const path = require("path");
var fs = require("fs");
const args = process.argv.slice(2);
const scriptIndex = args.findIndex(
(x) => x === "delete" || x === "copy" || x === "tem"
);
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
/**
* 获取命令行参数并返回对象
* @returns {Object} 参数对象
*/
function getOption() {
const arr = process.argv.slice(2); // 获取命令行参数数组
const r = arr.reduce((pre, item) => { // 使用reduce方法对参数数组进行处理
if (item.indexOf("=") !== -1) { // 判断参数是否有等号
return [...pre, item.split("=")]; // 将带有等号的参数进行分割并添加到结果数组中
}
return pre; // 否则返回原结果数组
}, []);
const params = Object.fromEntries(r); // 将结果数组转化为参数对象
return params; // 返回参数对象
}
if (script.indexOf("delete") !== -1) {
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
var packagePath = resolveApp("package.json");
var packageJson = require(packagePath);
var deleteModule = packageJson && packageJson.deleteModule;
if (!deleteModule) {
console.error("请在package.json中输入deleteModule");
return;
}
if (Array.isArray(deleteModule)) {
deleteModule.forEach((item) => {
require("../script/delete")(`./${item}`);
});
} else {
require("../script/delete")(`./${deleteModule}`);
}
} else if (script.indexOf("copy") !== -1) {
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
var packagePath = resolveApp("package.json");
var packageJson = require(packagePath);
var copy = packageJson && packageJson.copyModule;
if (Array.isArray(copy)) {
copy.forEach((item) => {
// 复制文件
require("../script/copy")(`./${item.from}`, `./${item.to}`);
});
} else {
console.error("copy必须是数组格式");
}
} else if (script.indexOf("tem") !== -1) {
const obj = getOption();
if (!obj.name) {
console.error("template必须输入name=");
return;
}
require("../script/template")(obj); // 列表
}
var fs = require("fs");
const path = require("path");
/**
* 模版里支持配置的变量
* T_Name (name会自动转首字母大写)
* T_name
* T_param
* T_key
* T_content
* T_classname
* T_id
*/
function firstToUpper(str) {
var firstLetter = str.charAt(0).toUpperCase() + str.slice(1);
return firstLetter;
}
function create(obj = {}) {
var templateDir = path.resolve(__dirname, "../tem");
fs.readdirSync(templateDir).forEach((file) => {
const filePath = path.join(templateDir, file);
if (fs.statSync(filePath).isFile()) {
const fileContent = fs.readFileSync(filePath, "utf8");
var templateStr = fileContent
.toString()
.replace(/T_Name/g, obj.name ? firstToUpper(obj.name) : "")
.replace(/T_name/g, obj.name)
.replace(/T_param/g, obj.content)
.replace(/T_key/g, obj.key)
.replace(/T_content/g, obj.content)
.replace(/T_classname/g, obj.classname)
.replace(/T_id/g, obj.id);
if (!fs.existsSync("./temOutput")) {
fs.mkdirSync("./temOutput");
}
const newFile = file.replace("tem", obj.name);
fs.writeFileSync("./temOutput/" + newFile, templateStr);
}
});
}
module.exports = create;
8、最终版本使用
使用在项目package.json配置如下
"scripts": {
"start": "wbhandle delete;react-scripts start --port 3000",
"tem": "wbhandle tem"
},
"deleteModule": [
"node_modules/busynessbill1",
"node_modules/busynessbill2",
"node_modules/busynessbill3"
]
// 或者
"deleteModule": "test/package.json" // 删除指定文件夹
"copyModule": [
{
"from": "package.json", // 复制文件到指定目录
"to": "test"
},
{
"from": "image", // 复制文件夹到指定目录
"to": "test"
}
],
创建模版文件执行
npm run tem name=ceshiwenjian
npm run tem name=ceshiwenjian list // 列表模版