『手撕Vue-CLI』编译模板『上』

2024-05-27 07:46:14 浏览数 (4)

前言

经『手撕Vue-CLI』完善提示信息后,nue-cli 的 create 指令已经实现了基本的功能,但是除了基本功能外,还有一些功能需要完善,比如模板的编译。

编译模板

为什么要起这么一篇文章来单独拆解编译模板这个功能呢?接下来的内容一起带着这个疑问来看。

为什么要编译模板

编译模板编译模板,利用模板就代表着有些内容咱们是不确定的,需要在运行时才能确定的,比如利用 create 指令创建项目时,项目名称、项目描述、作者等信息都是不确定的,需要在运行时才能确定的。

这些信息需要用户提供才能知晓,所以需要提前准备好模板,然后在运行时根据用户提供的信息来替换模板中的变量。

在之前的文章里,已经对 vue-simple-template 模板进行了完善。尚待完善的是 vue-advanced-template,这是一个需要编译后才能使用的模板。

下载 vue-advanced-template

居然要完成这个模板的编译,先下载下来,利用自己编写的 nue-cli create 进行下载:

代码语言:shell复制
nue-cli create example

在我下载过程中,发现 GitHub 对应的这个模板我没有发布版本号,我就去发布了一个 v1.0.0,如果有直接观看这篇文章不懂这个如何创建的,可以去看看我之前所发布的文章即可。

发布好了之后,在终端执行上面我给出的命令,进行拉取下载需要编译的模板项目如下:

这样咱们需要的项目就已经有了,这个时候就可以先将部分代码给注释掉了,因为我不想每次测试都反复去拉取,我直接将地址写死在代码里,这样就不用每次都去拉取了。

注释掉的代码如下:

在定义一个 sourcePath 变量,将模板的路径写死在这里:

代码语言:javascript复制
const sourcePath = `C:\Users\BNTang\.nue-template\vue-advanced-template`;

上面的地址你自己根据实际情况来更改为你自己的地址即可,这样就不用每次都去拉取了。

编译模板

模板下载下来了,先打卡模板目录中的 ask.js 文件,这个文件是用来获取用户输入的信息的,这个文件的内容如下:

代码语言:javascript复制
module.exports = [
    {
        type: 'input',
        name: 'name',
        message: 'project-name?',
    },
    {
        type: 'confirm',
        name: 'private',
        message: 'ths resgistery is private?',
    },
    {
        type: 'input',
        name: 'author',
        message: 'author?',
    },
    {
        type: 'input',
        name: 'description',
        message: 'description?',
    }
]

暴露出去了一个数组,数组中包含了一些对象,每个对象都是一个问题,这个问题是用来获取用户输入的信息的。

看了这个文件,再看看 package.json 文件,在这个文件中有几个信息我是利用 <%=name%> 表示一个变量,它会在渲染时被替换为具体的值。

经过我如上这么一番介绍之后你要知识,需要编译的模板已经下载来了,模板目录中有两个比较核心的文件,分别是 ask.jspackage.json

ask.js 文件是用来获取用户输入的信息的,package.json 文件是用来渲染的,这两个文件是比较核心的文件,也是完成编译的关键。

接下来就是改造代码时刻,在之前的代码中,我们是直接将模板进行拷贝到指定路径中,现在我们需要将模板进行编译,将用户输入的信息替换到模板中。

所以需要根据当前模板下是否有 ask.js 文件来判断是否需要编译,如果有这个文件,就需要编译,如果没有这个文件,就不需要编译。

这里得要利用到 fs 模块,通过 fs 模块来判断是否有这个文件,如果有这个文件,就需要编译,如果没有这个文件,就不需要编译。

先导入 fs 模块:

代码语言:javascript复制
const fs = require('fs');

然后在 create 方法中,根据是否有 ask.js 文件来判断是否需要编译:

代码语言:javascript复制
const askPath = path.join(sourcePath, 'ask.js');
if (!fs.existsSync(askPath)) {
    await waitLoading('copying template...', ncp)(sourcePath, destPath);
} else {
}

这样就可以根据是否有 ask.js 文件来判断是否需要编译了,接下来就是编译的逻辑了。

编译逻辑

编译逻辑就是将用户输入的信息替换到模板中,这里需要用到 Metalsmith 这个库,这个库的作用就是将用户输入的信息替换到模板中,它就有这个能力。

官网我就不贴出来大家自行去 npm 官网搜索即可,这里直接安装 Metalsmith:

代码语言:shell复制
npm install metalsmith --save

安装好了之后,导入 Metalsmith:

代码语言:javascript复制
const Metalsmith = require('metalsmith');

然后在 else 代码块中,编写编译逻辑:

代码语言:javascript复制
// 处理用户输入
await new Promise((resolve, reject) => {
    // 处理用户输入
    Metalsmith(__dirname)
        // 配置源目录
        .source(sourcePath)
        // 配置目标目录
        .destination(destPath)
        // 注册一个插件
        .use(async (files, metal, done) => {
            done();
        })
        .use(async (files, metal, done) => {
            done();
        })
        .build((err) => {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
});
  • Metalsmith(__dirname) 这个方法是用来创建一个 Metalsmith 实例的,这个实例中包含了一些方法,比如 source、destination、use、build 等方法。
  • .source(sourcePath) 这个方法是用来配置源目录的,这里就是我们的模板目录。
  • .destination(destPath) 这个方法是用来配置目标目录的,这里就是我们的项目目录。

为什么我这里写了两个 .use 方法呢?因为 Metalsmith 是一个流式处理的库,它是通过 .use 方法来注册插件的,这里我注册了两个插件,第一个插件是用来处理用户输入的,第二个插件是用来处理模板的。

本章先到这里编译内容有点多我在分一个文章来写。

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

0 人点赞