实现多套代码同时打包

背景: 一个路径包含了PC和手机端两套代码,两端代码是独立的vue-cli项目,要分别打包后放入同一个生产目录publish中。其中PC端打包输出的代码放在publish根目录,手机端放在publish/phone目录中。
资源结构:

publish //生产目录
src //PC端源码目录
--src //PC端资源
----phone //手机源码目录

缺陷: 每次修改代码都需要打包两次,打包完后还需要手动复制进生产目录。
优化: 将两个打包过程一体化,做到输入一个指令就能将PC和手机代码都打包并放进相应的生产目录。
实现:

第一步:在PC端源码根目录添加打包指令 “build-all”。

要做到打包PC端代码的同时,还要去手机端代码目录进行打包,这应该无法用一句字符串做到,所以将详细操作写进js文件里,输入指令后通过node 执行js文件达到目的。在这里插入图片描述

第二步:创建build-all.js,实现打包逻辑

这里梳理一下要做的事情:
1、打包前清空原publish目录,防止旧文件残留。
2、要在PC端源码根目录启动命令,执行js代码,执行npm run build打包PC端代码,并能继续进入到手机端目录,执行npm run build打包手机端代码
3、PC端打包好后,将输出代码(dist目录)复制到publish目录,phone打包好后,从phone下的dist移动到publish/phone。

实现第一点: 首先是想到了node的文件系统,参考网上用递归写了个删除函数

function deleteFile(pathNamedir) {
  // 读取文件夹内容
  const files = fs.readdirSync(pathNamedir);
  files.forEach(file => {
    const dirName = path.resolve(pathNamedir, file),
      stats = fs.lstatSync(dirName); // 返回值可以判断文件类型
    // 如果是文件夹递归调用函数
    if (stats.isDirectory()) {
      deleteFile(dirName);
    } else {
      fs.unlinkSync(dirName);
    }
  });
  // 清空文件夹内容之后之后删除文件夹
  // fs.rmdirSync(pathNamedir);
}

参考资源:全新体验,用node.js命令行方式清空并删除文件夹

实现第二点::由于对nodejs不熟,卡在nodejs怎么去执行npm指令这块,而且还要能去其他目录执行。网上一顿冲浪,找到child_process.exec(),它能创建一个shell,然后在shell里执行命令,关键还可以定义执行路径。没错这就是我想要的。
代码大概是这样:(两个打包程序同时进行)

const child_process = require("child_process");
child_process.exec("npm run build", function(error) {
  if (error) {
    console.log("PC端编译失败!!!", error);
  } 
});
child_process.exec("npm run build", { cwd: "./src/phone" }, function(error) {
  if (error) {
    console.log("phone端编译失败!!!", error);
  }
});

参考资源:
nodejs官网
其他方法讨论

实现第三点: 能打包完成了,还要能复制进生产目录,可以直接设置vue.config.js的 outputdir,把两者的输出目录改为相应的生产目录就行,但需要注意把打包时自动清理输出目录关闭掉,因为手机输出目录是PC输出目录的子目录,他俩无法保证谁先打包完,所以不能在打包时删除,但可提前删除。
但这里我还是想试着通过复制的方式去实现,首先想到的还是fs,但由于太麻烦了,找到了一个shelljs库,可以直接通过shell脚本操作文件。
一个shell.cp()方法即可实现资源复制;另外之前的删除也不用这么一大堆了,shelljs一句话就能搞定。

  //安装shelljs
  //删除publish目录后新建publish和phone空文件夹
  shell.rm("-rf", "../publish");
  shell.mkdir("-p", "../publish/phone");
  //移动PC端文件至publish目录,(注意会将整个文件夹包括最外层一起复制过去,外层是dist文件夹,不需要所以遍历去复制了)
  shell.ls(distPc).forEach(file => {
    shell.cp("-r", distPc + file, publishPc);
  });

完整的实现代码(简易版):

