Vue CLI 的秘密——打造属于你的前端脚手架工具
2024-02-04 13:30:30
前言
Vue CLI 是一个用于快速构建 Vue.js 应用程序的命令行界面工具,它可以帮助我们快速搭建一个 Vue.js 项目,并提供了许多有用的功能,如:项目初始化、代码生成、依赖管理、打包构建等。
本文将带领大家深入 Vue CLI 源码,手把手地搭建一个前端脚手架工具,在实践中学习 Vue CLI 的工作原理和前端构建工具的构建过程,同时加深对 Vue.js 项目开发的理解。
剖析 Vue CLI 源码
为了更好地理解 Vue CLI 的工作原理,我们首先需要了解它的源码结构。
源码目录结构
vue-cli/
├── bin # Vue CLI 的入口文件
├── command # 命令行命令
├── generator # 脚手架生成器
├── package.json # 包信息文件
├── prompts # 交互式命令行提示
├── shared # 共享代码
├── templates # 脚手架模板
└── utils # 工具函数
关键文件解析
1. 入口文件
入口文件位于 bin
目录下,其中最重要的是 vue
文件,它是 Vue CLI 的主程序,负责解析命令行参数,并根据不同的命令执行相应的任务。
2. 命令行命令
命令行命令位于 command
目录下,每个命令对应一个 .js
文件,比如 create.js
对应 vue create
命令。这些命令文件负责处理命令行参数,并调用相应的生成器或执行相应的任务。
3. 脚手架生成器
脚手架生成器位于 generator
目录下,每个生成器对应一个 .js
文件,比如 project.js
对应项目生成器。这些生成器负责创建项目文件,并安装必要的依赖包。
4. 共享代码
共享代码位于 shared
目录下,其中包含一些公共函数和类,比如 logger.js
中的日志记录函数,webpack.js
中的 Webpack 配置函数等。
5. 脚手架模板
脚手架模板位于 templates
目录下,其中包含各种项目模板,比如 default
模板用于创建一个默认的 Vue.js 项目,pwa
模板用于创建一个 PWA 项目。
6. 工具函数
工具函数位于 utils
目录下,其中包含一些常用的工具函数,比如 copyFile.js
中的复制文件函数,execa.js
中的执行命令函数等。
搭建前端脚手架工具
在了解了 Vue CLI 的源码结构和关键文件之后,我们就可以开始动手搭建自己的前端脚手架工具了。
1. 创建项目
首先,我们需要创建一个新的项目,并安装必要的依赖包:
mkdir my-cli
cd my-cli
npm init -y
npm install vue vue-cli-service -D
2. 创建入口文件
接下来,我们需要创建入口文件 bin/my-cli.js
:
#!/usr/bin/env node
const program = require('commander');
program
.version('0.0.1')
.command('create <project-name>')
.description('Create a new Vue.js project')
.action(require('../command/create'));
program.parse(process.argv);
3. 创建命令行命令
然后,我们需要创建命令行命令 command/create.js
:
const Generator = require('../generator/project');
module.exports = {
command: 'create <project-name>',
description: 'Create a new Vue.js project',
action: (projectName) => {
new Generator(projectName).generate();
},
};
4. 创建脚手架生成器
接着,我们需要创建脚手架生成器 generator/project.js
:
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const ora = require('ora');
class Generator {
constructor(projectName) {
this.projectName = projectName;
}
generate() {
const spinner = ora('Creating project...').start();
const projectPath = path.join(process.cwd(), this.projectName);
fs.mkdirSync(projectPath);
// 创建项目文件
fs.writeFileSync(path.join(projectPath, 'package.json'), JSON.stringify({
name: this.projectName,
version: '1.0.0',
scripts: {
dev: 'vue-cli-service serve',
build: 'vue-cli-service build',
},
dependencies: {
vue: '^2.6.12',
},
devDependencies: {
'@vue/cli-plugin-babel': '^4.5.12',
'@vue/cli-plugin-eslint': '^4.5.12',
'@vue/cli-plugin-router': '^4.5.12',
'@vue/cli-plugin-vuex': '^4.5.12',
'vue-cli-service': '^4.5.12',
},
}, null, 2));
fs.writeFileSync(path.join(projectPath, 'src/main.js'), `import Vue from 'vue';\nimport App from './App.vue';\nnew Vue({el: '#app', render: h => h(App);});`);
fs.writeFileSync(path.join(projectPath, 'src/App.vue'), `<template>\n <div id="app">\n <h1>{{ msg }}</h1>\n </div>\n</template>\n\n<script>\nexport default {\n data() {\n return {\n msg: 'Hello Vue.js!'