vue create 初步解析以及定制化修改

vue

初步解析vue create流程以及定制化修改脚手架

版本说明

$ 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 初步解析以及定制化修改 的全部内容, 来源链接: utcz.com/z/375753.html

回到顶部