const shell = require("shelljs"); //用于操作文件
const child_process = require("child_process");
//PC和手机端dist输出路径和生产路径(相对于当前文件执行目录)
const distPc = "dist/",
  distPhone = "src/phone/dist/",
  publishPc = "../publish/",
  publishPhone = "../publish/phone/";
var compiledPC = false,
  compiledPHONE = false;

function startCompile() {
  console.log("正在编译PC端文件和phone端文件......");
  // 衍生一个 shell 并在 shell 中执行 command
  child_process.exec("npm run build", function(error) {
    if (error) {
      console.log("PC端编译失败!!!", error);
    } else {
      console.log("PC端编译完成");
      //移动PC端文件至publish目录
      shell.ls(distPc).forEach(file => {
        shell.cp("-r", distPc + file, publishPc);
      });
      compiledPC = true;
    }
  });

  child_process.exec("npm run build", { cwd: "./src/phone" }, function(error) {
    if (error) {
      console.log("PHONE端编译失败!!!", error);
    } else {
      console.log("PHONE端编译完成");
      //移动PHONE端文件至publish/phone目录
      shell.ls(distPhone).forEach(file => {
        shell.cp("-r", distPhone + file, publishPhone);
      });
      compiledPHONE = true;
    }
  });
}

(function() {
  console.log("重置publish目录");
  shell.rm("-rf", "../publish");
  shell.mkdir("-p", "../publish/phone");
  startCompile();
  var timer = setInterval(() => {
    if (compiledPC && compiledPHONE) {
      clearInterval(timer);
      timer = null;
      console.log("编译完成!!!");
    }
  }, 1000);
})();
//TODO :还有缺陷,要结束进程啥的

完整的实现代码(使用了Promise和差错重编):

const shell = require("shelljs"); //用于操作文件
const child_process = require("child_process");
//PC和手机端dist输出路径和生产路径(相对于当前文件执行目录)
const distPc = "dist/",
  distPhone = "src/phone/dist/",
  publishPc = "../publish/",
  publishPhone = "../publish/phone/";
var reBuildTimes = 1;

var startCompile = compileLog => {
  console.log(compileLog);

  let promisePC = new Promise((resolve, reject) => {
    // 衍生一个 shell 并在 shell 中执行 command
    child_process.exec("npm run build", error => {
      if (error) {
        reject({ type: "PC", error });
      } else {
        //移动PC端文件至publish目录
        shell.ls(distPc).forEach(file => {
          shell.cp("-r", distPc + file, publishPc);
        });
        resolve();
      }
    });
  });

  let promisePHONE = new Promise((resolve, reject) => {
    child_process.exec("npm run build", { cwd: "./src/phone" }, error => {
      if (error) {
        reject({ type: "PHONE", error });
      } else {
        //移动PHONE端文件至publish/phone目录
        shell.ls(distPhone).forEach(file => {
          shell.cp("-r", distPhone + file, publishPhone);
        });
        resolve();
      }
    });
  });

  Promise.all([promisePC, promisePHONE])
    .then(() => {
      console.log("编译完成!!!");
    })
    .catch(error => {
      //重新编译reBuildTimes次
      if (reBuildTimes-- > 0) {
        startCompile(`${error.type}端编译出错,正在重新编译......`);
      } else {
        console.log(
          error.error + "\n" + error.type + "端编译出错,编译失败!!!"
        );
        process.exit(0);
      }
    });
};

(function() {
  console.log("重置publish目录");
  shell.rm("-rf", "../publish");
  shell.mkdir("-p", "../publish/phone");
  startCompile("正在编译PC端文件和PHONE端文件......");
})();

编译效果:
在这里插入图片描述

参考资源:
shelljs官方
shelljs中文
使用ShellJS提升你的开发效率(一)
nodeJs写一个移动文件的脚本
Stream文件流模块以及pipe()进行大文件复制
移动文件讨论
vue-cli不自动清理输出目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值