介绍
- 本文使用的模板并不是通用模板~,是自己构建的模板。内部具体如何选择模板逻辑就没有了,仅仅相当于入门demo实现流程。
- 有兴趣学习脚手架的话yo还是不错的,走完本文逻辑可以试试看抽成自己项目,然后引用至公司~
- 加油!
- 参考资料:
- yeoman官网
- node官网文档选择
实现过程
-
创建文件夹(xxx/csdn),然后执行
npm init -y
(1)注意name必须为 generator-xxx ; (xxx为你自定义名字,这里我们以 generator-app来举例子)
-
再创建 (xxx/csdn/generators/app)(xxx/csdn/generators/app/index.js)
xxx/csdn/generators/app/index.js内填入以下内容const Generator = require('yeoman-generator'); module.exports = class extends Generator { method() { console.log('我执行了') } }
-
下载需要的依赖
(1)yeoman-generator
[ npm install --save yeoman-generator ]
(2)inquirer
[ npm i inquirer@8.0.0 ]
(3)ejs
[npm i ejs]
(4)yo
[ npm install -g yo ]
(5)generator-webapp
[ npm install -g generator-webapp ]
做完以上操作后你的界面结构应该是这样的(你的yeoman环境准备完毕)
-
接下来进入cmd小黑窗运行 npm link命令;(不懂 npm link 意思的可以去看看我这篇文章)
-
然后任意找一个地方建立一个文件夹(d:/xxxxxxxx/use),cmd进入小黑窗然后执行
yo app
命令(记住你一开始使用的 generator-app则运行这个命令,如果不是则yo xxx;(xxx为你自定义的名字))
如果执行完毕后你出现以下情况,则说明你成功了一半了~
-
创建
xxx/csdn/utils/readFilePath.js
文件,填入以下代码,代码介绍代码里有~
/**
* fileDisplay(url, callback)
* @param url: 你即将读取的文件夹路径
* @param callback: 回调函数
*/
// node fs模块
const fs = require('fs');
// node path模块
const path = require('path');
// 收集所有的文件路径
const arr = [];
let timer = null;
class firstUrl {
_url = '';
constructor() {
this.get()
}
get(url) {
if (this._url) return this._url
this._url = url
return url
}
}
const init = new firstUrl();
const fileDisplay = (url, cb) => {
init.get(url);
const filePath = path.resolve(url);
//根据文件路径读取文件,返回文件列表
fs.readdir(filePath, (err, files) => {
if (err) return console.error('Error:(spec)', err)
files.forEach((filename) => {
//获取当前文件的绝对路径
const filedir = path.join(filePath, filename);
// fs.stat(path)执行后,会将stats类的实例返回给其回调函数。
fs.stat(filedir, (eror, stats) => {
if (eror) return console.error('Error:(spec)', err);
// 是否是文件
const isFile = stats.isFile();
// 是否是文件夹
const isDir = stats.isDirectory();
if (isFile) {
// 这块我自己处理了多余的绝对路径,第一个 replace 是替换掉那个路径,第二个是所有满足\\的直接替换掉
arr.push(filedir.replace(init.get(), '').replace(/\\/img, '/'))
// 最后打印的就是完整的文件路径了
if (timer) clearTimeout(timer)
timer = setTimeout(() => cb && cb(arr), 200)
}
// 如果是文件夹
if (isDir) {
arr.push(filedir.replace(init.get(), '').replace(/\\/img, '/'))
fileDisplay(filedir, cb)
};
})
});
});
}
// 测试代码
// fileDisplay('./src', (arr) => {
// console.log(arr, '-=')
// })
// commonjs规范
module.exports = fileDisplay;
- 然后
xxx/csdn/generators/app/index.js
文件内容替换成以下内容。
const Generator = require('yeoman-generator');
const inquirer = require('inquirer');
const fileDisplay = require('../../utils/readFilePath.js')
const path = require('path')
const ejs = require('ejs')
const fs = require('fs')
const exec = require("child_process").exec;
const execNpmi = () => {
const cmd = 'npm i';
exec(cmd, {
maxBuffer: 1024 * 2000,
stdio: 'inherit',
shell: true
}, function (err, stdout, stderr) {
if (err) {
console.log(err);
Promise.reject(err);
} else if (stderr.lenght > 0) {
Promise.reject(new Error(stderr.toString()));
} else {
console.log(stdout);
Promise.resolve();
}
});
}
module.exports = class extends Generator {
method1() {
const _this = this;
inquirer.prompt([
/* 在这里配置您的问题(可以设置多个,它们将按顺序向用户提出) */
{
type: 'input',
name: 'name',
message: '请输入项目名称'
}
]).then(answers => {
// 回调,对用户输入的答案就行处理
// 目标目录
const destDir = process.cwd();
const tmpDir = path.join(__dirname, 'templates')
const ejsArr = ['.js', '.ts', '.vue', '.jsx', '.tsx', '.html', '.css', '.json']
fileDisplay(tmpDir, (arrList) => {
console.log(arrList, 'arrList')
// 克隆文件及文件夹
arrList.forEach(file => {
fs.stat(path.join(tmpDir, file), (eror, stats) => {
// 是否是文件
const isFile = stats.isFile();
// 是否是文件夹
const isDir = stats.isDirectory();
if (isFile) {
// 如果满足 ejs 的文件规则 则进入 ejs 模板模式
if (ejsArr.includes(path.extname(file).toLowerCase())) {
ejs.renderFile(path.join(tmpDir, file), answers, function (err, res) {
if (err) return console.log(err, '写入错误');
fs.writeFileSync(path.join(destDir, file), res);
});
} else {
// 不满足则直接读取文件并进行拷贝
fs.readFile(path.join(tmpDir, file), 'utf8', function (err, info) {
if (err) return console.log(err)
fs.writeFileSync(path.join(destDir, file), info);
})
}
}
// 如果是文件夹
if (isDir) {
fs.mkdirSync(path.join(destDir, file));
};
})
});
// 执行命令行
execNpmi();
})
});
}
};
-
然后创建模板文件夹
xxx/csdn/generators/app/templates
。里面内容则为你需要的模板。 -
如果你没用模板可以用用我的小模板【注意要切换分支,使用template分支】
-
最终去到(d:/xxxxxxxx/use)进入小黑框执行 yo app;下图为最终输出结果(因为会下载依赖会导致界面黑屏卡顿,但是你会看到新增加node_modules还在新增文件,这个就说明是没问题的,需等待一会儿)
最终说明一下ejs语法
- 模板文件更改name为ejs语法就行了(<%= name %>);这个name是我们自己在控制台中输入的值,我们给它定义的名称就为name。所以说这里取值为name。
- 当你的模板文件中有ejs语法的时候需要这样写(<%%= xxxxxxx %>)表示<%%= xxxxxxx %>编译为<%= xxxxxxx %>