大前端 — Yeoman 的 简单学习
经常会有人问我,前端的脚手架到底是什么东西?我一般也只能泛泛而谈,把对方拉到比我低的水平,然后一本正经的编点东西....1、脚手架是一种约定和规范相同的文件组织结构相同的开发范式相同的模块依赖相同的工具配置相同的基础代码然后脚手架 将这些 重复性的东西全部都集成起来,减少这样无意义的操作就像在 flutter new project 中,自动生成的 文件目录,文件结构,就是脚手架的一种,而 vue
经常会有人问我,前端的脚手架到底是什么东西?我一般也只能泛泛而谈,把对方拉到比我低的水平,然后一本正经的编点东西....
1、脚手架是一种约定和规范
- 相同的文件组织结构
- 相同的开发范式
- 相同的模块依赖
- 相同的工具配置
- 相同的基础代码
- 然后脚手架 将这些 重复性的东西全部都集成起来,减少这样无意义的操作
就像在 flutter new project 中,自动生成的 文件目录,文件结构,就是脚手架的一种,而 vue-cli ,react-create-app 也是脚手架的一种
2. 安装yeoman
- 安装 yeoman
sudo yarn global add yo
- 安装 generator-node
sudo yarn global add generator-node
创建一个目录之后输入命令
yo node
接下来就是等了.....
3. 使用yeoman
只想给已有的项目增加 部分功能,生成自己的 cli
yo node:cli
sudo npm link
my-modlue --help
可以发现 my-module 这个 命令 被注册进了命令之中
需要注意的是,在 mac ,使用 yarn link 是会出现问题的 相关 issue
3、创建自己的generator,用于自动生成 定义好的文件
mkdir generator-simple
cd generator-simple
yarn init --yes
yarn add yeoman-generator // 所有 generator 的基类
创建 generators/app/index.js
// 作为 generator 的 核心入口
// 需要导入一个继承自 Yeoman Generator 的一些生命周期方法
// Yeoman Generator 在工作的时候回自动调用 再次类型中定义的 一些生命周期方法
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
// Yeoman 自动在生成文件阶段调用这个方法
writing() {
// 父类的 fs 模块
this.fs.write(
// 文件目录
this.destinationPath('temp.txt'),
// 文件内容
Math.random().toString()
)
}
}
可能会报这个错,Unexpected end of JSON input while parsing near '...LAigpnGt0Bi7uIZXmMhXs' ,执行
npm cache clean --force
cd ../
mkdir simple
yo simple // 就能看到 生成了自己想要的文件
使用模板
在 generators/app 里创建 templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
</head>
<body>
<% if (success) { %>
<div>Hello generator</div>
<% } %>
</body>
</html>
修改 index.js 中的代码
// 作为 generator 的 核心入口
// 需要导入一个继承自 Yeoman Generator 的一些生命周期方法
// Yeoman Generator 在工作的时候回自动调用 再次类型中定义的 一些生命周期方法
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
// Yeoman 自动在生成文件阶段调用这个方法
writing() {
// 通过模板方法 协议文件到目标目录
const tmpl = this.templatePath('index.html')
const output = this.destinationPath('index.html')
const conext = { title: 'generator', success: true }
this.fs.copyTpl(tmpl, output, conext)
}
}
然后执行 sudo npm unlink
sudo npm link
在 simple 文件夹中执行
yo simple
使用 用户输入的值
// 作为 generator 的 核心入口
// 需要导入一个继承自 Yeoman Generator 的一些生命周期方法
// Yeoman Generator 在工作的时候回自动调用 再次类型中定义的 一些生命周期方法
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
promiting() {
return this.prompt([
{
type: 'input', // 用户输入的方式
name: 'title',
message: 'your project title', // 提示
default: this.appname, // appname 为 为项目生成目录的名称,作为 这个问题的默认值
}
]).then(answers => {
this.answers = answers
})
}
// Yeoman 自动在生成文件阶段调用这个方法
writing() {
// 通过模板方法 协议文件到目标目录
// 这里可以定义一个 数组,然后 通过遍历的方式,一次性生成一大堆文件
const tmpl = this.templatePath('index.html')
const output = this.destinationPath('index.html')
const conext = { title: this.answers.title, success: true }
this.fs.copyTpl(tmpl, output, conext)
}
}
4、发布
echo node_modules > .gitignore
git init
git add .
git commit -m "XXX"
创建 github 仓库
git remote add origin xxxxxx
git push -u origin master // 上传 到 github
yarn publish // 发布(国内一般都是 使用 了淘宝的镜像,而这个镜像 是只读的,所以发布不上去,就需要改回去)
yarn publish --registry https://registry.yarnpkg.com // 手动推送 到 yarn 的地址上,这个是和 npm 库保持同步的
5、脚手架的原理—自己实现一个脚手架
mkdir scaffold
yarn init --yes
修改package.json,增加 bin 属性
{
"name": "scaffold",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"bin": "cli.js"
}
在根目录下创建一个 cli.js
#!/usr/bin/env node
// 设置环境变量的 文件头
console.log('cli start')
sudo npm link
scaffold // 执行 脚手架命令
开始实现脚手架的具体工作流程
- 通过命令行 询问用户问题
- 根据用户输入的内容,生成文件
yarn add inquirer // 在命令行发起询问
yarn add ejs // 模板引擎
创建templates 文件夹,里面加入 两个文件 index.html 和 index.css
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= name %></title></title>
</head>
<body>
</body>
</html>
.<%= name %> {
color: red;
}
修改 cli.js 里的内容
#!/usr/bin/env node
// 设置环境变量的 文件头
// 如果是 macOS 系统下,还得修改这个文件的权限为 755
const inquirer = require('inquirer')
const path = require('path')
const fs = require('fs')
const ejs = require('ejs')
inquirer.prompt([
{
type: 'input',
name: 'name',
message: '文件名称'
}
]).then(answers => {
// console.log(answers)
// 根据用户的输入结果生成文件
// 模板目录
const tmplDir = path.join(__dirname, 'templates')
// 目标目录
const destDir = process.cwd()
// 读取模板文件,并输出
fs.readdir(tmplDir, (err, files) => {
if (err) throw err
files.forEach(file => {
ejs.renderFile(path.join(tmplDir, file), answers, (err, result) => {
if (err) throw err
fs.writeFileSync(path.join(destDir, file), result)
})
})
})
})
然后到 一个新的 文件夹,
执行:
scaffold
- 所以脚手架 的原理到现在也比较清晰了
- 手动创建模板,或者需要的文件以及对应的配置
- 将 对应的命令注入到 bin 环境变量中
- 通过获取用户的输入,将输入 通过 模板语法注入到 之前的模板文件中
- 生成新的文件
更多推荐
所有评论(0)