前言
1.什么是脚手架,为什么要学习脚手架开发?
前端脚手架是一种用于快速搭建前端项目基础结构的工具,通过命令行交互的方式帮助开发者减少重复性工作,提高开发效率,掌握前端工程化思想
2.常见的脚手架(@vue/cli、@angular/cli、create-react-app、vite…)
全局安装和命令执行的原理
在开始介绍项目之前,我先说说为什么全局安装后就能在命令行里直接用 ying-cli 这个命令。
原来是这样的:
-
当我们执行
npm install -g ying-cli的时候,npm 会把这个包安装到全局目录下- Windows 系统一般在
C:\\Users\\用户名\\AppData\\Roaming\\npm\\node_modules - Mac/Linux 一般在
/usr/local/lib/node_modules
- Windows 系统一般在
-
安装的时候 npm 会看我们 package.json 里的
bin字段:{ "bin": { "ying-cli": "./bin/cli.js" } }这个配置告诉 npm:“嘿,帮我在全局目录创建一个叫
ying-cli的命令,指向这个 JS 文件” -
npm 就会在全局目录的 bin 文件夹里创建一个软链接:
- Windows 会创建
ying-cli.cmd - Mac/Linux 会创建一个叫
ying-cli的软链接
- Windows 会创建
-
这些目录都在系统的环境变量 PATH 里,所以当我们在终端输入
ying-cli的时候,系统就能找到并执行对应的 JS 文件了 -
在 cli.js 的开头,有一行很重要的代码:
#!/usr/bin/env node这行代码告诉系统用 node 来执行这个文件,这个注释必须放在第一行,专业点叫 “Shebang(Hashbang)“
脚手架是怎么工作的?
在开始介绍我的项目之前,先来聊聊脚手架的基本原理。它主要做这么几件事:
-
命令解析:当你在终端输入命令时(比如
ying-cli create my-project),脚手架会解析这个命令和参数,判断你想干什么。 -
项目模板:脚手架会在某个地方(可能是本地,也可能是远程)存储一些项目模板。就像你装修房子用的样板间,里面已经帮你把基础设施都配好了。
-
文件操作:根据你的选择,脚手架会把模板复制到你指定的位置,并且可能会根据你的配置修改一些文件内容。
-
依赖安装:最后,它会帮你装好所有需要的依赖,这样你就可以直接开始写代码了。
简单来说,脚手架就是一个自动化工具,帮你把那些重复的准备工作一键搞定!
为什么要自己造轮子?
已经有 Vue CLI、Create React App 这些成熟的工具了,为什么还要自己造轮子呢?
主要有这几个原因:
- 现有的脚手架可能不完全符合我们团队的开发习惯
- 想要更灵活的定制能力
- 最重要的是…学习嘛,造轮子的过程其实就是学习的过程!
核心功能
Ying CLI 目前实现了这些功能:
- 🚀 快速创建项目:支持多种项目模板
- 📦 自动装依赖:省去手动 npm install 的步骤
- 🔄 强制更新:想覆盖就覆盖,就是这么任性
- 🌐 开发服务器:内置了一个静态文件服务器
- 🎨 交互体验:命令行界面很友好,菜鸟也能轻松上手
技术实现
1. 命令行工具开发
首先用 commander 来处理命令行操作:
import chalk from "chalk"; // 命令行美化工具
import { program } from "commander"; // 引入commander
// 设置命令行名称、使用方法、描述、版本
program.name(pkg.name).usage("<command> [options]").description(chalk.greenBright(pkg.description)).version(pkg.version);
// 定义 create 命令
program
.command("create [projectName]") // 配置命令的名字和参数
.description(chalk.greenBright("创建一个项目")) // 命令对应的描述
.option("-f, --force", chalk.greenBright("如果文件存在就强行覆盖"))
.action(create);
// 定义 server 命令
program
.command("server [directory]")
.description(chalk.greenBright(chalk.bold("启动本地静态文件服务器")))
.option("-p, --port <port>", `指定${chalk.yellowBright("端口号")}`, "8080")
.option("-o, --open", "自动打开浏览器", false)
.action((directory, options) => {
server(directory, {
port: parseInt(options.port),
open: options.open,
}).catch(() => process.exit(1));
});
2. 项目模板管理
目前功能已经实现,但是还没有模板
3. 开发服务器实现
用 Express 搭了个简单的静态服务器:
import express from "express";
import path from "path";
import chalk from "chalk";
import os from "os";
async function server(directory = ".", options = {}) {
const {
port = 8080,
host = "0.0.0.0",
open = false,
} = options;
const app = express();
const rootDir = path.resolve(process.cwd(), directory);
// 静态文件服务
app.use(express.static(rootDir));
return new Promise((resolve, reject) => {
try {
const portNumber = parseInt(port, 10);
const server = app.listen(portNumber, host, () => {
const localIP = getLocalIP();
const networkAddress = `http://${localIP}:${portNumber}`;
console.log(`${chalk.cyan("Network:")} ${chalk.cyan(networkAddress)}`);
if (open) {
import("open").then(module => module.default(localAddress));
}
resolve(server);
});
server.on("error", (err) => {
if (err.code === "EADDRINUSE") {
console.error(chalk.red(`Port ${portNumber} is already in use`));
console.error(chalk.yellow(`Try: ying-cli server -p ${portNumber + 1}`));
} else {
console.error(chalk.red("Server error:"), err.message);
}
reject(err);
});
} catch (err) {
console.error(chalk.red("Fatal error:"), err.message);
reject(err);
}
});
}
4. 用户交互优化
使用 inquirer 来实现命令行交互,让用户选择项目模板:
const inquirer = require('inquirer');
async function promptTemplate() {
const { template } = await inquirer.prompt([
{
type: 'list',
name: 'template',
message: '请选择项目模板:',
choices: [
{ name: 'Vue2 + TS + Vant (H5)', value: 'vue2-h5' },
{ name: 'Vue2 + TS + Vant (AppWeb)', value: 'vue2-appweb' }
]
}
]);
return template;
}
怎么用?
安装
# 全局安装
npm install -g ying-cli
# 或者用 yarn 也行
yarn global add ying-cli
创建项目
# 创建新项目
ying-cli create my-project
# 要是目录已经存在,可以强制覆盖
ying-cli create my-project -f
启动开发服务器
# 在当前目录启动服务器
ying-cli server
# 想指定端口和目录?没问题
ying-cli server ./dist -p 3000
# 懒得自己打开浏览器?加个 -o 参数就行
ying-cli server -o
项目结构
ying-cli/
├── bin/ # CLI 入口文件
├── src/ # 源代码
│ ├── config/ # 配置文件
│ └── scripts/ # 脚本文件
└── templates/ # 项目模板
用到的工具
- commander:处理命令行
- chalk:让命令行输出有点颜色看着舒服
- inquirer:处理用户输入,支持选择、确认等交互
- ora:添加好看的加载动画
- fs-extra:文件操作更方便
- express:搭建开发服务器
- open:自动打开浏览器
写在最后
这是我的第一个脚手架工具,虽然功能还比较简单,但是对于我个人来说还是挺有帮助的。通过这个项目,我也学到了不少关于 Node.js 和工程化的知识。