版本说明

$ vue --version
@vue/cli 4.5.9
$ node --version
v14.0.0
$ npm --version
7.6.1

源码位置-mac

/usr/local/lib/node_modules/@vue/cli

流程说明

  1. 根据package.json中的bin可以知道入口文件在bin/vue.js
  2. vue.js中找到create <app-name>的命令设定,在action钩子中调用了lib/create

create.js

  1. 获取项目绝对路径
  2. 判断项目文件夹是否存在
  3. 创建文件夹
  4. 调用lib/Creator.js

Creator.js

Creator.create()

  1. 根据创建项目时的选择项配置preset插件组

  2. 深度拷贝preset

  3. 配置preset中的默认插件的配置项:@vue/cli-service@vue/cli-plugin-router@vue/cli-plugin-typescript@vue/cli-plugin-vuex

  4. 获取包管理器:yarn/npm/pnpm

  5. 开始创建项目,获取vue-cli版本

  6. 根据preset中的插件配置生成package.json文件

  7. pnpm生成.npmrc文件,为yarn生成.yarnrc

  8. 为项目添加git配置:git init

  9. 安装CLI插件:生成指定格式的文件目录

    await generator.generate({
    extractConfigFiles: preset.useConfigFiles,
    });
  10. 唤醒插件

  11. 安装配置额外的依赖

  12. running completion hooks

  13. 生成README.md

  14. 配置git的状态,为测试配置Git

  15. 完成

自定义修改脚手架程序

公司内项目所使用的插件等配置基本相似,在项目开发过程中也有很多提高开发效率的做法,这些可以在脚手架的程序流程中自定义

  1. 摆脱复制-粘贴的重复工作,同时避免复制-粘贴丢失导致的可以不用debug的bug
  2. 提高项目开发效率,统一项目开发风格

生成vue.config.js-仿生成README.md

  1. generateVueConfig.js
// 生成README.md:lib/util/generateReademe.js
// 生成vue.config.js:lib/util/generateVueConfig.js,我另有其他配置项,需要根据配置生成vue.config.js
module.exports = function generateVueConfig(plugins) {
const iconSvg = plugins['svg-sprite-loader'] ? `chainWebpack: config => {
// svg rule loader
const svgRule = config.module.rule('svg') // 找到svg-loader
svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
svgRule // 添加svg新的loader处理
.test(/\.svg$/)
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
}) // 修改images loader 添加svg处理
const imagesRule = config.module.rule('images')
imagesRule.exclude.add(resolve('src/icon/svg'))
config.module
.rule('images')
.test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
}` : '' return `const path = require('path') function resolve(dir) {
return path.join(__dirname, './', dir)
}
module.exports = {
publicPath: './',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
},
productionSourceMap: false,
${iconSvg}
}`
}
  1. 修改create流程-Creator.js

    // 自定义生成vue.config.js,写入多次使用的配置,比如跨域配置,可以直接写,也可以将内容写在另一个js文件中并引入
    if (!generator.files['vue.config.js']) {
    log()
    log('⚙\u{fe0f} Generating vue.config.js...')
    await writeFileTree(context, {
    'vue.config.js': generateVueConfig(preset.otherPlugins),
    })
    }

配置并引入自定义npm包-仿配置@vue/cli-xxx包

在开发中,有一些包总会被引入,比如axios,加密的包,UI框架包等,可以在vue create前期选择时将其加入,来生成代码。

引入@vue/cli-xxx包流程:

  1. create.js中,根据new Creator来进入整体流程,初始化Creator时,传入了初始包列表,以下仅摘要了重要代码
// create.js
const { getPromptModules } = require('./util/createTools')
const creator = new Creator(name, targetDir, getPromptModules())
// getPromptModules()
exports.getPromptModules = () => {
return [
'vueVersion',
'babel',
'typescript',
'pwa',
'router',
'vuex',
'cssPreprocessors',
'linter',
'unit',
'e2e'
].map(file => require(`../promptModules/${file}`))
}
  1. 初始化Creator时,调用了PromptModuleAPI引入了相关包,调用了相关包的配置命令lib/promptModules/xxx
// Creator.js
constructor(name, context, promptModules) {
const promptAPI = new PromptModuleAPI(this);
promptModules.forEach((m) => m(promptAPI));
// 以上命令执行后,在shell界面中会显示每个相关包的配置命令,此时使用者进行选择或输入
}
  1. 在Creator.create()方法中,根据preset为每一个包配置了配置项,存储在preset.plugins
