first commit
This commit is contained in:
376
app_vue/node_modules/@vue/cli-service/lib/Service.js
generated
vendored
Normal file
376
app_vue/node_modules/@vue/cli-service/lib/Service.js
generated
vendored
Normal file
@ -0,0 +1,376 @@
|
||||
const path = require('path')
|
||||
const debug = require('debug')
|
||||
const { merge } = require('webpack-merge')
|
||||
const Config = require('webpack-chain')
|
||||
const PluginAPI = require('./PluginAPI')
|
||||
const dotenv = require('dotenv')
|
||||
const dotenvExpand = require('dotenv-expand')
|
||||
const defaultsDeep = require('lodash.defaultsdeep')
|
||||
const { warn, error, isPlugin, resolvePluginId, loadModule, resolvePkg, resolveModule, sortPlugins } = require('@vue/cli-shared-utils')
|
||||
|
||||
const { defaults } = require('./options')
|
||||
const loadFileConfig = require('./util/loadFileConfig')
|
||||
const resolveUserConfig = require('./util/resolveUserConfig')
|
||||
|
||||
// Seems we can't use `instanceof Promise` here (would fail the tests)
|
||||
const isPromise = p => p && typeof p.then === 'function'
|
||||
module.exports = class Service {
|
||||
constructor (context, { plugins, pkg, inlineOptions, useBuiltIn } = {}) {
|
||||
process.VUE_CLI_SERVICE = this
|
||||
this.initialized = false
|
||||
this.context = context
|
||||
this.inlineOptions = inlineOptions
|
||||
this.webpackChainFns = []
|
||||
this.webpackRawConfigFns = []
|
||||
this.devServerConfigFns = []
|
||||
this.commands = {}
|
||||
// Folder containing the target package.json for plugins
|
||||
this.pkgContext = context
|
||||
// package.json containing the plugins
|
||||
this.pkg = this.resolvePkg(pkg)
|
||||
// If there are inline plugins, they will be used instead of those
|
||||
// found in package.json.
|
||||
// When useBuiltIn === false, built-in plugins are disabled. This is mostly
|
||||
// for testing.
|
||||
this.plugins = this.resolvePlugins(plugins, useBuiltIn)
|
||||
// pluginsToSkip will be populated during run()
|
||||
this.pluginsToSkip = new Set()
|
||||
// resolve the default mode to use for each command
|
||||
// this is provided by plugins as module.exports.defaultModes
|
||||
// so we can get the information without actually applying the plugin.
|
||||
this.modes = this.plugins.reduce((modes, { apply: { defaultModes } }) => {
|
||||
return Object.assign(modes, defaultModes)
|
||||
}, {})
|
||||
}
|
||||
|
||||
resolvePkg (inlinePkg, context = this.context) {
|
||||
if (inlinePkg) {
|
||||
return inlinePkg
|
||||
}
|
||||
const pkg = resolvePkg(context)
|
||||
if (pkg.vuePlugins && pkg.vuePlugins.resolveFrom) {
|
||||
this.pkgContext = path.resolve(context, pkg.vuePlugins.resolveFrom)
|
||||
return this.resolvePkg(null, this.pkgContext)
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
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()
|
||||
const loadedCallback = (loadedUserOptions) => {
|
||||
this.projectOptions = defaultsDeep(loadedUserOptions, defaults())
|
||||
|
||||
debug('vue:project-config')(this.projectOptions)
|
||||
|
||||
// apply plugins.
|
||||
this.plugins.forEach(({ id, apply }) => {
|
||||
if (this.pluginsToSkip.has(id)) return
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
if (isPromise(userOptions)) {
|
||||
return userOptions.then(loadedCallback)
|
||||
} else {
|
||||
return loadedCallback(userOptions)
|
||||
}
|
||||
}
|
||||
|
||||
loadEnv (mode) {
|
||||
const logger = debug('vue:env')
|
||||
const basePath = path.resolve(this.context, `.env${mode ? `.${mode}` : ``}`)
|
||||
const localPath = `${basePath}.local`
|
||||
|
||||
const load = envPath => {
|
||||
try {
|
||||
const env = dotenv.config({ path: envPath, debug: process.env.DEBUG })
|
||||
dotenvExpand(env)
|
||||
logger(envPath, env)
|
||||
} catch (err) {
|
||||
// only ignore error if file is not found
|
||||
if (err.toString().indexOf('ENOENT') < 0) {
|
||||
error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load(localPath)
|
||||
load(basePath)
|
||||
|
||||
// by default, NODE_ENV and BABEL_ENV are set to "development" unless mode
|
||||
// is production or test. However the value in .env files will take higher
|
||||
// priority.
|
||||
if (mode) {
|
||||
// always set NODE_ENV during tests
|
||||
// as that is necessary for tests to not be affected by each other
|
||||
const shouldForceDefaultEnv = (
|
||||
process.env.VUE_CLI_TEST &&
|
||||
!process.env.VUE_CLI_TEST_TESTING_ENV
|
||||
)
|
||||
const defaultNodeEnv = (mode === 'production' || mode === 'test')
|
||||
? mode
|
||||
: 'development'
|
||||
if (shouldForceDefaultEnv || process.env.NODE_ENV == null) {
|
||||
process.env.NODE_ENV = defaultNodeEnv
|
||||
}
|
||||
if (shouldForceDefaultEnv || process.env.BABEL_ENV == null) {
|
||||
process.env.BABEL_ENV = defaultNodeEnv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPluginsToSkip (args, rawArgv) {
|
||||
let skipPlugins = args['skip-plugins']
|
||||
const pluginsToSkip = new Set()
|
||||
if (skipPlugins) {
|
||||
// When only one appearence, convert to array to prevent duplicate code
|
||||
if (!Array.isArray(skipPlugins)) {
|
||||
skipPlugins = Array.from([skipPlugins])
|
||||
}
|
||||
// Iter over all --skip-plugins appearences
|
||||
for (const value of skipPlugins.values()) {
|
||||
for (const plugin of value.split(',').map(id => resolvePluginId(id))) {
|
||||
pluginsToSkip.add(plugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.pluginsToSkip = pluginsToSkip
|
||||
|
||||
delete args['skip-plugins']
|
||||
// Delete all --skip-plugin appearences
|
||||
let index
|
||||
while ((index = rawArgv.indexOf('--skip-plugins')) > -1) {
|
||||
rawArgv.splice(index, 2) // Remove the argument and its value
|
||||
}
|
||||
}
|
||||
|
||||
resolvePlugins (inlinePlugins, useBuiltIn) {
|
||||
const idToPlugin = (id, absolutePath) => ({
|
||||
id: id.replace(/^.\//, 'built-in:'),
|
||||
apply: require(absolutePath || id)
|
||||
})
|
||||
|
||||
let plugins
|
||||
|
||||
const builtInPlugins = [
|
||||
'./commands/serve',
|
||||
'./commands/build',
|
||||
'./commands/inspect',
|
||||
'./commands/help',
|
||||
// config plugins are order sensitive
|
||||
'./config/base',
|
||||
'./config/assets',
|
||||
'./config/css',
|
||||
'./config/prod',
|
||||
'./config/app'
|
||||
].map((id) => idToPlugin(id))
|
||||
|
||||
if (inlinePlugins) {
|
||||
plugins = useBuiltIn !== false
|
||||
? builtInPlugins.concat(inlinePlugins)
|
||||
: inlinePlugins
|
||||
} else {
|
||||
const projectPlugins = Object.keys(this.pkg.devDependencies || {})
|
||||
.concat(Object.keys(this.pkg.dependencies || {}))
|
||||
.filter(isPlugin)
|
||||
.map(id => {
|
||||
if (
|
||||
this.pkg.optionalDependencies &&
|
||||
id in this.pkg.optionalDependencies
|
||||
) {
|
||||
let apply = loadModule(id, this.pkgContext)
|
||||
if (!apply) {
|
||||
warn(`Optional dependency ${id} is not installed.`)
|
||||
apply = () => {}
|
||||
}
|
||||
|
||||
return { id, apply }
|
||||
} else {
|
||||
return idToPlugin(id, resolveModule(id, this.pkgContext))
|
||||
}
|
||||
})
|
||||
|
||||
plugins = builtInPlugins.concat(projectPlugins)
|
||||
}
|
||||
|
||||
// Local plugins
|
||||
if (this.pkg.vuePlugins && this.pkg.vuePlugins.service) {
|
||||
const files = this.pkg.vuePlugins.service
|
||||
if (!Array.isArray(files)) {
|
||||
throw new Error(`Invalid type for option 'vuePlugins.service', expected 'array' but got ${typeof files}.`)
|
||||
}
|
||||
plugins = plugins.concat(files.map(file => ({
|
||||
id: `local:${file}`,
|
||||
apply: loadModule(`./${file}`, this.pkgContext)
|
||||
})))
|
||||
}
|
||||
debug('vue:plugins')(plugins)
|
||||
|
||||
const orderedPlugins = sortPlugins(plugins)
|
||||
debug('vue:plugins-ordered')(orderedPlugins)
|
||||
|
||||
return orderedPlugins
|
||||
}
|
||||
|
||||
async run (name, args = {}, rawArgv = []) {
|
||||
// resolve mode
|
||||
// prioritize inline --mode
|
||||
// fallback to resolved default modes from plugins or development if --watch is defined
|
||||
const mode = args.mode || (name === 'build' && args.watch ? 'development' : this.modes[name])
|
||||
|
||||
// --skip-plugins arg may have plugins that should be skipped during init()
|
||||
this.setPluginsToSkip(args, rawArgv)
|
||||
|
||||
// load env variables, load user config, apply plugins
|
||||
await this.init(mode)
|
||||
|
||||
args._ = args._ || []
|
||||
let command = this.commands[name]
|
||||
if (!command && name) {
|
||||
error(`command "${name}" does not exist.`)
|
||||
process.exit(1)
|
||||
}
|
||||
if (!command || args.help || args.h) {
|
||||
command = this.commands.help
|
||||
} else {
|
||||
args._.shift() // remove command itself
|
||||
rawArgv.shift()
|
||||
}
|
||||
const { fn } = command
|
||||
return fn(args, rawArgv)
|
||||
}
|
||||
|
||||
resolveChainableWebpackConfig () {
|
||||
const chainableConfig = new Config()
|
||||
// apply chains
|
||||
this.webpackChainFns.forEach(fn => fn(chainableConfig))
|
||||
return chainableConfig
|
||||
}
|
||||
|
||||
resolveWebpackConfig (chainableConfig = this.resolveChainableWebpackConfig()) {
|
||||
if (!this.initialized) {
|
||||
throw new Error('Service must call init() before calling resolveWebpackConfig().')
|
||||
}
|
||||
// get raw config
|
||||
let config = chainableConfig.toConfig()
|
||||
const original = config
|
||||
// apply raw config fns
|
||||
this.webpackRawConfigFns.forEach(fn => {
|
||||
if (typeof fn === 'function') {
|
||||
// function with optional return value
|
||||
const res = fn(config)
|
||||
if (res) config = merge(config, res)
|
||||
} else if (fn) {
|
||||
// merge literal values
|
||||
config = merge(config, fn)
|
||||
}
|
||||
})
|
||||
|
||||
// #2206 If config is merged by merge-webpack, it discards the __ruleNames
|
||||
// information injected by webpack-chain. Restore the info so that
|
||||
// vue inspect works properly.
|
||||
if (config !== original) {
|
||||
cloneRuleNames(
|
||||
config.module && config.module.rules,
|
||||
original.module && original.module.rules
|
||||
)
|
||||
}
|
||||
|
||||
// check if the user has manually mutated output.publicPath
|
||||
const target = process.env.VUE_CLI_BUILD_TARGET
|
||||
if (
|
||||
!process.env.VUE_CLI_TEST &&
|
||||
(target && target !== 'app') &&
|
||||
config.output.publicPath !== this.projectOptions.publicPath
|
||||
) {
|
||||
throw new Error(
|
||||
`Do not modify webpack output.publicPath directly. ` +
|
||||
`Use the "publicPath" option in vue.config.js instead.`
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
!process.env.VUE_CLI_ENTRY_FILES &&
|
||||
typeof config.entry !== 'function'
|
||||
) {
|
||||
let entryFiles
|
||||
if (typeof config.entry === 'string') {
|
||||
entryFiles = [config.entry]
|
||||
} else if (Array.isArray(config.entry)) {
|
||||
entryFiles = config.entry
|
||||
} else {
|
||||
entryFiles = Object.values(config.entry || []).reduce((allEntries, curr) => {
|
||||
return allEntries.concat(curr)
|
||||
}, [])
|
||||
}
|
||||
|
||||
entryFiles = entryFiles.map(file => path.resolve(this.context, file))
|
||||
process.env.VUE_CLI_ENTRY_FILES = JSON.stringify(entryFiles)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Note: we intentionally make this function synchronous by default
|
||||
// because eslint-import-resolver-webpack does not support async webpack configs.
|
||||
loadUserOptions () {
|
||||
const { fileConfig, fileConfigPath } = loadFileConfig(this.context)
|
||||
|
||||
if (isPromise(fileConfig)) {
|
||||
return fileConfig
|
||||
.then(mod => mod.default)
|
||||
.then(loadedConfig => resolveUserConfig({
|
||||
inlineOptions: this.inlineOptions,
|
||||
pkgConfig: this.pkg.vue,
|
||||
fileConfig: loadedConfig,
|
||||
fileConfigPath
|
||||
}))
|
||||
}
|
||||
|
||||
return resolveUserConfig({
|
||||
inlineOptions: this.inlineOptions,
|
||||
pkgConfig: this.pkg.vue,
|
||||
fileConfig,
|
||||
fileConfigPath
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function cloneRuleNames (to, from) {
|
||||
if (!to || !from) {
|
||||
return
|
||||
}
|
||||
from.forEach((r, i) => {
|
||||
if (to[i]) {
|
||||
Object.defineProperty(to[i], '__ruleNames', {
|
||||
value: r.__ruleNames
|
||||
})
|
||||
cloneRuleNames(to[i].oneOf, r.oneOf)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** @type {import('../types/index').defineConfig} */
|
||||
module.exports.defineConfig = (config) => config
|
Reference in New Issue
Block a user