前言
经『手撕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
文件,这个文件是用来获取用户输入的信息的,这个文件的内容如下:
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.js
和 package.json
。
ask.js 文件是用来获取用户输入的信息的,package.json 文件是用来渲染的,这两个文件是比较核心的文件,也是完成编译的关键。
接下来就是改造代码时刻,在之前的代码中,我们是直接将模板进行拷贝到指定路径中,现在我们需要将模板进行编译,将用户输入的信息替换到模板中。
所以需要根据当前模板下是否有 ask.js
文件来判断是否需要编译,如果有这个文件,就需要编译,如果没有这个文件,就不需要编译。
这里得要利用到 fs 模块,通过 fs 模块来判断是否有这个文件,如果有这个文件,就需要编译,如果没有这个文件,就不需要编译。
先导入 fs 模块:
代码语言:javascript复制const fs = require('fs');
然后在 create
方法中,根据是否有 ask.js
文件来判断是否需要编译:
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
代码块中,编写编译逻辑:
// 处理用户输入
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腾讯技术创作特训营最新征文,快来和我瓜分大奖!