脚手架难点(1)-动态化命令&多进程实战

938 阅读2分钟

Why?

  • cli安装速度慢,所有package都集成在cli里面,多进程进行性能优化&本地包缓存
  • init命令只能使用@mac-mw-cli-dev/init包,其实各个bu的包init命令可能都不一样,

实现动态init命令, 脚手架支持a使用a-init包 b使用b-init包

what?

How?

核心流程点分析

封装Package类

让每一个npm包对应一个Package实例,这样我们可以封装出包最新版本,包是否在本地缓存等方法.作用:优先使用本地缓存的Init命令的npm包,且支持自动升级包版本

class Package{

  /** 在命令行指定了init包的路径 */
  this.targetPath = options.targetPath;
  /** 缓存在.mac-mw-cli-dev的init包路径目录 */
  this.storeDir = options.storeDir;
  /** npm包的name */
  this.packageName = options.name;
  /** npm包的version */
  this.packageVersion = options.version;
  /** 缓存目录前缀 */
  this.cacheFilePathPrefix = this.packageName.replace("/", "_");
  /** 判断当前包是否存在于本地的缓存目录 */
  async exits(){
    
  }
  /** 安装npm包到本地的缓存目录 */
  async install(){
    
  }
  /** 如果本地安装了包,会去对比npm最新版本,同时本地包更新到最新版本 */
  async update(){
    
  }
  /** 获取包的入口文件 */
  async getRootFilePath(){
    
  }
}

封装Command类

将脚手架的每个命令对应于我们的Command类,内部封装命令的准备阶段和执行阶段,采用promise方式按序执行.准备阶段执行node版本和参数初始化等前置操作,执行阶段真正执行命令

class Command {
  constructor(){
    promise.then(()=>fun1)
    promise.then(()=>init())
    promise.then(()=>exec())
  }
  async init(){
    
  }
  async exec(){
    
  }
}

本地包缓存

if(pkg,exits()){
  await pkg.update(); //先测试一下是否是最新版本
 
}else{
   pkg.install(); //下载包到本地缓存目录
}
// 直接使用本地包
const rootFile = pkg.getRootFilePath()
// 执行包里面到处的方法
onst code = `require('${rootFile}')(${JSON.stringify(options)})`;
await execSync("node", ["-e", code], {
      stdio: "inherit",
      cwd: process.cwd(),
});

Node多进程-childprocess

将安装依赖和执行npm install等方法用spawn子进程执行

const exec = (command, args, options) => {
  const win32 = process.platform === "win32";
  const cmd = win32 ? "cmd" : command; // windows 下 cmd才是可执行文件
  const cmdArgs = win32 ? ["/c"].concat(command, args) : args; //// windows 下 /c表示 静莫执行
  return require("child_process").spawn(cmd, cmdArgs, options || {});
};
const execSync = (command, args, options) => {
  return new Promise((resolve, reject) => {
    const p = exec(command, args, options);
    p.on("error", (e) => reject(e));
    p.on("exit", (c) => resolve(c));
  });
};
// eg
const code = `require('${rootFile}').call(null, ${JSON.stringify(
        argsTemp
)})`;
const child = spawn("node", ["-e", code], {
    cwd: process.cwd(),
    stdio: "inherit",
});

支持各方Init包

配置好各方init包的npm名字,通过Package类的install去安装和缓存,最后通过Node多进程去执行main里到处的函数

const SETTINGS = {
  init: "@mac-mw-cli-dev/init", // important 这里可以根据不同的公司用不同的init包 然后不指定targetPath 那么脚手架会把这个包缓存到本地 然后用这个包去执行方法 而且会判断是否有新版本更新
};
 pkg = new Package({
      targetPath,
      name: npmPackageName,
      version: packageVersion,
      storeDir,
});
if (await pkg.exits()) {
    await pkg.update();
} else {
    await pkg.install();
}

End

代码链接在这里: github.com/bangbang6/m…

规划->变化->Buffer->目标.

我们的努力,都是向着金钱看齐.

Time