// Creator.js-create()方法,以下仅举例
preset.plugins["@vue/cli-service"] = Object.assign(
{
projectName: name,
},
preset
); if (cliOptions.bare) {
preset.plugins["@vue/cli-service"].bare = true;
} // legacy support for router
if (preset.router) {
preset.plugins["@vue/cli-plugin-router"] = {}; if (preset.routerHistoryMode) {
preset.plugins["@vue/cli-plugin-router"].historyMode = true;
}
}

仿制以上流程即可导入自己想在初始化过程中导入的包,比如axios等,为避免冲突,全部为另开发的代码,以下以axios以及可选择式的UI框架来举例

  1. createOtherTools.js -仿制getPromptModules函数,配置自定义包列表,并添加到初始化Creator中
// lib/util/createOtherTools.js  otherModules文件夹存储自定义包的相关命令行
exports.getOtherPromptModules = () => {
return [
'axios',
'uiStruct'
].map(file => require(`../otherModules/${file}`))
}
// create.js
const { getPromptModules } = require('./util/createTools')
const { getOtherPromptModules } = require('./util/createOtherTools')
const creator = new Creator(name, targetDir, getPromptModules(), getOtherPromptModules())
  1. 导入相关包的命令行配置,将自定义包的配置存储在options.otherPlugins
// Creator.js
constructor(name, context, promptModules, otherPromptModules) {
const promptAPI = new PromptModuleAPI(this);
promptModules.forEach((m) => m(promptAPI));
otherPromptModules.forEach((m) => m(promptAPI));
// 以上命令执行后,在shell界面中会显示每个相关包的配置命令,此时使用者进行选择或输入
}
// 新建 otherModules 文件夹
// otherModules/axios.js
module.exports = cli => {
cli.injectFeature({
name: 'Axios', // 显示在vue create命令后的选择项里的名字
value: 'axios', // 相对应的value值
description: 'Promise based HTTP client for the browser and node.js', // 介绍
link: 'https://github.com/mzabriskie/axios', // 相关链接
checked: true // 显示在vue create命令后的选择项里,是否默认选中
}) cli.onPromptComplete((answers, options) => {
if (answers.features.includes('axios')) { // includes(value)是否包含上面定义的value值
options.otherPlugins['axios'] = {} // 在此指定相对应的报名
}
})
}
// otherModules/uiStruct.js
module.exports = cli => {
cli.injectFeature({
name: 'Choose UI Struct', // 显示在vue create命令后的选择项里的名字
value: 'ui-struct', // 相对应的value值
description: 'Choose a struct of UI that you want to use with the project' // 介绍
}) cli.injectPrompt({
name: 'uiStruct',
when: answers => answers.features.includes('ui-struct'), // 判断是否选择
message: 'Choose a struct of UI that you want to use with the project', // 描述
type: 'list', // 选择类shell命令
choices: [
{
name: 'ant-design-vue', // 选项名
value: 'ant-design-vue' // 选项相对应的包名
},
{
name: 'element-ui',
value: 'element-ui'
}
],
default: 'element-ui' // 默认选项
}) cli.onPromptComplete((answers, options) => {
if (answers.uiStruct) {
options.otherPlugins[answers.uiStruct] = {} // answers.uiStruct存储了包名
}
})
}
  1. 将自定义包的引入加入到流程中,在生成package.json之前引入
// Creator.js - create()函数
if (preset.otherPlugins) {
Object.keys(preset.otherPlugins).forEach((dep) => {
let { version } = preset.otherPlugins[dep];
pkg.dependencies[dep] = version ? version : "latest";
});
}

