Node 如何调用 vue-cli 打包

原创
前端路迹
2021-4-23 09:12
编辑于 2022-6-20 15:49

vue-cli 官方没有直接提供 api 来打包,一般大家也不会遇到需要用调用 api 来打包的场景,使用 vue-cli 提供的命令基本可以满足所有场景。那么如果需要使用 api 来批量打包该如何做呢?

我们先来了解下 vue-cli 自身是如何打包的。

先找到执行打包命令的入口文件。

https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/package.json

vue-cli-service.js 代码比较简单,整个打包过程可以概括为:初始化了一个 Service 类,然后直接执行实例的 run 方法就完成了整个打包动作。那么如果我们要自己打包,理论上也按这个流程就可以完成。

vue-cli-service 源码核心代码如下:

const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
// 省略初始 cli 参数
service.run(command, args, rawArgv).catch(err => {
  error(err)
  process.exit(1)
})

接下来用一个例子来测试上面的方法是否可行。

使用 vue-cli 初始化一个项目。

vue create mybuild

这里我们希望通过调用非命令的方式,循环将 components 下的 vue 文件打包为三个库(--target=lib)。

新建一个打包文件 build.js,打包代码参考 vue-cli-service.js 的流程。

const path = require("path");
const fs = require("fs");
const Service = require("@vue/cli-service/lib/Service");
const { error } = require("@vue/cli-shared-utils");

const service = new Service(path.resolve(__dirname, "../"));

function pack(file, dest, buildArgs = ["--name", "index"]) {
    return new Promise((resolve, reject) => {
        const rawArgv = ["build", "--target", "lib", "--dest", dest, ...buildArgs, file];
        const args = require("minimist")(rawArgv, {
            boolean: [
                // build
                "modern",
                "report",
                "report-json",
                "inline-vue",
                "watch",
                // serve
                "open",
                "copy",
                "https",
                // inspect
                "verbose"
            ]
        });
        const command = args._[0];

        service
            .run(command, args, rawArgv)
            .then(() => {
                resolve();
            })
            .catch((err) => {
                error(err);
                reject(err);
            });
    });
}

Service 初始化需要传入项目根目录,因为一些打包的配置文件一般都放在项目根目录(比如 eslint,babel等)。

上面的 rawArgv 对应的是在使用命令方式打包时的命令参数,比如 --target、--dest,我们使用的是 api 调用方式,因此直接可以将参数给列出来,这里我们要打包为 lib,因此要在 rawArgv 中增加 --target lib,其他一些配置可以根据自己的需求来添加。

接下来就是循环调用 pack 来打包 components 下的所有文件,并输出到 dist 目录下。

async function build() {
    const root = path.resolve(__dirname, "./src/components");
    const files = await fs.promises.readdir(root);

    for (let i = 0, j = files.length; i < j; i++) {
        const file = files[i];
        const entryFile = path.join(root, file);
        const fileInfo = path.parse(entryFile);
        const destDir = "./dist/" + fileInfo.name;
        await pack(entryFile, destDir);
    }
}

build();

执行

node build.js

打包后的文件如下图所示。

仔细分析 vue-cli-service 源码发现,打包的时候还可以自定义 vue.config.js 的路径,甚至文件名都可以随意指定,只需调整对应的环境变量即可。

process.env.VUE_CLI_SERVICE_CONFIG_PATH="配置文件路径"

比如我们在指定一个 components.config.js 用于打包 components 下的 vue 文件,配置方式和 vue.config.js 一样。


module.exports = {
    productionSourceMap: false,
    configureWebpack: {
        externals: {
            vue: {
                commonjs: "vue",
                commonjs2: "vue",
                root: "Vue",
                amd: "vue"
            }
        }
    }
};

在打包方法里面修改环境变量。

async function build() {
    process.env.VUE_CLI_SERVICE_CONFIG_PATH = "./components.config.js";

    const root = path.resolve(__dirname, "./src/components");
    const files = await fs.promises.readdir(root);

    for (let i = 0, j = files.length; i < j; i++) {
        const file = files[i];
        const entryFile = path.join(root, file);
        const fileInfo = path.parse(entryFile);
        const destDir = "./dist/" + fileInfo.name;
        await pack(entryFile, destDir);
    }
}

再次打包,会发现 source map 文件没有再生成,说明指定的配置文件生效了。

这样就不会和项目的 vue.config.js 产生冲突。

转载请注明出处。本文地址: https://www.qinshenxue.com/article/node-vue-cli-api.html
关注 & 咨询问题