从package.json文件中可以看到"vue-cli-service": "bin/vue-cli-service.js"
目录结构
Service.js 指令、配置文件管理类 new Service(context)
constructor (context, { plugins, pkg, inlineOptions, useBuiltIn } = {}){
// ...
}
PluginAPI.js 指令api,new PluginAPI(id, service)
//service是Service.js导出的实例对象
constructor (id, service) {
this.id = id
this.service = service
}
// 在init方法中初始化PluginAPI的方法从这段代码中可以看出循环初始化PluginAPI的参数service都是同一个this
// 使用了单例模式,使多个PluginAPI实例的service指向同一个Service实例
this.plugins.forEach(({ id, apply }) => {
apply(new PluginAPI(id, this), this.projectOptions)
})
options.js 参数配置项
commands
// 指令目录这个目录下返回的都是一个函数function(api,options) api是PluginAPI实例,options是项目配置
module.exports = (api, options) =>{
//...
}
// 指令对应的webpack模式
module.exports.defaultModes = {
inspect: 'development'
}
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
this.modes = this.plugins.reduce((modes, { apply: { defaultModes }}) => {
return Object.assign(modes, defaultModes)
}, {})
build
help.js
inspect.js
serve.js
config 各种开发模式下需要配置的的插件
// 指令目录这个目录下返回的都是一个函数function(api,options) api是PluginAPI实例,options是项目配置
module.exports = (api, options) =>{
//...
}
app.js
base.js
css.js
dev.js
index-default.html
prod.js
terserOptions.js
使用npm进行调用时执行的代码
#!/usr/bin/env node
const semver = require('semver')
const { error } = require('@vue/cli-shared-utils')
const requiredVersion = require('../package.json').engines.node
if (!semver.satisfies(process.version, requiredVersion)) {
error(
`You are using Node ${process.version}, but vue-cli-service ` +
`requires Node ${requiredVersion}.\nPlease upgrade your Node version.`
)
process.exit(1)
}
const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
const rawArgv = process.argv.slice(2)
const args = require('minimist')(rawArgv, {
boolean: [
// build
'modern',
'report',
'report-json',
'watch',
// serve
'open',
'copy',
'https',
// inspect
'verbose'
]
})
const command = args._[0]
service.run(command, args, rawArgv).catch(err => {
error(err)
process.exit(1)
})
- 构造函数中加载指令和参数配置项信息
- 构造函数中
- 初始化环境变量
- 加载用户配置项
- 将用户配置项与默认选项合并
- 初始化指令,环境配置选项
- 处理合并后的chainWebpack链路配置与configureWebpack选项
init (mode = process.env.VUE_CLI_MODE) {
if (this.initialized) {
return
}
this.initialized = true
this.mode = mode
// load mode .env
if (mode) {
this.loadEnv(mode)
}
// load base .env
this.loadEnv()
// load user config
const userOptions = this.loadUserOptions()
this.projectOptions = defaultsDeep(userOptions, defaults())
debug('vue:project-config')(this.projectOptions)
// apply plugins.
this.plugins.forEach(({ id, apply }) => {
apply(new PluginAPI(id, this), this.projectOptions)
})
// apply webpack configs from project config file
if (this.projectOptions.chainWebpack) {
this.webpackChainFns.push(this.projectOptions.chainWebpack)
}
if (this.projectOptions.configureWebpack) {
this.webpackRawConfigFns.push(this.projectOptions.configureWebpack)
}
}
loadEnv (mode) {
const logger = debug('vue:env')
const basePath = path.resolve(this.context, `.env${mode ? `.${mode}` : ``}`)
const localPath = `${basePath}.local`
const load = path => {
try {
const env = dotenv.config({ path, debug: process.env.DEBUG })
dotenvExpand(env)
logger(path, env)
} catch (err) {
// only ignore error if file is not found
if (err.toString().indexOf('ENOENT') < 0) {
error(err)
}
}
}
load(localPath)
load(basePath)
// ...
}
process.env.NODE_ENV !== 'production'
vue cli是根据这个变量来做webpack优化操作的,// config/prod.js配置文件中的部分代码
if (process.env.NODE_ENV === 'production'){
//...
}
//获取用户配置文件代码
const configPath = (
process.env.VUE_CLI_SERVICE_CONFIG_PATH ||
path.resolve(this.context, 'vue.config.js')
)
const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
//use instead of
const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILD
process.VUE_CLI_SERVICE = this
// resolveClientEnv.js文件处理客户端的环境变量问题V以 UE_APP_开头的变量会切入到客户端的目标文件中
const prefixRE = /^VUE_APP_/
module.exports = function resolveClientEnv (options, raw) {
const env = {}
Object.keys(process.env).forEach(key => {
if (prefixRE.test(key) || key === 'NODE_ENV') {
env[key] = process.env[key]
}
})
env.BASE_URL = options.publicPath
if (raw) {
return env
}
for (const key in env) {
env[key] = JSON.stringify(env[key])
}
return {
'process.env': env
}
}