vue create 初步解析以及定制化修改的更多相关文章

  1. 定制化Azure站点Java运行环境(4)

    定制化使用您自己的Tomcat版本和JDK环境 在上面章节中,介绍了如何通过web.config,定制默认的Azure website的Java运行环境,默认情况下,Azure站点的Tomcat是7. ...

  2. 定制化Azure站点Java运行环境(3)

    定制化Azure Website提供的默认的Tomcat和JDK环境 在我们之前的测试中,如果你访问你的WEB站点URL时不加任何上下文,实际上你看到的web界面是系统自带的测试页面index.jsp ...

  3. jquery-ui-datepicker定制化,汉化,因手机布局美观化源码修改

    感谢浏览,欢迎交流=.= 公司微信网页需要使用日历控件,想到jquery-mobile,但是css影响页面布局,放弃后使用jquery-ui-datepicker. 话不多说,进入正题: 1.jque ...

  4. 【vuejs深入二】vue源码解析之一,基础源码结构和htmlParse解析器

    写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. vuejs是一个优秀的前端mvvm框架,它的易用性和渐进式的理念可以使每一个前端开发人员感到舒服,感到easy.它内 ...

  5. Oceanus:美团HTTP流量定制化路由的实践

    背景简述 Oceanus是美团基础架构部研发的统一HTTP服务治理框架,基于Nginx和ngx_lua扩展,主要提供服务注册与发现.动态负载均衡.可视化管理.定制化路由.安全反扒.session ID ...

  6. AI应用开发实战 - 定制化视觉服务的使用

    AI应用开发实战 - 定制化视觉服务的使用 本篇教程的目标是学会使用定制化视觉服务,并能在UWP应用中集成定制化视觉服务模型. 前一篇:AI应用开发实战 - 手写识别应用入门 建议和反馈,请发送到 h ...

  7. EpiiServer 更快捷更方便的php+nginx环境定制化方案

    EpiiServer是什么 更快捷更方便的php+nginx多应用部署环境. github仓库首页 https://github.com/epaii/epii-server gitee仓库 https ...

  8. unittest加载测试用例名称必须以test开头,是否可以定制化

    ​ 前几天,在一个群里,一个人问了,这样一个问题.说他面试遇到一个面试官,问他,为啥unittest的测试用例要用test 开头,能不能定制化.他不知道为啥. 看到这个题目,我回答当然可以了,可以用l ...

  9. ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”

    DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...

随机推荐

  1. flask分页功能:基于flask-sqlalchemy和jinja2

    先看源码: @app.route('/movie', methods=['GET', 'POST']) @app.route('/home', methods=['GET', 'POST']) @ap ...

  2. day06 视图层

    day06 视图层 今日内容 视图层 小白必会三板斧 JsonResponse form表单发送文件 FBV与CBV FBV基于函数的视图 CBV基于类的视图 模板层 模板语法的传值 模板语法之过滤器 ...

  3. Zookeeper【概述、安装、原理、使用】

    目录 第1章 Zookeeper入门 1.1 概述 1.2 特点 1.3 数据结构 1.4应用场景 第2章 Zookeep安装 2.1 下载地址 2.2 本地模式安装 1. 安装前准备 2. 配置修改 ...

  4. 容器之分类与各种测试(四)——unordered_set和unordered_map

    关于set和map的区别前面已经说过,这里仅是用hashtable将其实现,所以不做过多说明,直接看程序 unordered_set #include<stdexcept> #includ ...

  5. Git的使用-一个分支完全替换另一个分支

    之前公司git分支混乱,今天花时间整理了一下,在合并分支的时候遇到一个问题: 一个很久没有拉取远程代码的分支与master分支合并时,出现冲突之外,还会丢失文件,很头疼,然后找到了下面的方法,可以直接 ...

  6. Mysql多字段模糊查询

    MySQL同一字段多值模糊查询 一. 同一字段多值模糊查询,使用多个or进行链接,效率不高,但没有更好的解决方案.(有看到CHARINDEX 关键字,可查询结果并不是模糊,举个栗子 例如SELECT ...

  7. t01_docker安装TiDB

    Docker环境安装TiDB,在官方说明的基础上补充了几个细节,安装记录如下 个人环境-vbox上安装centos7.4系统 CPU:12核24线程,分配给虚拟机12线程 MEM: 48G,分配给虚拟 ...

  8. 漏洞扫描器-AWVS

    目录 介绍 漏洞扫描 网络爬虫==漏洞分析.验证 主机发现 子域名探测 SQL注入 HTTP头编辑 HTTP监听 介绍 AWVS为Acunetix Web Vulnarability Scanner的 ...

  9. MicroK8S 安装 修改IP 设置镜像加速 升级 卸载等

    系统要求: Ubuntu 20.04 LTS, 18.04 LTS or 16.04 LTS或其他支持snapd的操作系统 内存:4G+ 硬盘:20G+ 官方文档 安装microk8s sudo sn ...

  10. Mysql配置 主从同步

    目录 一.准备 二.操作 主数据库操作 从服务器操作 一.准备 1.主从数据库版本最好一致 2.主从数据库内数据保持一致,若不一致,可将从库中所有数据删除,并将主库全部数据导入进去 主数据库:182. ...