first commit

This commit is contained in:
monjack
2025-06-20 18:01:48 +08:00
commit 6daa6d65c1
24611 changed files with 2512443 additions and 0 deletions

21
app_vue/node_modules/@vue/cli-service/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

5
app_vue/node_modules/@vue/cli-service/README.md generated vendored Normal file
View File

@ -0,0 +1,5 @@
# @vue/cli-service
> service for vue-cli
[Full Docs](https://cli.vuejs.org/)

View File

@ -0,0 +1,40 @@
#!/usr/bin/env node
const { semver, error } = require('@vue/cli-shared-utils')
const requiredVersion = require('../package.json').engines.node
if (!semver.satisfies(process.version, requiredVersion, { includePrerelease: true })) {
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
// FIXME: --no-module, --no-unsafe-inline, no-clean, etc.
'modern',
'report',
'report-json',
'inline-vue',
'watch',
// serve
'open',
'copy',
'https',
// inspect
'verbose'
]
})
const command = args._[0]
service.run(command, args, rawArgv).catch(err => {
error(err)
process.exit(1)
})

View File

@ -0,0 +1,81 @@
module.exports = (api, options) => {
api.render('./template', {
doesCompile: api.hasPlugin('babel') || api.hasPlugin('typescript'),
useBabel: api.hasPlugin('babel')
})
if (options.vueVersion === '3') {
api.extendPackage({
dependencies: {
'vue': '^3.2.13'
}
})
} else {
api.extendPackage({
dependencies: {
'vue': '^2.6.14'
},
devDependencies: {
'vue-template-compiler': '^2.6.14'
}
})
}
api.extendPackage({
scripts: {
'serve': 'vue-cli-service serve',
'build': 'vue-cli-service build'
},
browserslist: [
'> 1%',
'last 2 versions',
'not dead',
...(options.vueVersion === '3' ? ['not ie 11'] : [])
]
})
if (options.cssPreprocessor) {
const deps = {
sass: {
sass: '^1.32.7',
'sass-loader': '^12.0.0'
},
'dart-sass': {
sass: '^1.32.7',
'sass-loader': '^12.0.0'
},
less: {
'less': '^4.0.0',
'less-loader': '^8.0.0'
},
stylus: {
'stylus': '^0.55.0',
'stylus-loader': '^6.1.0'
}
}
api.extendPackage({
devDependencies: deps[options.cssPreprocessor]
})
}
// for v3 compatibility
if (options.router && !api.hasPlugin('router')) {
require('./router')(api, options, options)
}
// for v3 compatibility
if (options.vuex && !api.hasPlugin('vuex')) {
require('./vuex')(api, options, options)
}
// additional tooling configurations
if (options.configs) {
api.extendPackage(options.configs)
}
// Delete jsconfig.json when typescript
if (api.hasPlugin('typescript')) {
api.render((files) => delete files['jsconfig.json'])
}
}

View File

@ -0,0 +1,5 @@
module.exports = (api, options) => {
require('@vue/cli-plugin-router/generator')(api, {
historyMode: options.routerHistoryMode
})
}

View File

@ -0,0 +1,39 @@
.DS_Store
node_modules
/dist
<%_ if (rootOptions.plugins && rootOptions.plugins['@vue/cli-plugin-e2e-nightwatch']) { _%>
/tests/e2e/reports/
selenium-debug.log
chromedriver.log
geckodriver.log
<%_ } _%>
<%_ if (rootOptions.plugins && rootOptions.plugins['@vue/cli-plugin-e2e-cypress']) { _%>
/tests/e2e/videos/
/tests/e2e/screenshots/
<%_ } _%>
<%_ if (rootOptions.plugins && rootOptions.plugins['@vue/cli-plugin-e2e-webdriverio']) { _%>
/tests/e2e/logs/
<%_ } _%>
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "<%- options.useBabel ? 'esnext' : 'es5' %>",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%%= BASE_URL %%>favicon.ico">
<title><%%= htmlWebpackPlugin.options.title %%></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%%= htmlWebpackPlugin.options.title %%> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -0,0 +1,63 @@
<template>
<%_ if (rootOptions.vueVersion === '3') { _%>
<img alt="Vue logo" src="./assets/logo.png">
<%_ if (!rootOptions.bare) { _%>
<HelloWorld msg="Welcome to Your Vue.js App"/>
<%_ } else { _%>
<h1>Welcome to Your Vue.js App</h1>
<%_ } _%>
<%_ } else { _%>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<%_ if (!rootOptions.bare) { _%>
<HelloWorld msg="Welcome to Your Vue.js App"/>
<%_ } else { _%>
<h1>Welcome to Your Vue.js App</h1>
<%_ } _%>
</div>
<%_ } _%>
</template>
<%_ if (!rootOptions.bare) { _%>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<%_ if (rootOptions.cssPreprocessor !== 'stylus') { _%>
<style<%-
rootOptions.cssPreprocessor
? ` lang="${
rootOptions.cssPreprocessor.includes('sass')
? 'scss'
: rootOptions.cssPreprocessor
}"`
: ``
%>>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<%_ } else { _%>
<style lang="stylus">
#app
font-family Avenir, Helvetica, Arial, sans-serif
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
text-align center
color #2c3e50
margin-top 60px
</style>
<%_ } _%>
<%_ } _%>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,87 @@
<%_ if (!rootOptions.bare) { _%>
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<%_ for (plugin of plugins) { _%>
<li><a href="<%- plugin.link %>" target="_blank" rel="noopener"><%- plugin.name %></a></li>
<%_ } _%>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<%_ if (rootOptions.cssPreprocessor !== 'stylus') { _%>
<style scoped<%-
rootOptions.cssPreprocessor
? ` lang="${
rootOptions.cssPreprocessor.includes('sass')
? 'scss'
: rootOptions.cssPreprocessor
}"`
: ``
%>>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<%_ } else { _%>
<style scoped lang="stylus">
h3
margin 40px 0 0
ul
list-style-type none
padding 0
li
display inline-block
margin 0 10px
a
color #42b983
</style>
<%_ } _%>
<%_ } _%>

View File

@ -0,0 +1,19 @@
<%_ if (rootOptions.vueVersion === '3') { _%>
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
<%_ } else { _%>
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
<%_ if (doesCompile) { _%>
render: h => h(App),
<%_ } else { _%>
render: function (h) { return h(App) },
<%_ } _%>
}).$mount('#app')
<%_ } _%>

View File

@ -0,0 +1,3 @@
module.exports = api => {
require('@vue/cli-plugin-vuex/generator')(api)
}

217
app_vue/node_modules/@vue/cli-service/lib/PluginAPI.js generated vendored Normal file
View File

@ -0,0 +1,217 @@
const path = require('path')
const hash = require('hash-sum')
const { semver, matchesPluginId } = require('@vue/cli-shared-utils')
// Note: if a plugin-registered command needs to run in a specific default mode,
// the plugin needs to expose it via `module.exports.defaultModes` in the form
// of { [commandName]: mode }. This is because the command mode needs to be
// known and applied before loading user options / applying plugins.
class PluginAPI {
/**
* @param {string} id - Id of the plugin.
* @param {Service} service - A vue-cli-service instance.
*/
constructor (id, service) {
this.id = id
this.service = service
}
get version () {
return require('../package.json').version
}
assertVersion (range) {
if (typeof range === 'number') {
if (!Number.isInteger(range)) {
throw new Error('Expected string or integer value.')
}
range = `^${range}.0.0-0`
}
if (typeof range !== 'string') {
throw new Error('Expected string or integer value.')
}
if (semver.satisfies(this.version, range, { includePrerelease: true })) return
throw new Error(
`Require @vue/cli-service "${range}", but was loaded with "${this.version}".`
)
}
/**
* Current working directory.
*/
getCwd () {
return this.service.context
}
/**
* Resolve path for a project.
*
* @param {string} _path - Relative path from project root
* @return {string} The resolved absolute path.
*/
resolve (_path) {
return path.resolve(this.service.context, _path)
}
/**
* Check if the project has a given plugin.
*
* @param {string} id - Plugin id, can omit the (@vue/|vue-|@scope/vue)-cli-plugin- prefix
* @return {boolean}
*/
hasPlugin (id) {
return this.service.plugins.some(p => matchesPluginId(id, p.id))
}
/**
* Register a command that will become available as `vue-cli-service [name]`.
*
* @param {string} name
* @param {object} [opts]
* {
* description: string,
* usage: string,
* options: { [string]: string }
* }
* @param {function} fn
* (args: { [string]: string }, rawArgs: string[]) => ?Promise
*/
registerCommand (name, opts, fn) {
if (typeof opts === 'function') {
fn = opts
opts = null
}
this.service.commands[name] = { fn, opts: opts || {} }
}
/**
* Register a function that will receive a chainable webpack config
* the function is lazy and won't be called until `resolveWebpackConfig` is
* called
*
* @param {function} fn
*/
chainWebpack (fn) {
this.service.webpackChainFns.push(fn)
}
/**
* Register
* - a webpack configuration object that will be merged into the config
* OR
* - a function that will receive the raw webpack config.
* the function can either mutate the config directly or return an object
* that will be merged into the config.
*
* @param {object | function} fn
*/
configureWebpack (fn) {
this.service.webpackRawConfigFns.push(fn)
}
/**
* Register a dev serve config function. It will receive the express `app`
* instance of the dev server.
*
* @param {function} fn
*/
configureDevServer (fn) {
this.service.devServerConfigFns.push(fn)
}
/**
* Resolve the final raw webpack config, that will be passed to webpack.
*
* @param {ChainableWebpackConfig} [chainableConfig]
* @return {object} Raw webpack config.
*/
resolveWebpackConfig (chainableConfig) {
return this.service.resolveWebpackConfig(chainableConfig)
}
/**
* Resolve an intermediate chainable webpack config instance, which can be
* further tweaked before generating the final raw webpack config.
* You can call this multiple times to generate different branches of the
* base webpack config.
* See https://github.com/mozilla-neutrino/webpack-chain
*
* @return {ChainableWebpackConfig}
*/
resolveChainableWebpackConfig () {
return this.service.resolveChainableWebpackConfig()
}
/**
* Generate a cache identifier from a number of variables
*/
genCacheConfig (id, partialIdentifier, configFiles = []) {
const fs = require('fs')
const cacheDirectory = this.resolve(`node_modules/.cache/${id}`)
// replace \r\n to \n generate consistent hash
const fmtFunc = conf => {
if (typeof conf === 'function') {
return conf.toString().replace(/\r\n?/g, '\n')
}
return conf
}
const variables = {
partialIdentifier,
'cli-service': require('../package.json').version,
env: process.env.NODE_ENV,
test: !!process.env.VUE_CLI_TEST,
config: [
fmtFunc(this.service.projectOptions.chainWebpack),
fmtFunc(this.service.projectOptions.configureWebpack)
]
}
try {
variables['cache-loader'] = require('cache-loader/package.json').version
} catch (e) {
// cache-loader is only intended to be used for webpack 4
}
if (!Array.isArray(configFiles)) {
configFiles = [configFiles]
}
configFiles = configFiles.concat([
'package-lock.json',
'yarn.lock',
'pnpm-lock.yaml'
])
const readConfig = file => {
const absolutePath = this.resolve(file)
if (!fs.existsSync(absolutePath)) {
return
}
if (absolutePath.endsWith('.js')) {
// should evaluate config scripts to reflect environment variable changes
try {
return JSON.stringify(require(absolutePath))
} catch (e) {
return fs.readFileSync(absolutePath, 'utf-8')
}
} else {
return fs.readFileSync(absolutePath, 'utf-8')
}
}
variables.configFiles = configFiles.map(file => {
const content = readConfig(file)
return content && content.replace(/\r\n?/g, '\n')
})
const cacheIdentifier = hash(variables)
return { cacheDirectory, cacheIdentifier }
}
}
module.exports = PluginAPI

376
app_vue/node_modules/@vue/cli-service/lib/Service.js generated vendored Normal file
View 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

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title><%- htmlWebpackPlugin.options.libName %> demo</title>
<script src="./<%- htmlWebpackPlugin.options.assetsFileName %>.umd.js"></script>
<% if (htmlWebpackPlugin.options.cssExtract) { %>
<link rel="stylesheet" href="./<%- htmlWebpackPlugin.options.assetsFileName %>.css">
<% } %>
<script>
console.log(<%- htmlWebpackPlugin.options.libName %>)
</script>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title><%- htmlWebpackPlugin.options.libName %> demo</title>
<script src="//unpkg.com/vue@<%- htmlWebpackPlugin.options.vueMajor %>"></script>
<script src="./<%- htmlWebpackPlugin.options.assetsFileName %>.umd.js"></script>
<% if (htmlWebpackPlugin.options.cssExtract) { %>
<link rel="stylesheet" href="./<%- htmlWebpackPlugin.options.assetsFileName %>.css">
<% } %>
<div id="app">
<demo></demo>
</div>
<script>
<% if (htmlWebpackPlugin.options.vueMajor === 3) { %>
Vue.createApp({
components: {
demo: <%- htmlWebpackPlugin.options.libName %>
}
}).mount('#app')
<% } else { %>
new Vue({
components: {
demo: <%- htmlWebpackPlugin.options.libName %>
}
}).$mount('#app')
<% } %>
</script>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title><%- htmlWebpackPlugin.options.libName %> demo</title>
<script src="https://unpkg.com/vue@<%- htmlWebpackPlugin.options.vueMajor %>"></script>
<script src="./<%- htmlWebpackPlugin.options.libName %>.js"></script>
<% for (const comp of htmlWebpackPlugin.options.components) { %>
<<%= comp %>></<%= comp %>>
<% } %>

View File

@ -0,0 +1,2 @@
import './setPublicPath'
export * from '~entry'

View File

@ -0,0 +1,4 @@
import './setPublicPath'
import mod from '~entry'
export default mod
export * from '~entry'

View File

@ -0,0 +1,12 @@
import './setPublicPath'
import Vue from 'vue'
import wrap from '@vue/web-component-wrapper'
// runtime shared by every component chunk
import 'css-loader/dist/runtime/api.js'
import 'vue-style-loader/lib/addStylesShadow'
import 'vue-loader/lib/runtime/componentNormalizer'
window.customElements.define('build-wc-async-app', wrap(Vue, () => import('~root/src/App.vue?shadow')))
window.customElements.define('build-wc-async-hello-world', wrap(Vue, () => import('~root/src/components/HelloWorld.vue?shadow')))

View File

@ -0,0 +1,77 @@
module.exports = function formatStats (stats, dir, api) {
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const ui = require('cliui')({ width: process.stdout.columns || 80 })
const { chalk } = require('@vue/cli-shared-utils')
const json = stats.toJson({
hash: false,
modules: false,
chunks: false
})
let assets = json.assets
? json.assets
: json.children.reduce((acc, child) => acc.concat(child.assets), [])
const seenNames = new Map()
const isJS = val => /\.js$/.test(val)
const isCSS = val => /\.css$/.test(val)
const isMinJS = val => /\.min\.js$/.test(val)
assets = assets
.map(a => {
a.name = a.name.split('?')[0]
return a
})
.filter(a => {
if (seenNames.has(a.name)) {
return false
}
seenNames.set(a.name, true)
return isJS(a.name) || isCSS(a.name)
})
.sort((a, b) => {
if (isJS(a.name) && isCSS(b.name)) return -1
if (isCSS(a.name) && isJS(b.name)) return 1
if (isMinJS(a.name) && !isMinJS(b.name)) return -1
if (!isMinJS(a.name) && isMinJS(b.name)) return 1
return b.size - a.size
})
function formatSize (size) {
return (size / 1024).toFixed(2) + ' KiB'
}
function getGzippedSize (asset) {
const filepath = api.resolve(path.join(dir, asset.name))
const buffer = fs.readFileSync(filepath)
return formatSize(zlib.gzipSync(buffer).length)
}
function makeRow (a, b, c) {
return ` ${a}\t ${b}\t ${c}`
}
ui.div(
makeRow(
chalk.cyan.bold(`File`),
chalk.cyan.bold(`Size`),
chalk.cyan.bold(`Gzipped`)
) + `\n\n` +
assets.map(asset => makeRow(
/js$/.test(asset.name)
? chalk.green(path.join(dir, asset.name))
: chalk.blue(path.join(dir, asset.name)),
formatSize(asset.size),
getGzippedSize(asset)
)).join(`\n`)
)
const time = stats.endTime - stats.startTime
const now = new Date().toISOString()
const hash = stats.hash
const info = `Build at: ${chalk.white(now)} - Hash: ${chalk.white(hash)} - Time: ${chalk.white(time)}ms`
return `${ui.toString()}\n\n ${chalk.gray(`Images and other types of assets omitted.`)}\n ${info}\n`
}

View File

@ -0,0 +1,238 @@
const defaults = {
clean: true,
target: 'app',
module: true,
formats: 'commonjs,umd,umd-min'
}
const buildModes = {
lib: 'library',
wc: 'web component',
'wc-async': 'web component (async)'
}
const modifyConfig = (config, fn) => {
if (Array.isArray(config)) {
config.forEach(c => fn(c))
} else {
fn(config)
}
}
module.exports = (api, options) => {
api.registerCommand('build', {
description: 'build for production',
usage: 'vue-cli-service build [options] [entry|pattern]',
options: {
'--mode': `specify env mode (default: production)`,
'--dest': `specify output directory (default: ${options.outputDir})`,
'--no-module': `build app without generating <script type="module"> chunks for modern browsers`,
'--target': `app | lib | wc | wc-async (default: ${defaults.target})`,
'--inline-vue': 'include the Vue module in the final bundle of library or web component target',
'--formats': `list of output formats for library builds (default: ${defaults.formats})`,
'--name': `name for lib or web-component mode (default: "name" in package.json or entry filename)`,
'--filename': `file name for output, only usable for 'lib' target (default: value of --name)`,
'--no-clean': `do not remove the dist directory contents before building the project`,
'--report': `generate report.html to help analyze bundle content`,
'--report-json': 'generate report.json to help analyze bundle content',
'--skip-plugins': `comma-separated list of plugin names to skip for this run`,
'--watch': `watch for changes`,
'--stdin': `close when stdin ends`
}
}, async (args, rawArgs) => {
for (const key in defaults) {
if (args[key] == null) {
args[key] = defaults[key]
}
}
args.entry = args.entry || args._[0]
if (args.target !== 'app') {
args.entry = args.entry || 'src/App.vue'
}
process.env.VUE_CLI_BUILD_TARGET = args.target
const { log, execa } = require('@vue/cli-shared-utils')
const { allProjectTargetsSupportModule } = require('../../util/targets')
let needsDifferentialLoading = args.target === 'app' && args.module
if (allProjectTargetsSupportModule) {
log(
`All browser targets in the browserslist configuration have supported ES module.\n` +
`Therefore we don't build two separate bundles for differential loading.\n`
)
needsDifferentialLoading = false
}
args.needsDifferentialLoading = needsDifferentialLoading
if (!needsDifferentialLoading) {
await build(args, api, options)
return
}
process.env.VUE_CLI_MODERN_MODE = true
if (!process.env.VUE_CLI_MODERN_BUILD) {
// main-process for legacy build
const legacyBuildArgs = { ...args, moduleBuild: false, keepAlive: true }
await build(legacyBuildArgs, api, options)
// spawn sub-process of self for modern build
const cliBin = require('path').resolve(__dirname, '../../../bin/vue-cli-service.js')
await execa('node', [cliBin, 'build', ...rawArgs], {
stdio: 'inherit',
env: {
VUE_CLI_MODERN_BUILD: true
}
})
} else {
// sub-process for modern build
const moduleBuildArgs = { ...args, moduleBuild: true, clean: false }
await build(moduleBuildArgs, api, options)
}
})
}
async function build (args, api, options) {
const fs = require('fs-extra')
const path = require('path')
const webpack = require('webpack')
const { chalk } = require('@vue/cli-shared-utils')
const formatStats = require('./formatStats')
const validateWebpackConfig = require('../../util/validateWebpackConfig')
const {
log,
done,
info,
logWithSpinner,
stopSpinner
} = require('@vue/cli-shared-utils')
log()
const mode = api.service.mode
if (args.target === 'app') {
const bundleTag = args.needsDifferentialLoading
? args.moduleBuild
? `module bundle `
: `legacy bundle `
: ``
logWithSpinner(`Building ${bundleTag}for ${mode}...`)
} else {
const buildMode = buildModes[args.target]
if (buildMode) {
const additionalParams = buildMode === 'library' ? ` (${args.formats})` : ``
logWithSpinner(`Building for ${mode} as ${buildMode}${additionalParams}...`)
} else {
throw new Error(`Unknown build target: ${args.target}`)
}
}
if (args.dest) {
// Override outputDir before resolving webpack config as config relies on it (#2327)
options.outputDir = args.dest
}
const targetDir = api.resolve(options.outputDir)
const isLegacyBuild = args.needsDifferentialLoading && !args.moduleBuild
// resolve raw webpack config
let webpackConfig
if (args.target === 'lib') {
webpackConfig = require('./resolveLibConfig')(api, args, options)
} else if (
args.target === 'wc' ||
args.target === 'wc-async'
) {
webpackConfig = require('./resolveWcConfig')(api, args, options)
} else {
webpackConfig = require('./resolveAppConfig')(api, args, options)
}
// check for common config errors
validateWebpackConfig(webpackConfig, api, options, args.target)
if (args.watch) {
modifyConfig(webpackConfig, config => {
config.watch = true
})
}
if (args.stdin) {
process.stdin.on('end', () => {
process.exit(0)
})
process.stdin.resume()
}
// Expose advanced stats
if (args.dashboard) {
const DashboardPlugin = require('../../webpack/DashboardPlugin')
modifyConfig(webpackConfig, config => {
config.plugins.push(new DashboardPlugin({
type: 'build',
moduleBuild: args.moduleBuild,
keepAlive: args.keepAlive
}))
})
}
if (args.report || args['report-json']) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
modifyConfig(webpackConfig, config => {
const bundleName = args.target !== 'app'
? config.output.filename.replace(/\.js$/, '-')
: isLegacyBuild ? 'legacy-' : ''
config.plugins.push(new BundleAnalyzerPlugin({
logLevel: 'warn',
openAnalyzer: false,
analyzerMode: args.report ? 'static' : 'disabled',
reportFilename: `${bundleName}report.html`,
statsFilename: `${bundleName}report.json`,
generateStatsFile: !!args['report-json']
}))
})
}
if (args.clean) {
await fs.emptyDir(targetDir)
}
return new Promise((resolve, reject) => {
webpack(webpackConfig, (err, stats) => {
stopSpinner(false)
if (err) {
return reject(err)
}
if (stats.hasErrors()) {
return reject(new Error('Build failed with errors.'))
}
if (!args.silent) {
const targetDirShort = path.relative(
api.service.context,
targetDir
)
log(formatStats(stats, targetDirShort, api))
if (args.target === 'app' && !isLegacyBuild) {
if (!args.watch) {
done(`Build complete. The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.`)
info(`Check out deployment instructions at ${chalk.cyan(`https://cli.vuejs.org/guide/deployment.html`)}\n`)
} else {
done(`Build complete. Watching for changes...`)
}
}
}
// test-only signal
if (process.env.VUE_CLI_TEST) {
console.log('Build complete.')
}
resolve()
})
})
}
module.exports.defaultModes = {
build: 'production'
}

View File

@ -0,0 +1,52 @@
module.exports = (api, args, options) => {
// respect inline entry
if (args.entry && !options.pages) {
api.configureWebpack(config => {
config.entry = { app: api.resolve(args.entry) }
})
}
const config = api.resolveChainableWebpackConfig()
const targetDir = api.resolve(args.dest || options.outputDir)
// respect inline build destination in copy plugin
if (args.dest && config.plugins.has('copy')) {
config.plugin('copy').tap(pluginArgs => {
pluginArgs[0].patterns.to = targetDir
return pluginArgs
})
}
if (process.env.VUE_CLI_MODERN_MODE) {
const ModernModePlugin = require('../../webpack/ModernModePlugin')
const SafariNomoduleFixPlugin = require('../../webpack/SafariNomoduleFixPlugin')
if (!args.moduleBuild) {
// Inject plugin to extract build stats and write to disk
config
.plugin('modern-mode-legacy')
.use(ModernModePlugin, [{
targetDir,
isModuleBuild: false
}])
} else {
config
.plugin('safari-nomodule-fix')
.use(SafariNomoduleFixPlugin, [{
// as we may generate an addition file asset (if Safari 10 fix is needed)
// we need to provide the correct directory for that file to place in
jsDirectory: require('../../util/getAssetPath')(options, 'js')
}])
// Inject plugin to read non-modern build stats and inject HTML
config
.plugin('modern-mode-modern')
.use(ModernModePlugin, [{
targetDir,
isModuleBuild: true
}])
}
}
return api.resolveWebpackConfig(config)
}

View File

@ -0,0 +1,159 @@
const fs = require('fs')
const path = require('path')
module.exports = (api, { entry, name, formats, filename, 'inline-vue': inlineVue }, options) => {
const { log, error } = require('@vue/cli-shared-utils')
const abort = msg => {
log()
error(msg)
process.exit(1)
}
const vueMajor = require('../../util/getVueMajor')(api.getCwd())
const fullEntryPath = api.resolve(entry)
if (!fs.existsSync(fullEntryPath)) {
abort(
`Failed to resolve lib entry: ${entry}${entry === `src/App.vue` ? ' (default)' : ''}. ` +
`Make sure to specify the correct entry file.`
)
}
const isVueEntry = /\.vue$/.test(entry)
const libName = (
name ||
(
api.service.pkg.name
? api.service.pkg.name.replace(/^@.+\//, '')
: path.basename(entry).replace(/\.(jsx?|vue)$/, '')
)
)
filename = filename || libName
function genConfig (format, postfix = format, genHTML) {
const config = api.resolveChainableWebpackConfig()
const browserslist = require('browserslist')
const targets = browserslist(undefined, { path: fullEntryPath })
const supportsIE = targets.some(agent => agent.includes('ie'))
const webpack = require('webpack')
config.plugin('need-current-script-polyfill')
.use(webpack.DefinePlugin, [{
'process.env.NEED_CURRENTSCRIPT_POLYFILL': JSON.stringify(supportsIE)
}])
// adjust css output name so they write to the same file
if (config.plugins.has('extract-css')) {
config
.plugin('extract-css')
.tap(args => {
args[0].filename = `${filename}.css`
return args
})
}
// only minify min entry
if (!/\.min/.test(postfix)) {
config.optimization.minimize(false)
}
// inject demo page for umd
if (genHTML) {
const template = isVueEntry ? 'demo-lib.html' : 'demo-lib-js.html'
config
.plugin('demo-html')
.use(require('html-webpack-plugin'), [{
template: path.resolve(__dirname, template),
inject: false,
filename: 'demo.html',
libName,
vueMajor,
assetsFileName: filename,
cssExtract: config.plugins.has('extract-css')
}])
}
// resolve entry/output
const entryName = `${filename}.${postfix}`
config.resolve
.alias
.set('~entry', fullEntryPath)
// set output target before user configureWebpack hooks are applied
config.output.libraryTarget(format)
// set entry/output after user configureWebpack hooks are applied
const rawConfig = api.resolveWebpackConfig(config)
let realEntry = require.resolve('./entry-lib.js')
// avoid importing default if user entry file does not have default export
if (!isVueEntry) {
const entryContent = fs.readFileSync(fullEntryPath, 'utf-8')
if (!/\b(export\s+default|export\s{[^}]+as\s+default)\b/.test(entryContent)) {
realEntry = require.resolve('./entry-lib-no-default.js')
}
}
// externalize Vue in case user imports it
rawConfig.externals = [
...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
{
...(inlineVue || {
vue: {
commonjs: 'vue',
commonjs2: 'vue',
root: 'Vue'
}
})
}
].filter(Boolean)
rawConfig.entry = {
[entryName]: realEntry
}
rawConfig.output = Object.assign({
library: libName,
libraryExport: isVueEntry ? 'default' : undefined,
libraryTarget: format,
// preserve UDM header from webpack 3 until webpack provides either
// libraryTarget: 'esm' or target: 'universal'
// https://github.com/webpack/webpack/issues/6522
// https://github.com/webpack/webpack/issues/6525
globalObject: `(typeof self !== 'undefined' ? self : this)`
}, rawConfig.output, {
filename: `${entryName}.js`,
chunkFilename: `${entryName}.[name].js`,
// use dynamic publicPath so this can be deployed anywhere
// the actual path will be determined at runtime by checking
// document.currentScript.src.
publicPath: ''
})
if (format === 'commonjs2') {
// #6188
delete rawConfig.output.library
}
return rawConfig
}
const configMap = {
commonjs: genConfig('commonjs2', 'common'),
umd: genConfig('umd', undefined, true),
'umd-min': genConfig('umd', 'umd.min')
}
const formatArray = (formats + '').split(',')
const configs = formatArray.map(format => configMap[format])
if (configs.indexOf(undefined) !== -1) {
const unknownFormats = formatArray.filter(f => configMap[f] === undefined).join(', ')
abort(
`Unknown library build formats: ${unknownFormats}`
)
}
return configs
}

View File

@ -0,0 +1,143 @@
const path = require('path')
const { resolveEntry, fileToComponentName } = require('./resolveWcEntry')
module.exports = (api, { target, entry, name, 'inline-vue': inlineVue }) => {
// Disable CSS extraction and turn on CSS shadow mode for vue-style-loader
process.env.VUE_CLI_CSS_SHADOW_MODE = true
const { log, error } = require('@vue/cli-shared-utils')
const abort = msg => {
log()
error(msg)
process.exit(1)
}
const cwd = api.getCwd()
const webpack = require('webpack')
const vueMajor = require('../../util/getVueMajor')(cwd)
if (vueMajor === 3) {
abort(`Vue 3 support of the web component target is still under development.`)
}
const isAsync = /async/.test(target)
// generate dynamic entry based on glob files
const resolvedFiles = require('globby').sync(entry.split(','), { cwd: api.resolve('.') })
if (!resolvedFiles.length) {
abort(`entry pattern "${entry}" did not match any files.`)
}
let libName
let prefix
if (resolvedFiles.length === 1) {
// in single mode, determine the lib name from filename
libName = name || fileToComponentName('', resolvedFiles[0]).kebabName
prefix = ''
if (libName.indexOf('-') < 0) {
abort(`--name must contain a hyphen when building a single web component.`)
}
} else {
// multi mode
libName = prefix = (name || api.service.pkg.name)
if (!libName) {
abort(`--name is required when building multiple web components.`)
}
}
const dynamicEntry = resolveEntry(prefix, libName, resolvedFiles, isAsync)
function genConfig (minify, genHTML) {
const config = api.resolveChainableWebpackConfig()
// make sure not to transpile wc-wrapper
config.module
.rule('js')
.exclude
.add(/vue-wc-wrapper/)
// only minify min entry
if (!minify) {
config.optimization.minimize(false)
}
config
.plugin('webpack-virtual-modules')
.use(require('webpack-virtual-modules'), [{
[dynamicEntry.filePath]: dynamicEntry.content
}])
config
.plugin('web-component-options')
.use(webpack.DefinePlugin, [{
'process.env.CUSTOM_ELEMENT_NAME': JSON.stringify(libName)
}])
// enable shadow mode in vue-loader
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.shadowMode = true
return options
})
if (genHTML) {
config
.plugin('demo-html')
.use(require('html-webpack-plugin'), [{
template: path.resolve(__dirname, `./demo-wc.html`),
inject: false,
filename: 'demo.html',
libName,
vueMajor,
components:
prefix === ''
? [libName]
: resolvedFiles.map(file => {
return fileToComponentName(prefix, file).kebabName
})
}])
}
// set entry/output last so it takes higher priority than user
// configureWebpack hooks
// set proxy entry for *.vue files
config.resolve
.alias
.set('~root', api.resolve('.'))
const rawConfig = api.resolveWebpackConfig(config)
// externalize Vue in case user imports it
rawConfig.externals = [
...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
{ ...(inlineVue || { vue: 'Vue' }) }
].filter(Boolean)
const entryName = `${libName}${minify ? `.min` : ``}`
rawConfig.entry = {
[entryName]: dynamicEntry.filePath
}
Object.assign(rawConfig.output, {
filename: `${entryName}.js`,
chunkFilename: `${libName}.[name]${minify ? `.min` : ``}.js`,
// use dynamic publicPath so this can be deployed anywhere
// the actual path will be determined at runtime by checking
// document.currentScript.src.
publicPath: ''
})
// to ensure that multiple copies of async wc bundles can co-exist
// on the same page.
rawConfig.output.uniqueName = `vue-lib-${libName}`
return rawConfig
}
return [
genConfig(false, true),
genConfig(true, false)
]
}

View File

@ -0,0 +1,67 @@
const path = require('path')
const camelizeRE = /-(\w)/g
const camelize = str => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
}
const hyphenateRE = /\B([A-Z])/g
const hyphenate = str => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
}
/**
* Creates the script to add the component to the custom elements
* @param {string} prefix The prefix for the component library
* @param {string} component The component name for single entry builds, component file for multi-entry builds
* @param {string} file The file for the component
* @param {boolean} isAsync Whether to load component async or not
*/
const createElement = (prefix, component, file, isAsync) => {
const { camelName, kebabName } = exports.fileToComponentName(prefix, component)
return isAsync
? `window.customElements.define('${kebabName}', wrap(Vue, () => import('~root/${file}?shadow')))\n`
: `import ${camelName} from '~root/${file}?shadow'\n` +
`window.customElements.define('${kebabName}', wrap(Vue, ${camelName}))\n`
}
exports.fileToComponentName = (prefix, file) => {
const basename = path.basename(file).replace(/\.(jsx?|vue)$/, '')
const camelName = camelize(basename)
const kebabName = `${prefix ? `${prefix}-` : ``}${hyphenate(basename)}`
return {
basename,
camelName,
kebabName
}
}
exports.resolveEntry = (prefix, libName, files, isAsync) => {
const filePath = path.resolve(__dirname, 'entry-wc.js')
const elements =
prefix === ''
? [createElement('', libName, files[0])]
: files.map(file => createElement(prefix, file, file, isAsync)).join('\n')
function resolveImportPath (mod) {
return require.resolve(mod).replace(/\\/g, '\\\\')
}
const content = `
import './setPublicPath'
import Vue from 'vue'
import wrap from '@vue/web-component-wrapper'
// runtime shared by every component chunk
import '${resolveImportPath('css-loader/dist/runtime/api.js')}'
import '${resolveImportPath('vue-style-loader/lib/addStylesShadow')}'
import '${resolveImportPath('@vue/vue-loader-v15/lib/runtime/componentNormalizer')}'
${elements}`.trim()
return {
filePath: filePath,
content: content
}
}

View File

@ -0,0 +1,23 @@
/* eslint-disable no-var */
// This file is imported into lib/wc client bundles.
if (typeof window !== 'undefined') {
var currentScript = window.document.currentScript
if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {
var getCurrentScript = require('@soda/get-current-script')
currentScript = getCurrentScript()
// for backward compatibility, because previously we directly included the polyfill
if (!('currentScript' in document)) {
Object.defineProperty(document, 'currentScript', { get: getCurrentScript })
}
}
var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/)
if (src) {
__webpack_public_path__ = src[1] // eslint-disable-line
}
}
// Indicate to webpack that this file can be concatenated
export default null

View File

@ -0,0 +1,62 @@
const { chalk } = require('@vue/cli-shared-utils')
const getPadLength = require('../util/getPadLength')
module.exports = (api, options) => {
api.registerCommand('help', args => {
const commandName = args._[0]
if (!commandName) {
logMainHelp()
} else {
logHelpForCommand(commandName, api.service.commands[commandName])
}
})
function logMainHelp () {
console.log(
`\n Usage: vue-cli-service <command> [options]\n` +
`\n Commands:\n`
)
const commands = api.service.commands
const padLength = getPadLength(commands)
for (const name in commands) {
if (name !== 'help') {
const opts = commands[name].opts || {}
console.log(` ${
chalk.blue(name.padEnd(padLength))
}${
opts.description || ''
}`)
}
}
console.log(`\n run ${
chalk.green(`vue-cli-service help [command]`)
} for usage of a specific command.\n`)
}
function logHelpForCommand (name, command) {
if (!command) {
console.log(chalk.red(`\n command "${name}" does not exist.`))
} else {
const opts = command.opts || {}
if (opts.usage) {
console.log(`\n Usage: ${opts.usage}`)
}
if (opts.options) {
console.log(`\n Options:\n`)
const padLength = getPadLength(opts.options)
for (const [flags, description] of Object.entries(opts.options)) {
console.log(` ${
chalk.blue(flags.padEnd(padLength))
}${
description
}`)
}
}
if (opts.details) {
console.log()
console.log(opts.details.split('\n').map(line => ` ${line}`).join('\n'))
}
console.log()
}
}
}

View File

@ -0,0 +1,74 @@
module.exports = (api, options) => {
api.registerCommand(
'inspect',
{
description: 'inspect internal webpack config',
usage: 'vue-cli-service inspect [options] [...paths]',
options: {
'--mode': 'specify env mode (default: development)',
'--rule <ruleName>': 'inspect a specific module rule',
'--plugin <pluginName>': 'inspect a specific plugin',
'--rules': 'list all module rule names',
'--plugins': 'list all plugin names',
'--verbose': 'show full function definitions in output',
'--skip-plugins': 'comma-separated list of plugin names to skip for this run'
}
},
args => {
const { chalk, get } = require('@vue/cli-shared-utils')
const { toString } = require('webpack-chain')
const { highlight } = require('cli-highlight')
const config = api.resolveWebpackConfig()
const { _: paths, verbose } = args
let res
let hasUnnamedRule
if (args.rule) {
res = config.module.rules.find(r => r.__ruleNames[0] === args.rule)
} else if (args.plugin) {
res = config.plugins.find(p => p.__pluginName === args.plugin)
} else if (args.rules) {
res = config.module.rules.map(r => {
const name = r.__ruleNames ? r.__ruleNames[0] : 'Nameless Rule (*)'
hasUnnamedRule = hasUnnamedRule || !r.__ruleNames
return name
})
} else if (args.plugins) {
res = config.plugins.map(p => p.__pluginName || p.constructor.name)
} else if (paths.length > 1) {
res = {}
paths.forEach(path => {
res[path] = get(config, path)
})
} else if (paths.length === 1) {
res = get(config, paths[0])
} else {
res = config
}
const output = toString(res, { verbose })
console.log(highlight(output, { language: 'js' }))
// Log explanation for Nameless Rules
if (hasUnnamedRule) {
console.log(`--- ${chalk.green('Footnotes')} ---`)
console.log(`*: ${chalk.green(
'Nameless Rules'
)} were added through the ${chalk.green(
'configureWebpack()'
)} API (possibly by a plugin) instead of ${chalk.green(
'chainWebpack()'
)} (recommended).
You can run ${chalk.green(
'vue-cli-service inspect'
)} without any arguments to inspect the full config and read these rules' config.`)
}
}
)
}
module.exports.defaultModes = {
inspect: 'development'
}

View File

@ -0,0 +1,397 @@
const {
info,
error,
hasProjectYarn,
hasProjectPnpm,
IpcMessenger
} = require('@vue/cli-shared-utils')
const getBaseUrl = require('../util/getBaseUrl')
const defaults = {
host: '0.0.0.0',
port: 8080,
https: false
}
/** @type {import('@vue/cli-service').ServicePlugin} */
module.exports = (api, options) => {
const baseUrl = getBaseUrl(options)
api.registerCommand('serve', {
description: 'start development server',
usage: 'vue-cli-service serve [options] [entry]',
options: {
'--open': `open browser on server start`,
'--copy': `copy url to clipboard on server start`,
'--stdin': `close when stdin ends`,
'--mode': `specify env mode (default: development)`,
'--host': `specify host (default: ${defaults.host})`,
'--port': `specify port (default: ${defaults.port})`,
'--https': `use https (default: ${defaults.https})`,
'--public': `specify the public network URL for the HMR client`,
'--skip-plugins': `comma-separated list of plugin names to skip for this run`
}
}, async function serve (args) {
info('Starting development server...')
// although this is primarily a dev server, it is possible that we
// are running it in a mode with a production env, e.g. in E2E tests.
const isInContainer = checkInContainer()
const isProduction = process.env.NODE_ENV === 'production'
const { chalk } = require('@vue/cli-shared-utils')
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const portfinder = require('portfinder')
const prepareURLs = require('../util/prepareURLs')
const prepareProxy = require('../util/prepareProxy')
const launchEditorMiddleware = require('launch-editor-middleware')
const validateWebpackConfig = require('../util/validateWebpackConfig')
const isAbsoluteUrl = require('../util/isAbsoluteUrl')
// configs that only matters for dev server
api.chainWebpack(webpackConfig => {
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
if (!webpackConfig.get('devtool')) {
webpackConfig
.devtool('eval-cheap-module-source-map')
}
// https://github.com/webpack/webpack/issues/6642
// https://github.com/vuejs/vue-cli/issues/3539
webpackConfig
.output
.globalObject(`(typeof self !== 'undefined' ? self : this)`)
if (
!process.env.VUE_CLI_TEST &&
(!options.devServer.client ||
options.devServer.client.progress !== false)
) {
// the default progress plugin won't show progress due to infrastructreLogging.level
webpackConfig
.plugin('progress')
.use(require('progress-webpack-plugin'))
}
}
})
// resolve webpack config
const webpackConfig = api.resolveWebpackConfig()
// check for common config errors
validateWebpackConfig(webpackConfig, api, options)
// load user devServer options with higher priority than devServer
// in webpack config
const projectDevServerOptions = Object.assign(
webpackConfig.devServer || {},
options.devServer
)
// expose advanced stats
if (args.dashboard) {
const DashboardPlugin = require('../webpack/DashboardPlugin')
webpackConfig.plugins.push(new DashboardPlugin({
type: 'serve'
}))
}
// entry arg
const entry = args._[0]
if (entry) {
webpackConfig.entry = {
app: api.resolve(entry)
}
}
// resolve server options
const modesUseHttps = ['https', 'http2']
const serversUseHttps = ['https', 'spdy']
const optionsUseHttps = modesUseHttps.some(modeName => !!projectDevServerOptions[modeName]) ||
(typeof projectDevServerOptions.server === 'string' && serversUseHttps.includes(projectDevServerOptions.server)) ||
(typeof projectDevServerOptions.server === 'object' && projectDevServerOptions.server !== null && serversUseHttps.includes(projectDevServerOptions.server.type))
const useHttps = args.https || optionsUseHttps || defaults.https
const protocol = useHttps ? 'https' : 'http'
const host = args.host || process.env.HOST || projectDevServerOptions.host || defaults.host
portfinder.basePort = args.port || process.env.PORT || projectDevServerOptions.port || defaults.port
const port = await portfinder.getPortPromise()
const rawPublicUrl = args.public || projectDevServerOptions.public
const publicUrl = rawPublicUrl
? /^[a-zA-Z]+:\/\//.test(rawPublicUrl)
? rawPublicUrl
: `${protocol}://${rawPublicUrl}`
: null
const publicHost = publicUrl ? /^[a-zA-Z]+:\/\/([^/?#]+)/.exec(publicUrl)[1] : undefined
const urls = prepareURLs(
protocol,
host,
port,
isAbsoluteUrl(baseUrl) ? '/' : baseUrl
)
const localUrlForBrowser = publicUrl || urls.localUrlForBrowser
const proxySettings = prepareProxy(
projectDevServerOptions.proxy,
api.resolve('public')
)
// inject dev & hot-reload middleware entries
let webSocketURL
if (!isProduction) {
if (publicHost) {
// explicitly configured via devServer.public
webSocketURL = {
protocol: protocol === 'https' ? 'wss' : 'ws',
hostname: publicHost,
port
}
} else if (isInContainer) {
// can't infer public network url if inside a container
// infer it from the browser instead
webSocketURL = 'auto://0.0.0.0:0/ws'
} else {
// otherwise infer the url from the config
webSocketURL = {
protocol: protocol === 'https' ? 'wss' : 'ws',
hostname: urls.lanUrlForConfig || 'localhost',
port
}
}
if (process.env.APPVEYOR) {
webpackConfig.plugins.push(
new webpack.EntryPlugin(__dirname, 'webpack/hot/poll?500', { name: undefined })
)
}
}
const { projectTargets } = require('../util/targets')
const supportsIE = !!projectTargets
if (supportsIE) {
webpackConfig.plugins.push(
// must use undefined as name,
// to avoid dev server establishing an extra ws connection for the new entry
new webpack.EntryPlugin(__dirname, 'whatwg-fetch', { name: undefined })
)
}
// fixme: temporary fix to suppress dev server logging
// should be more robust to show necessary info but not duplicate errors
webpackConfig.infrastructureLogging = { ...webpackConfig.infrastructureLogging, level: 'none' }
webpackConfig.stats = 'errors-only'
// create compiler
const compiler = webpack(webpackConfig)
// handle compiler error
compiler.hooks.failed.tap('vue-cli-service serve', msg => {
error(msg)
process.exit(1)
})
// create server
const server = new WebpackDevServer(Object.assign({
historyApiFallback: {
disableDotRule: true,
htmlAcceptHeaders: [
'text/html',
'application/xhtml+xml'
],
rewrites: genHistoryApiFallbackRewrites(baseUrl, options.pages)
},
hot: !isProduction
}, projectDevServerOptions, {
host,
port,
server: {
type: protocol,
...(typeof projectDevServerOptions.server === 'object'
? projectDevServerOptions.server
: {})
},
proxy: proxySettings,
static: {
directory: api.resolve('public'),
publicPath: options.publicPath,
watch: !isProduction,
...projectDevServerOptions.static
},
client: {
webSocketURL,
logging: 'none',
overlay: isProduction // TODO disable this
? false
: { warnings: false, errors: true },
progress: !process.env.VUE_CLI_TEST,
...projectDevServerOptions.client
},
open: args.open || projectDevServerOptions.open,
setupExitSignals: true,
setupMiddlewares (middlewares, devServer) {
// launch editor support.
// this works with vue-devtools & @vue/cli-overlay
devServer.app.use('/__open-in-editor', launchEditorMiddleware(() => console.log(
`To specify an editor, specify the EDITOR env variable or ` +
`add "editor" field to your Vue project config.\n`
)))
// allow other plugins to register middlewares, e.g. PWA
// todo: migrate to the new API interface
api.service.devServerConfigFns.forEach(fn => fn(devServer.app, devServer))
if (projectDevServerOptions.setupMiddlewares) {
return projectDevServerOptions.setupMiddlewares(middlewares, devServer)
}
return middlewares
}
}), compiler)
if (args.stdin) {
process.stdin.on('end', () => {
server.stopCallback(() => {
process.exit(0)
})
})
process.stdin.resume()
}
// on appveyor, killing the process with SIGTERM causes execa to
// throw error
if (process.env.VUE_CLI_TEST) {
process.stdin.on('data', data => {
if (data.toString() === 'close') {
console.log('got close signal!')
server.stopCallback(() => {
process.exit(0)
})
}
})
}
return new Promise((resolve, reject) => {
// log instructions & open browser on first compilation complete
let isFirstCompile = true
compiler.hooks.done.tap('vue-cli-service serve', stats => {
if (stats.hasErrors()) {
return
}
let copied = ''
if (isFirstCompile && args.copy) {
try {
require('clipboardy').writeSync(localUrlForBrowser)
copied = chalk.dim('(copied to clipboard)')
} catch (_) {
/* catch exception if copy to clipboard isn't supported (e.g. WSL), see issue #3476 */
}
}
const networkUrl = publicUrl
? publicUrl.replace(/([^/])$/, '$1/')
: urls.lanUrlForTerminal
console.log()
console.log(` App running at:`)
console.log(` - Local: ${chalk.cyan(urls.localUrlForTerminal)} ${copied}`)
if (!isInContainer) {
console.log(` - Network: ${chalk.cyan(networkUrl)}`)
} else {
console.log()
console.log(chalk.yellow(` It seems you are running Vue CLI inside a container.`))
if (!publicUrl && options.publicPath && options.publicPath !== '/') {
console.log()
console.log(chalk.yellow(` Since you are using a non-root publicPath, the hot-reload socket`))
console.log(chalk.yellow(` will not be able to infer the correct URL to connect. You should`))
console.log(chalk.yellow(` explicitly specify the URL via ${chalk.blue(`devServer.public`)}.`))
console.log()
}
console.log(chalk.yellow(` Access the dev server via ${chalk.cyan(
`${protocol}://localhost:<your container's external mapped port>${options.publicPath}`
)}`))
}
console.log()
if (isFirstCompile) {
isFirstCompile = false
if (!isProduction) {
const buildCommand = hasProjectYarn(api.getCwd()) ? `yarn build` : hasProjectPnpm(api.getCwd()) ? `pnpm run build` : `npm run build`
console.log(` Note that the development build is not optimized.`)
console.log(` To create a production build, run ${chalk.cyan(buildCommand)}.`)
} else {
console.log(` App is served in production mode.`)
console.log(` Note this is for preview or E2E testing only.`)
}
console.log()
// Send final app URL
if (args.dashboard) {
const ipc = new IpcMessenger()
ipc.send({
vueServe: {
url: localUrlForBrowser
}
})
}
// resolve returned Promise
// so other commands can do api.service.run('serve').then(...)
resolve({
server,
url: localUrlForBrowser
})
} else if (process.env.VUE_CLI_TEST) {
// signal for test to check HMR
console.log('App updated')
}
})
server.start().catch(err => reject(err))
})
})
}
// https://stackoverflow.com/a/20012536
function checkInContainer () {
if ('CODESANDBOX_SSE' in process.env) {
return true
}
const fs = require('fs')
if (fs.existsSync(`/proc/1/cgroup`)) {
const content = fs.readFileSync(`/proc/1/cgroup`, 'utf-8')
return /:\/(lxc|docker|kubepods(\.slice)?)\//.test(content)
}
}
function genHistoryApiFallbackRewrites (baseUrl, pages = {}) {
const path = require('path')
const multiPageRewrites = Object
.keys(pages)
// sort by length in reversed order to avoid overrides
// eg. 'page11' should appear in front of 'page1'
.sort((a, b) => b.length - a.length)
.map(name => ({
from: new RegExp(`^/${name}`),
to: path.posix.join(baseUrl, pages[name].filename || `${name}.html`)
}))
return [
...multiPageRewrites,
{ from: /./, to: path.posix.join(baseUrl, 'index.html') }
]
}
module.exports.defaultModes = {
serve: 'development'
}

269
app_vue/node_modules/@vue/cli-service/lib/config/app.js generated vendored Normal file
View File

@ -0,0 +1,269 @@
// config that are specific to --target app
const fs = require('fs')
const path = require('path')
// ensure the filename passed to html-webpack-plugin is a relative path
// because it cannot correctly handle absolute paths
function ensureRelative (outputDir, _path) {
if (path.isAbsolute(_path)) {
return path.relative(outputDir, _path)
} else {
return _path
}
}
module.exports = (api, options) => {
api.chainWebpack(webpackConfig => {
// only apply when there's no alternative target
if (process.env.VUE_CLI_BUILD_TARGET && process.env.VUE_CLI_BUILD_TARGET !== 'app') {
return
}
const isProd = process.env.NODE_ENV === 'production'
const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILD
const outputDir = api.resolve(options.outputDir)
const getAssetPath = require('../util/getAssetPath')
const outputFilename = getAssetPath(
options,
`js/[name]${isLegacyBundle ? `-legacy` : ``}${isProd && options.filenameHashing ? '.[contenthash:8]' : ''}.js`
)
webpackConfig
.output
.filename(outputFilename)
.chunkFilename(outputFilename)
// FIXME: a temporary workaround to get accurate contenthash in `applyLegacy`
// Should use a better fix per discussions at <https://github.com/jantimon/html-webpack-plugin/issues/1554#issuecomment-753653580>
webpackConfig.optimization
.set('realContentHash', false)
// code splitting
if (process.env.NODE_ENV !== 'test') {
webpackConfig.optimization.splitChunks({
cacheGroups: {
defaultVendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
})
}
// HTML plugin
const resolveClientEnv = require('../util/resolveClientEnv')
const htmlOptions = {
title: api.service.pkg.name,
scriptLoading: 'defer',
templateParameters: (compilation, assets, assetTags, pluginOptions) => {
// enhance html-webpack-plugin's built in template params
return Object.assign({
compilation: compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
tags: assetTags,
files: assets,
options: pluginOptions
}
}, resolveClientEnv(options, true /* raw */))
}
}
// handle indexPath
if (options.indexPath !== 'index.html') {
// why not set filename for html-webpack-plugin?
// 1. It cannot handle absolute paths
// 2. Relative paths causes incorrect SW manifest to be generated (#2007)
webpackConfig
.plugin('move-index')
.use(require('../webpack/MovePlugin'), [
path.resolve(outputDir, 'index.html'),
path.resolve(outputDir, options.indexPath)
])
}
// resolve HTML file(s)
const HTMLPlugin = require('html-webpack-plugin')
// const PreloadPlugin = require('@vue/preload-webpack-plugin')
const multiPageConfig = options.pages
const htmlPath = api.resolve('public/index.html')
const defaultHtmlPath = path.resolve(__dirname, 'index-default.html')
const publicCopyIgnore = ['**/.DS_Store']
if (!multiPageConfig) {
// default, single page setup.
htmlOptions.template = fs.existsSync(htmlPath)
? htmlPath
: defaultHtmlPath
publicCopyIgnore.push(api.resolve(htmlOptions.template).replace(/\\/g, '/'))
webpackConfig
.plugin('html')
.use(HTMLPlugin, [htmlOptions])
// FIXME: need to test out preload plugin's compatibility with html-webpack-plugin 4/5
// if (!isLegacyBundle) {
// // inject preload/prefetch to HTML
// webpackConfig
// .plugin('preload')
// .use(PreloadPlugin, [{
// rel: 'preload',
// include: 'initial',
// fileBlacklist: [/\.map$/, /hot-update\.js$/]
// }])
// webpackConfig
// .plugin('prefetch')
// .use(PreloadPlugin, [{
// rel: 'prefetch',
// include: 'asyncChunks'
// }])
// }
} else {
// multi-page setup
webpackConfig.entryPoints.clear()
const pages = Object.keys(multiPageConfig)
const normalizePageConfig = c => typeof c === 'string' ? { entry: c } : c
pages.forEach(name => {
const pageConfig = normalizePageConfig(multiPageConfig[name])
const {
entry,
template = `public/${name}.html`,
filename = `${name}.html`,
chunks = ['chunk-vendors', 'chunk-common', name]
} = pageConfig
// Currently Cypress v3.1.0 comes with a very old version of Node,
// which does not support object rest syntax.
// (https://github.com/cypress-io/cypress/issues/2253)
// So here we have to extract the customHtmlOptions manually.
const customHtmlOptions = {}
for (const key in pageConfig) {
if (
!['entry', 'template', 'filename', 'chunks'].includes(key)
) {
customHtmlOptions[key] = pageConfig[key]
}
}
// inject entry
const entries = Array.isArray(entry) ? entry : [entry]
webpackConfig.entry(name).merge(entries.map(e => api.resolve(e)))
// trim inline loader
// * See https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md#2-setting-a-loader-directly-for-the-template
const templateWithoutLoader = template.replace(/^.+!/, '').replace(/\?.+$/, '')
// resolve page index template
const hasDedicatedTemplate = fs.existsSync(api.resolve(templateWithoutLoader))
const templatePath = hasDedicatedTemplate
? template
: fs.existsSync(htmlPath)
? htmlPath
: defaultHtmlPath
publicCopyIgnore.push(api.resolve(templateWithoutLoader).replace(/\\/g, '/'))
// inject html plugin for the page
const pageHtmlOptions = Object.assign(
{},
htmlOptions,
{
chunks,
template: templatePath,
filename: ensureRelative(outputDir, filename)
},
customHtmlOptions
)
webpackConfig
.plugin(`html-${name}`)
.use(HTMLPlugin, [pageHtmlOptions])
})
// FIXME: preload plugin is not compatible with webpack 5 / html-webpack-plugin 4 yet
// if (!isLegacyBundle) {
// pages.forEach(name => {
// const filename = ensureRelative(
// outputDir,
// normalizePageConfig(multiPageConfig[name]).filename || `${name}.html`
// )
// webpackConfig
// .plugin(`preload-${name}`)
// .use(PreloadPlugin, [{
// rel: 'preload',
// includeHtmlNames: [filename],
// include: {
// type: 'initial',
// entries: [name]
// },
// fileBlacklist: [/\.map$/, /hot-update\.js$/]
// }])
// webpackConfig
// .plugin(`prefetch-${name}`)
// .use(PreloadPlugin, [{
// rel: 'prefetch',
// includeHtmlNames: [filename],
// include: {
// type: 'asyncChunks',
// entries: [name]
// }
// }])
// })
// }
}
// CORS and Subresource Integrity
if (options.crossorigin != null || options.integrity) {
webpackConfig
.plugin('cors')
.use(require('../webpack/CorsPlugin'), [{
crossorigin: options.crossorigin,
integrity: options.integrity,
publicPath: options.publicPath
}])
}
// copy static assets in public/
const publicDir = api.resolve('public')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const PlaceholderPlugin = class PlaceholderPlugin { apply () {} }
const copyOptions = {
patterns: [{
from: publicDir,
to: outputDir,
toType: 'dir',
noErrorOnMissing: true,
globOptions: {
ignore: publicCopyIgnore
},
info: {
minimized: true
}
}]
}
if (fs.existsSync(publicDir)) {
if (isLegacyBundle) {
webpackConfig.plugin('copy').use(PlaceholderPlugin, [copyOptions])
} else {
webpackConfig.plugin('copy').use(CopyWebpackPlugin, [copyOptions])
}
}
})
}

View File

@ -0,0 +1,47 @@
/** @type {import('@vue/cli-service').ServicePlugin} */
module.exports = (api, options) => {
const getAssetPath = require('../util/getAssetPath')
const genAssetSubPath = dir => {
return getAssetPath(
options,
`${dir}/[name]${options.filenameHashing ? '.[hash:8]' : ''}[ext]`
)
}
api.chainWebpack(webpackConfig => {
webpackConfig.module
.rule('svg')
.test(/\.(svg)(\?.*)?$/)
// do not base64-inline SVGs.
// https://github.com/facebookincubator/create-react-app/pull/1180
.set('type', 'asset/resource')
.set('generator', {
filename: genAssetSubPath('img')
})
webpackConfig.module
.rule('images')
.test(/\.(png|jpe?g|gif|webp|avif)(\?.*)?$/)
.set('type', 'asset')
.set('generator', {
filename: genAssetSubPath('img')
})
webpackConfig.module
.rule('media')
.test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
.set('type', 'asset')
.set('generator', {
filename: genAssetSubPath('media')
})
webpackConfig.module
.rule('fonts')
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
.set('type', 'asset')
.set('generator', {
filename: genAssetSubPath('fonts')
})
})
}

View File

@ -0,0 +1,226 @@
const path = require('path')
/** @type {import('@vue/cli-service').ServicePlugin} */
module.exports = (api, options) => {
const cwd = api.getCwd()
const webpack = require('webpack')
const vueMajor = require('../util/getVueMajor')(cwd)
api.chainWebpack(webpackConfig => {
const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILD
const resolveLocal = require('../util/resolveLocal')
// https://github.com/webpack/webpack/issues/14532#issuecomment-947525539
webpackConfig.output.set('hashFunction', 'xxhash64')
// https://github.com/webpack/webpack/issues/11467#issuecomment-691873586
webpackConfig.module
.rule('esm')
.test(/\.m?jsx?$/)
.resolve.set('fullySpecified', false)
webpackConfig
.mode('development')
.context(api.service.context)
.entry('app')
.add('./src/main.js')
.end()
.output
.path(api.resolve(options.outputDir))
.filename(isLegacyBundle ? '[name]-legacy.js' : '[name].js')
.publicPath(options.publicPath)
webpackConfig.resolve
.extensions
.merge(['.mjs', '.js', '.jsx', '.vue', '.json', '.wasm'])
.end()
.modules
.add('node_modules')
.add(api.resolve('node_modules'))
.add(resolveLocal('node_modules'))
.end()
.alias
.set('@', api.resolve('src'))
webpackConfig.resolveLoader
.modules
.add('node_modules')
.add(api.resolve('node_modules'))
.add(resolveLocal('node_modules'))
webpackConfig.module
.noParse(/^(vue|vue-router|vuex|vuex-router-sync)$/)
// js is handled by cli-plugin-babel ---------------------------------------
// vue-loader --------------------------------------------------------------
let cacheLoaderPath
try {
cacheLoaderPath = require.resolve('cache-loader')
} catch (e) {}
if (vueMajor === 2) {
// for Vue 2 projects
const partialIdentifier = {
'vue-loader': require('@vue/vue-loader-v15/package.json').version,
'@vue/component-compiler-utils': require('@vue/component-compiler-utils/package.json').version
}
try {
partialIdentifier['vue-template-compiler'] = require('vue-template-compiler/package.json').version
} catch (e) {
// For Vue 2.7 projects, `vue-template-compiler` is not required
}
const vueLoaderCacheConfig = api.genCacheConfig('vue-loader', partialIdentifier)
webpackConfig.resolve
.alias
.set(
'vue$',
options.runtimeCompiler
? 'vue/dist/vue.esm.js'
: 'vue/dist/vue.runtime.esm.js'
)
if (cacheLoaderPath) {
webpackConfig.module
.rule('vue')
.test(/\.vue$/)
.use('cache-loader')
.loader(cacheLoaderPath)
.options(vueLoaderCacheConfig)
}
webpackConfig.module
.rule('vue')
.test(/\.vue$/)
.use('vue-loader')
.loader(require.resolve('@vue/vue-loader-v15'))
.options(Object.assign({
compilerOptions: {
whitespace: 'condense'
}
}, cacheLoaderPath ? vueLoaderCacheConfig : {}))
webpackConfig
.plugin('vue-loader')
.use(require('@vue/vue-loader-v15').VueLoaderPlugin)
// some plugins may implicitly relies on the `vue-loader` dependency path name
// such as vue-cli-plugin-apollo
// <https://github.com/Akryum/vue-cli-plugin-apollo/blob/d9fe48c61cc19db88fef4e4aa5e49b31aa0c44b7/index.js#L88>
// so we need a hotfix for that
webpackConfig
.resolveLoader
.modules
.prepend(path.resolve(__dirname, './vue-loader-v15-resolve-compat'))
} else if (vueMajor === 3) {
// for Vue 3 projects
const vueLoaderCacheConfig = api.genCacheConfig('vue-loader', {
'vue-loader': require('vue-loader/package.json').version
})
webpackConfig.resolve
.alias
.set(
'vue$',
options.runtimeCompiler
? 'vue/dist/vue.esm-bundler.js'
: 'vue/dist/vue.runtime.esm-bundler.js'
)
if (cacheLoaderPath) {
webpackConfig.module
.rule('vue')
.test(/\.vue$/)
.use('cache-loader')
.loader(cacheLoaderPath)
.options(vueLoaderCacheConfig)
}
webpackConfig.module
.rule('vue')
.test(/\.vue$/)
.use('vue-loader')
.loader(require.resolve('vue-loader'))
.options({
...vueLoaderCacheConfig,
babelParserPlugins: ['jsx', 'classProperties', 'decorators-legacy']
})
webpackConfig
.plugin('vue-loader')
.use(require('vue-loader').VueLoaderPlugin)
// feature flags <http://link.vuejs.org/feature-flags>
webpackConfig
.plugin('feature-flags')
.use(webpack.DefinePlugin, [{
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false'
}])
}
// https://github.com/vuejs/vue-loader/issues/1435#issuecomment-869074949
webpackConfig.module
.rule('vue-style')
.test(/\.vue$/)
.resourceQuery(/type=style/)
.sideEffects(true)
// Other common pre-processors ---------------------------------------------
const maybeResolve = name => {
try {
return require.resolve(name)
} catch (error) {
return name
}
}
webpackConfig.module
.rule('pug')
.test(/\.pug$/)
.oneOf('pug-vue')
.resourceQuery(/vue/)
.use('pug-plain-loader')
.loader(maybeResolve('pug-plain-loader'))
.end()
.end()
.oneOf('pug-template')
.use('raw')
.loader(maybeResolve('raw-loader'))
.end()
.use('pug-plain-loader')
.loader(maybeResolve('pug-plain-loader'))
.end()
.end()
const resolveClientEnv = require('../util/resolveClientEnv')
webpackConfig
.plugin('define')
.use(webpack.DefinePlugin, [
resolveClientEnv(options)
])
webpackConfig
.plugin('case-sensitive-paths')
.use(require('case-sensitive-paths-webpack-plugin'))
// friendly error plugin displays very confusing errors when webpack
// fails to resolve a loader, so we provide custom handlers to improve it
const { transformer, formatter } = require('../util/resolveLoaderError')
webpackConfig
.plugin('friendly-errors')
.use(require('@soda/friendly-errors-webpack-plugin'), [{
additionalTransformers: [transformer],
additionalFormatters: [formatter]
}])
const TerserPlugin = require('terser-webpack-plugin')
const terserOptions = require('./terserOptions')
webpackConfig.optimization
.minimizer('terser')
.use(TerserPlugin, [terserOptions(options)])
})
}

234
app_vue/node_modules/@vue/cli-service/lib/config/css.js generated vendored Normal file
View File

@ -0,0 +1,234 @@
const fs = require('fs')
const path = require('path')
const { chalk, semver, loadModule } = require('@vue/cli-shared-utils')
const isAbsoluteUrl = require('../util/isAbsoluteUrl')
const findExisting = (context, files) => {
for (const file of files) {
if (fs.existsSync(path.join(context, file))) {
return file
}
}
}
module.exports = (api, rootOptions) => {
api.chainWebpack(webpackConfig => {
const getAssetPath = require('../util/getAssetPath')
const shadowMode = !!process.env.VUE_CLI_CSS_SHADOW_MODE
const isProd = process.env.NODE_ENV === 'production'
const {
extract = isProd,
sourceMap = false,
loaderOptions = {}
} = rootOptions.css || {}
const shouldExtract = extract !== false && !shadowMode
const filename = getAssetPath(
rootOptions,
`css/[name]${rootOptions.filenameHashing ? '.[contenthash:8]' : ''}.css`
)
const extractOptions = Object.assign({
filename,
chunkFilename: filename
}, extract && typeof extract === 'object' ? extract : {})
// when project publicPath is a relative path
// use relative publicPath in extracted CSS based on extract location
const cssPublicPath = (isAbsoluteUrl(rootOptions.publicPath) || rootOptions.publicPath.startsWith('/'))
? rootOptions.publicPath
: process.env.VUE_CLI_BUILD_TARGET === 'lib'
// in lib mode, CSS is extracted to dist root.
? './'
: '../'.repeat(
extractOptions.filename
.replace(/^\.[/\\]/, '')
.split(/[/\\]/g)
.length - 1
)
// check if the project has a valid postcss config
// if it doesn't, don't use postcss-loader for direct style imports
// because otherwise it would throw error when attempting to load postcss config
const hasPostCSSConfig = !!(loaderOptions.postcss || api.service.pkg.postcss || findExisting(api.resolve('.'), [
'.postcssrc',
'.postcssrc.js',
'postcss.config.js',
'.postcssrc.yaml',
'.postcssrc.json'
]))
if (!hasPostCSSConfig) {
// #6342
// NPM 6 may incorrectly hoist postcss 7 to the same level of autoprefixer
// So we have to run a preflight check to tell the users how to fix it
const autoprefixerDirectory = path.dirname(require.resolve('autoprefixer/package.json'))
const postcssPkg = loadModule('postcss/package.json', autoprefixerDirectory)
const postcssVersion = postcssPkg.version
if (!semver.satisfies(postcssVersion, '8.x')) {
throw new Error(
`The package manager has hoisted a wrong version of ${chalk.cyan('postcss')}, ` +
`please run ${chalk.cyan('npm i postcss@8 -D')} to fix it.`
)
}
loaderOptions.postcss = {
postcssOptions: {
plugins: [
require('autoprefixer')
]
}
}
}
// if building for production but not extracting CSS, we need to minimize
// the embbeded inline CSS as they will not be going through the optimizing
// plugin.
const needInlineMinification = isProd && !shouldExtract
const cssnanoOptions = {
preset: ['default', {
mergeLonghand: false,
cssDeclarationSorter: false
}]
}
if (rootOptions.productionSourceMap && sourceMap) {
cssnanoOptions.map = { inline: false }
}
function createCSSRule (lang, test, loader, options) {
const baseRule = webpackConfig.module.rule(lang).test(test)
// rules for <style module>
const vueModulesRule = baseRule.oneOf('vue-modules').resourceQuery(/module/)
applyLoaders(vueModulesRule, true)
// rules for <style>
const vueNormalRule = baseRule.oneOf('vue').resourceQuery(/\?vue/)
applyLoaders(vueNormalRule)
// rules for *.module.* files
const extModulesRule = baseRule.oneOf('normal-modules').test(/\.module\.\w+$/)
applyLoaders(extModulesRule)
// rules for normal CSS imports
const normalRule = baseRule.oneOf('normal')
applyLoaders(normalRule)
function applyLoaders (rule, forceCssModule = false) {
if (shouldExtract) {
rule
.use('extract-css-loader')
.loader(require('mini-css-extract-plugin').loader)
.options({
publicPath: cssPublicPath
})
} else {
rule
.use('vue-style-loader')
.loader(require.resolve('vue-style-loader'))
.options({
sourceMap,
shadowMode
})
}
const cssLoaderOptions = Object.assign({
sourceMap,
importLoaders: (
1 + // stylePostLoader injected by vue-loader
1 + // postcss-loader
(needInlineMinification ? 1 : 0)
)
}, loaderOptions.css)
if (forceCssModule) {
cssLoaderOptions.modules = {
...cssLoaderOptions.modules,
auto: () => true
}
}
if (cssLoaderOptions.modules) {
cssLoaderOptions.modules = {
localIdentName: '[name]_[local]_[hash:base64:5]',
...cssLoaderOptions.modules
}
}
rule
.use('css-loader')
.loader(require.resolve('css-loader'))
.options(cssLoaderOptions)
if (needInlineMinification) {
rule
.use('cssnano')
.loader(require.resolve('postcss-loader'))
.options({
sourceMap,
postcssOptions: {
plugins: [require('cssnano')(cssnanoOptions)]
}
})
}
rule
.use('postcss-loader')
.loader(require.resolve('postcss-loader'))
.options(Object.assign({ sourceMap }, loaderOptions.postcss))
if (loader) {
let resolvedLoader
try {
resolvedLoader = require.resolve(loader)
} catch (error) {
resolvedLoader = loader
}
rule
.use(loader)
.loader(resolvedLoader)
.options(Object.assign({ sourceMap }, options))
}
}
}
createCSSRule('css', /\.css$/)
createCSSRule('postcss', /\.p(ost)?css$/)
createCSSRule('scss', /\.scss$/, 'sass-loader', Object.assign(
{},
loaderOptions.scss || loaderOptions.sass
))
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign(
{},
loaderOptions.sass,
{
sassOptions: Object.assign(
{},
loaderOptions.sass && loaderOptions.sass.sassOptions,
{
indentedSyntax: true
}
)
}
))
createCSSRule('less', /\.less$/, 'less-loader', loaderOptions.less)
createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', loaderOptions.stylus)
// inject CSS extraction plugin
if (shouldExtract) {
webpackConfig
.plugin('extract-css')
.use(require('mini-css-extract-plugin'), [extractOptions])
// minify extracted CSS
webpackConfig.optimization
.minimizer('css')
.use(require('css-minimizer-webpack-plugin'), [{
parallel: rootOptions.parallel,
minimizerOptions: cssnanoOptions
}])
}
})
}

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Vue App</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1,15 @@
/** @type {import('@vue/cli-service').ServicePlugin} */
module.exports = (api, options) => {
api.chainWebpack(webpackConfig => {
if (process.env.NODE_ENV === 'production') {
webpackConfig
.mode('production')
.devtool(options.productionSourceMap ? 'source-map' : false)
// disable optimization during tests to speed things up
if (process.env.VUE_CLI_TEST && !process.env.VUE_CLI_TEST_MINIMIZE) {
webpackConfig.optimization.minimize(false)
}
}
})
}

View File

@ -0,0 +1,110 @@
// @ts-check
const TerserPlugin = require('terser-webpack-plugin')
const genTerserOptions = (defaultOptions, options) => {
const userOptions = options.terser && options.terser.terserOptions
// user's config is first
return {
...defaultOptions,
...userOptions
}
}
const terserMinify = (options) => ({
terserOptions: genTerserOptions(
{
compress: {
// turn off flags with small gains to speed up minification
arrows: false,
collapse_vars: false, // 0.3kb
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
// a few flags with noticeable gains/speed ratio
// numbers based on out of the box vendor bundle
booleans: true, // 0.7kb
if_return: true, // 0.4kb
sequences: true, // 0.7kb
unused: true, // 2.3kb
// required features to drop conditional branches
conditionals: true,
dead_code: true,
evaluate: true
},
mangle: {
safari10: true
}
},
options
),
parallel: options.parallel,
extractComments: false
})
// `terserOptions` options will be passed to `esbuild`
// Link to options - https://esbuild.github.io/api/#minify
const esbuildMinify = (options) => ({
minify: TerserPlugin.esbuildMinify,
terserOptions: genTerserOptions(
{
minify: false,
minifyWhitespace: true,
minifyIdentifiers: false,
minifySyntax: true
},
options
),
parallel: options.parallel
})
// `terserOptions` options will be passed to `swc` (`@swc/core`)
// Link to options - https://swc.rs/docs/config-js-minify
const swcMinify = (options) => ({
minify: TerserPlugin.swcMinify,
terserOptions: genTerserOptions(
{
compress: {
unused: true
},
mangle: true
},
options
),
parallel: options.parallel
})
// `terserOptions` options will be passed to `uglify-js`
// Link to options - https://github.com/mishoo/UglifyJS#minify-options
const uglifyJsMinify = (options) => ({
minify: TerserPlugin.uglifyJsMinify,
terserOptions: genTerserOptions({}, options),
parallel: options.parallel
})
// Currently we do not allow custom minify function
const getMinify = (options) => {
const { minify = 'terser' } = options.terser || {}
const minifyMap = {
terser: terserMinify,
esbuild: esbuildMinify,
swc: swcMinify,
uglifyJs: uglifyJsMinify
}
return minifyMap[minify](options)
}
module.exports = getMinify

View File

@ -0,0 +1 @@
module.exports = require('@vue/vue-loader-v15')

147
app_vue/node_modules/@vue/cli-service/lib/options.js generated vendored Normal file
View File

@ -0,0 +1,147 @@
const { createSchema, validate } = require('@vue/cli-shared-utils')
const schema = createSchema(joi => joi.object({
publicPath: joi.string().allow(''),
outputDir: joi.string(),
assetsDir: joi.string().allow(''),
indexPath: joi.string(),
filenameHashing: joi.boolean(),
runtimeCompiler: joi.boolean(),
transpileDependencies: joi.alternatives().try(
joi.boolean(),
joi.array()
),
productionSourceMap: joi.boolean(),
parallel: joi.alternatives().try(
joi.boolean(),
joi.number().integer()
),
devServer: joi.object(),
pages: joi.object().pattern(
/\w+/,
joi.alternatives().try(
joi.string().required(),
joi.array().items(joi.string().required()),
joi.object().keys({
entry: joi.alternatives().try(
joi.string().required(),
joi.array().items(joi.string().required())
).required()
}).unknown(true)
)
),
crossorigin: joi.string().valid('', 'anonymous', 'use-credentials'),
integrity: joi.boolean(),
// css
css: joi.object({
extract: joi.alternatives().try(joi.boolean(), joi.object()),
sourceMap: joi.boolean(),
loaderOptions: joi.object({
css: joi.object(),
sass: joi.object(),
scss: joi.object(),
less: joi.object(),
stylus: joi.object(),
postcss: joi.object()
})
}),
// webpack
chainWebpack: joi.func(),
configureWebpack: joi.alternatives().try(
joi.object(),
joi.func()
),
// known runtime options for built-in plugins
lintOnSave: joi.any().valid(true, false, 'error', 'warning', 'default'),
pwa: joi.object(),
// terser
terser: joi.object({
minify: joi.string().valid('terser', 'esbuild', 'swc', 'uglifyJs'),
terserOptions: joi.object()
}),
// 3rd party plugin options
pluginOptions: joi.object()
}))
exports.validate = (options, cb) => {
validate(options, schema, cb)
}
// #2110
// https://github.com/nodejs/node/issues/19022
// in some cases cpus() returns undefined, and may simply throw in the future
function hasMultipleCores () {
try {
return require('os').cpus().length > 1
} catch (e) {
return false
}
}
exports.defaults = () => ({
// project deployment base
publicPath: '/',
// where to output built files
outputDir: 'dist',
// where to put static assets (js/css/img/font/...)
assetsDir: '',
// filename for index.html (relative to outputDir)
indexPath: 'index.html',
// whether filename will contain hash part
filenameHashing: true,
// boolean, use full build?
runtimeCompiler: false,
// whether to transpile all dependencies
transpileDependencies: false,
// sourceMap for production build?
productionSourceMap: !process.env.VUE_CLI_TEST,
// use thread-loader for babel & TS in production build
// enabled by default if the machine has more than 1 cores
parallel: hasMultipleCores(),
// multi-page config
pages: undefined,
// <script type="module" crossorigin="use-credentials">
// #1656, #1867, #2025
crossorigin: undefined,
// subresource integrity
integrity: false,
css: {
// extract: true,
// modules: false,
// sourceMap: false,
// loaderOptions: {}
},
// whether to use eslint-loader
lintOnSave: 'default',
devServer: {
/*
open: process.platform === 'darwin',
host: '0.0.0.0',
port: 8080,
https: false,
hotOnly: false,
proxy: null, // string | Object
before: app => {}
*/
}
})

View File

@ -0,0 +1,7 @@
const path = require('path')
module.exports = function getAssetPath (options, filePath) {
return options.assetsDir
? path.posix.join(options.assetsDir, filePath)
: filePath
}

View File

@ -0,0 +1,3 @@
module.exports = function getBaseUrl (options) {
return options.publicPath === 'auto' ? '' : options.publicPath
}

View File

@ -0,0 +1,9 @@
module.exports = function getPadLength (obj) {
let longest = 10
for (const name in obj) {
if (name.length + 1 > longest) {
longest = name.length + 1
}
}
return longest
}

View File

@ -0,0 +1,13 @@
const { semver, loadModule } = require('@vue/cli-shared-utils')
/**
* Get the major Vue version that the user project uses
* @param {string} cwd the user project root
* @returns {2|3}
*/
module.exports = function getVueMajor (cwd) {
const vue = loadModule('vue', cwd)
// TODO: make Vue 3 the default version
const vueMajor = vue ? semver.major(vue.version) : 2
return vueMajor
}

View File

@ -0,0 +1,4 @@
module.exports = function isAbsoluteUrl (url) {
// A URL is considered absolute if it begins with "<scheme>://" or "//"
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
}

View File

@ -0,0 +1,38 @@
const fs = require('fs')
const path = require('path')
const { pathToFileURL } = require('url')
const isFileEsm = require('is-file-esm')
const { loadModule } = require('@vue/cli-shared-utils')
module.exports = function loadFileConfig (context) {
let fileConfig, fileConfigPath
const possibleConfigPaths = [
process.env.VUE_CLI_SERVICE_CONFIG_PATH,
'./vue.config.js',
'./vue.config.cjs',
'./vue.config.mjs'
]
for (const p of possibleConfigPaths) {
const resolvedPath = p && path.resolve(context, p)
if (resolvedPath && fs.existsSync(resolvedPath)) {
fileConfigPath = resolvedPath
break
}
}
if (fileConfigPath) {
const { esm } = isFileEsm.sync(fileConfigPath)
if (esm) {
fileConfig = import(pathToFileURL(fileConfigPath))
} else {
fileConfig = loadModule(fileConfigPath, context)
}
}
return {
fileConfig,
fileConfigPath
}
}

View File

@ -0,0 +1,205 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file at
* https://github.com/facebookincubator/create-react-app/blob/master/LICENSE
*/
const fs = require('fs')
const url = require('url')
const path = require('path')
const { chalk } = require('@vue/cli-shared-utils')
const address = require('address')
const defaultConfig = {
logLevel: 'silent',
secure: false,
changeOrigin: true,
ws: true,
xfwd: true
}
module.exports = function prepareProxy (proxy, appPublicFolder) {
// `proxy` lets you specify alternate servers for specific requests.
// It can either be a string or an object conforming to the Webpack dev server proxy configuration
// https://webpack.github.io/docs/webpack-dev-server.html
if (!proxy) {
return undefined
}
if (Array.isArray(proxy) || (typeof proxy !== 'object' && typeof proxy !== 'string')) {
console.log(
chalk.red(
'When specified, "proxy" in package.json must be a string or an object.'
)
)
console.log(
chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".')
)
console.log(
chalk.red(
'Either remove "proxy" from package.json, or make it an object.'
)
)
process.exit(1)
}
// If proxy is specified, let it handle any request except for
// files in the public folder and requests to the WebpackDevServer socket endpoint.
// https://github.com/facebook/create-react-app/issues/6720
function mayProxy (pathname) {
const maybePublicPath = path.resolve(appPublicFolder, pathname.slice(1))
const isPublicFileRequest = fs.existsSync(maybePublicPath) && fs.statSync(maybePublicPath).isFile()
const isWdsEndpointRequest = pathname.startsWith('/sockjs-node') // used by webpackHotDevClient
return !(isPublicFileRequest || isWdsEndpointRequest)
}
function createProxyEntry (target, usersOnProxyReq, context) {
// #2478
// There're a little-known use case that the `target` field is an object rather than a string
// https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/https.md
if (typeof target === 'string' && process.platform === 'win32') {
target = resolveLoopback(target)
}
return {
target,
context (pathname, req) {
// is a static asset
if (!mayProxy(pathname)) {
return false
}
if (context) {
// Explicit context, e.g. /api
return pathname.match(context)
} else {
// not a static request
if (req.method !== 'GET') {
return true
}
// Heuristics: if request `accept`s text/html, we pick /index.html.
// Modern browsers include text/html into `accept` header when navigating.
// However API calls like `fetch()` wont generally accept text/html.
// If this heuristic doesnt work well for you, use a custom `proxy` object.
return (
req.headers.accept &&
req.headers.accept.indexOf('text/html') === -1
)
}
},
onProxyReq (proxyReq, req, res) {
if (usersOnProxyReq) {
usersOnProxyReq(proxyReq, req, res)
}
// Browsers may send Origin headers even with same-origin
// requests. To prevent CORS issues, we have to change
// the Origin to match the target URL.
if (!proxyReq.agent && proxyReq.getHeader('origin')) {
proxyReq.setHeader('origin', target)
}
},
onError: onProxyError(target)
}
}
// Support proxy as a string for those who are using the simple proxy option
if (typeof proxy === 'string') {
if (!/^http(s)?:\/\//.test(proxy)) {
console.log(
chalk.red(
'When "proxy" is specified in package.json it must start with either http:// or https://'
)
)
process.exit(1)
}
return [
Object.assign({}, defaultConfig, createProxyEntry(proxy))
]
}
// Otherwise, proxy is an object so create an array of proxies to pass to webpackDevServer
return Object.keys(proxy).map(context => {
const config = proxy[context]
if (!Object.prototype.hasOwnProperty.call(config, 'target')) {
console.log(
chalk.red(
'When `proxy` in package.json is an object, each `context` object must have a ' +
'`target` property specified as a url string'
)
)
process.exit(1)
}
const entry = createProxyEntry(config.target, config.onProxyReq, context)
return Object.assign({}, defaultConfig, config, entry)
})
}
function resolveLoopback (proxy) {
const o = new url.URL(proxy)
o.host = undefined
if (o.hostname !== 'localhost') {
return proxy
}
// Unfortunately, many languages (unlike node) do not yet support IPv6.
// This means even though localhost resolves to ::1, the application
// must fall back to IPv4 (on 127.0.0.1).
// We can re-enable this in a few years.
/* try {
o.hostname = address.ipv6() ? '::1' : '127.0.0.1';
} catch (_ignored) {
o.hostname = '127.0.0.1';
} */
try {
// Check if we're on a network; if we are, chances are we can resolve
// localhost. Otherwise, we can just be safe and assume localhost is
// IPv4 for maximum compatibility.
if (!address.ip()) {
o.hostname = '127.0.0.1'
}
} catch (_ignored) {
o.hostname = '127.0.0.1'
}
return url.format(o)
}
// We need to provide a custom onError function for httpProxyMiddleware.
// It allows us to log custom error messages on the console.
function onProxyError (proxy) {
return (err, req, res) => {
const host = req.headers && req.headers.host
console.log(
chalk.red('Proxy error:') +
' Could not proxy request ' +
chalk.cyan(req.url) +
' from ' +
chalk.cyan(host) +
' to ' +
chalk.cyan(proxy) +
'.'
)
console.log(
'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
chalk.cyan(err.code) +
').'
)
console.log()
// And immediately send the proper error response to the client.
// Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
if (res.writeHead && !res.headersSent) {
res.writeHead(500)
}
res.end(
'Proxy error: Could not proxy request ' +
req.url +
' from ' +
host +
' to ' +
proxy +
' (' +
err.code +
').'
)
}
}

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file at
* https://github.com/facebookincubator/create-react-app/blob/master/LICENSE
*/
const url = require('url')
const { chalk } = require('@vue/cli-shared-utils')
const address = require('address')
const defaultGateway = require('default-gateway')
module.exports = function prepareUrls (protocol, host, port, pathname = '/') {
const formatUrl = hostname =>
url.format({
protocol,
hostname,
port,
pathname
})
const prettyPrintUrl = hostname =>
url.format({
protocol,
hostname,
port: chalk.bold(port),
pathname
})
const isUnspecifiedHost = host === '0.0.0.0' || host === '::'
let prettyHost, lanUrlForConfig
let lanUrlForTerminal = chalk.gray('unavailable')
if (isUnspecifiedHost) {
prettyHost = 'localhost'
try {
// This can only return an IPv4 address
const result = defaultGateway.v4.sync()
lanUrlForConfig = address.ip(result && result.interface)
if (lanUrlForConfig) {
// Check if the address is a private ip
// https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
if (
/^10[.]|^172[.](1[6-9]|2[0-9]|3[0-1])[.]|^192[.]168[.]/.test(
lanUrlForConfig
)
) {
// Address is private, format it for later use
lanUrlForTerminal = prettyPrintUrl(lanUrlForConfig)
} else {
// Address is not private, so we will discard it
lanUrlForConfig = undefined
}
}
} catch (_e) {
// ignored
}
} else {
prettyHost = host
lanUrlForConfig = host
lanUrlForTerminal = prettyPrintUrl(lanUrlForConfig)
}
const localUrlForTerminal = prettyPrintUrl(prettyHost)
const localUrlForBrowser = formatUrl(prettyHost)
return {
lanUrlForConfig,
lanUrlForTerminal,
localUrlForTerminal,
localUrlForBrowser
}
}

View File

@ -0,0 +1,23 @@
const getBaseUrl = require('./getBaseUrl')
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 = getBaseUrl(options)
if (raw) {
return env
}
for (const key in env) {
env[key] = JSON.stringify(env[key])
}
return {
'process.env': env
}
}

View File

@ -0,0 +1,47 @@
const { chalk } = require('@vue/cli-shared-utils')
const rules = [
{
type: 'cant-resolve-loader',
re: /Can't resolve '(.*loader)'/,
msg: (e, match) => (
`Failed to resolve loader: ${chalk.yellow(match[1])}\n` +
`You may need to install it.`
)
}
]
exports.transformer = error => {
if (error.webpackError) {
const message = typeof error.webpackError === 'string'
? error.webpackError
: error.webpackError.message || ''
for (const { re, msg, type } of rules) {
const match = message.match(re)
if (match) {
return Object.assign({}, error, {
// type is necessary to avoid being printed as default error
// by friendly-error-webpack-plugin
type,
shortMessage: msg(error, match)
})
}
}
// no match, unknown webpack error without a message.
// friendly-error-webpack-plugin fails to handle this.
if (!error.message) {
return Object.assign({}, error, {
type: 'unknown-webpack-error',
shortMessage: message
})
}
}
return error
}
exports.formatter = errors => {
errors = errors.filter(e => e.shortMessage)
if (errors.length) {
return errors.map(e => e.shortMessage)
}
}

View File

@ -0,0 +1,5 @@
const path = require('path')
module.exports = function resolveLocal (...args) {
return path.join(__dirname, '../../', ...args)
}

View File

@ -0,0 +1,83 @@
const path = require('path')
const { chalk, warn, error } = require('@vue/cli-shared-utils')
const { validate } = require('../options')
function ensureSlash (config, key) {
const val = config[key]
if (typeof val === 'string') {
config[key] = val.replace(/([^/])$/, '$1/')
}
}
function removeSlash (config, key) {
if (typeof config[key] === 'string') {
config[key] = config[key].replace(/\/$/g, '')
}
}
module.exports = function resolveUserConfig ({
inlineOptions,
pkgConfig,
fileConfig,
fileConfigPath
}) {
if (fileConfig) {
if (typeof fileConfig === 'function') {
fileConfig = fileConfig()
}
if (!fileConfig || typeof fileConfig !== 'object') {
throw new Error(
`Error loading ${chalk.bold(fileConfigPath)}: ` +
`should export an object or a function that returns object.`
)
}
}
// package.vue
if (pkgConfig && typeof pkgConfig !== 'object') {
throw new Error(
`Error loading Vue CLI config in ${chalk.bold(`package.json`)}: ` +
`the "vue" field should be an object.`
)
}
let resolved, resolvedFrom
if (fileConfig) {
const configFileName = path.basename(fileConfigPath)
if (pkgConfig) {
warn(
`"vue" field in package.json ignored ` +
`due to presence of ${chalk.bold(configFileName)}.`
)
warn(
`You should migrate it into ${chalk.bold(configFileName)} ` +
`and remove it from package.json.`
)
}
resolved = fileConfig
resolvedFrom = configFileName
} else if (pkgConfig) {
resolved = pkgConfig
resolvedFrom = '"vue" field in package.json'
} else {
resolved = inlineOptions || {}
resolvedFrom = 'inline options'
}
// normalize some options
if (resolved.publicPath !== 'auto') {
ensureSlash(resolved, 'publicPath')
}
if (typeof resolved.publicPath === 'string') {
resolved.publicPath = resolved.publicPath.replace(/^\.\//, '')
}
removeSlash(resolved, 'outputDir')
// validate options
validate(resolved, msg => {
error(`Invalid options in ${chalk.bold(resolvedFrom)}: ${msg}`)
})
return resolved
}

View File

@ -0,0 +1,70 @@
// copied from @vue/babel-preset-app
const { semver } = require('@vue/cli-shared-utils')
const { default: getTargets } = require('@babel/helper-compilation-targets')
// See the result at <https://github.com/babel/babel/blob/v7.13.15/packages/babel-compat-data/data/native-modules.json>
const allModuleTargets = getTargets(
{ esmodules: true },
{ ignoreBrowserslistConfig: true }
)
function getIntersectionTargets (targets, constraintTargets) {
const intersection = Object.keys(constraintTargets).reduce(
(results, browser) => {
// exclude the browsers that the user does not need
if (!targets[browser]) {
return results
}
// if the user-specified version is higher the minimum version that supports esmodule, than use it
results[browser] = semver.gt(
semver.coerce(constraintTargets[browser]),
semver.coerce(targets[browser])
)
? constraintTargets[browser]
: targets[browser]
return results
},
{}
)
return intersection
}
function getModuleTargets (targets) {
// use the intersection of modern mode browsers and user defined targets config
return getIntersectionTargets(targets, allModuleTargets)
}
function doAllTargetsSupportModule (targets) {
const browserList = Object.keys(targets)
return browserList.every(browserName => {
if (!allModuleTargets[browserName]) {
return false
}
return semver.gte(
semver.coerce(targets[browserName]),
semver.coerce(allModuleTargets[browserName])
)
})
}
// get browserslist targets in current working directory
const projectTargets = getTargets()
const projectModuleTargets = getModuleTargets(projectTargets)
const allProjectTargetsSupportModule = doAllTargetsSupportModule(projectTargets)
module.exports = {
getTargets,
getModuleTargets,
getIntersectionTargets,
doAllTargetsSupportModule,
projectTargets,
projectModuleTargets,
allProjectTargetsSupportModule
}

View File

@ -0,0 +1,38 @@
module.exports = function validateWebpackConfig (
webpackConfig,
api,
options,
target = 'app'
) {
const singleConfig = Array.isArray(webpackConfig)
? webpackConfig[0]
: webpackConfig
const actualTargetDir = singleConfig.output.path
if (actualTargetDir !== api.resolve(options.outputDir)) {
// user directly modifies output.path in configureWebpack or chainWebpack.
// this is not supported because there's no way for us to give copy
// plugin the correct value this way.
throw new Error(
`\n\nConfiguration Error: ` +
`Avoid modifying webpack output.path directly. ` +
`Use the "outputDir" option instead.\n`
)
}
if (actualTargetDir === api.service.context) {
throw new Error(
`\n\nConfiguration Error: ` +
`Do not set output directory to project root.\n`
)
}
if (target === 'app' && singleConfig.output.publicPath !== options.publicPath) {
throw new Error(
`\n\nConfiguration Error: ` +
`Avoid modifying webpack output.publicPath directly. ` +
`Use the "publicPath" option instead.\n`
)
}
}

View File

@ -0,0 +1,69 @@
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = class CorsPlugin {
constructor ({ publicPath, crossorigin, integrity }) {
this.crossorigin = crossorigin
this.integrity = integrity
this.publicPath = publicPath
}
apply (compiler) {
const ID = `vue-cli-cors-plugin`
compiler.hooks.compilation.tap(ID, compilation => {
const ssri = require('ssri')
const computeHash = url => {
const filename = url.replace(this.publicPath, '')
const asset = compilation.assets[filename]
if (asset) {
const src = asset.source()
const integrity = ssri.fromData(src, {
algorithms: ['sha384']
})
return integrity.toString()
}
}
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tap(ID, data => {
const tags = [...data.headTags, ...data.bodyTags]
if (this.crossorigin != null) {
tags.forEach(tag => {
if (tag.tagName === 'script' || tag.tagName === 'link') {
tag.attributes.crossorigin = this.crossorigin
}
})
}
if (this.integrity) {
tags.forEach(tag => {
if (tag.tagName === 'script') {
const hash = computeHash(tag.attributes.src)
if (hash) {
tag.attributes.integrity = hash
}
} else if (tag.tagName === 'link' && tag.attributes.rel === 'stylesheet') {
const hash = computeHash(tag.attributes.href)
if (hash) {
tag.attributes.integrity = hash
}
}
})
// when using SRI, Chrome somehow cannot reuse
// the preloaded resource, and causes the files to be downloaded twice.
// this is a Chrome bug (https://bugs.chromium.org/p/chromium/issues/detail?id=677022)
// for now we disable preload if SRI is used.
data.headTags = data.headTags.filter(tag => {
return !(
tag.tagName === 'link' &&
tag.attributes.rel === 'preload'
)
})
}
})
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tap(ID, data => {
data.html = data.html.replace(/\scrossorigin=""/g, ' crossorigin')
})
})
}
}

View File

@ -0,0 +1,223 @@
// From https://github.com/FormidableLabs/webpack-dashboard/blob/7f99b31c5f00a7818d8129cb8a8fc6eb1b71799c/plugin/index.js
// Modified by Guillaume Chau (Akryum)
/* eslint-disable max-params, max-statements */
'use strict'
const path = require('path')
const fs = require('fs-extra')
const webpack = require('webpack')
const { IpcMessenger } = require('@vue/cli-shared-utils')
const { analyzeBundle } = require('./analyzeBundle')
const ID = 'vue-cli-dashboard-plugin'
const ONE_SECOND = 1000
const FILENAME_QUERY_REGEXP = /\?.*$/
const ipc = new IpcMessenger()
function getTimeMessage (timer) {
let time = Date.now() - timer
if (time >= ONE_SECOND) {
time /= ONE_SECOND
time = Math.round(time)
time += 's'
} else {
time += 'ms'
}
return ` (${time})`
}
class DashboardPlugin {
constructor (options) {
this.type = options.type
if (this.type === 'build' && options.moduleBuild) {
this.type = 'build-modern'
}
this.watching = false
this.autoDisconnect = !options.keepAlive
}
cleanup () {
this.sendData = null
if (this.autoDisconnect) ipc.disconnect()
}
apply (compiler) {
let sendData = this.sendData
let timer
let inProgress = false
let assetSources = new Map()
if (!sendData) {
sendData = data => ipc.send({
webpackDashboardData: {
type: this.type,
value: data
}
})
}
// Progress status
let progressTime = Date.now()
const progressPlugin = new webpack.ProgressPlugin((percent, msg) => {
// in webpack 5, progress plugin will continue sending progresses even after the done hook
// for things like caching, causing the progress indicator stuck at 0.99
// so we have to use a flag to stop sending such `compiling` progress data
if (!inProgress) {
return
}
// Debouncing
const time = Date.now()
if (time - progressTime > 300) {
progressTime = time
sendData([
{
type: 'status',
value: 'Compiling'
},
{
type: 'progress',
value: percent
},
{
type: 'operations',
value: msg + getTimeMessage(timer)
}
])
}
})
progressPlugin.apply(compiler)
compiler.hooks.watchRun.tap(ID, c => {
this.watching = true
})
compiler.hooks.run.tap(ID, c => {
this.watching = false
})
compiler.hooks.compile.tap(ID, () => {
inProgress = true
timer = Date.now()
sendData([
{
type: 'status',
value: 'Compiling'
},
{
type: 'progress',
value: 0
}
])
})
compiler.hooks.invalid.tap(ID, () => {
sendData([
{
type: 'status',
value: 'Invalidated'
},
{
type: 'progress',
value: 0
},
{
type: 'operations',
value: 'idle'
}
])
})
compiler.hooks.failed.tap(ID, () => {
sendData([
{
type: 'status',
value: 'Failed'
},
{
type: 'operations',
value: `idle${getTimeMessage(timer)}`
}
])
inProgress = false
})
compiler.hooks.afterEmit.tap(ID, compilation => {
assetSources = new Map()
for (const name in compilation.assets) {
const asset = compilation.assets[name]
const filename = name.replace(FILENAME_QUERY_REGEXP, '')
try {
assetSources.set(filename, asset.source())
} catch (e) {
const webpackFs = compiler.outputFileSystem
const fullPath = (webpackFs.join || path.join)(compiler.options.output.path, filename)
const buf = webpackFs.readFileSync(fullPath)
assetSources.set(filename, buf.toString())
}
}
})
compiler.hooks.done.tap(ID, stats => {
let statsData = stats.toJson()
// Sometimes all the information is located in `children` array
if ((!statsData.assets || !statsData.assets.length) && statsData.children && statsData.children.length) {
statsData = statsData.children[0]
}
const outputPath = compiler.options.output.path
statsData.assets.forEach(asset => {
// Removing query part from filename (yes, somebody uses it for some reason and Webpack supports it)
asset.name = asset.name.replace(FILENAME_QUERY_REGEXP, '')
asset.fullPath = path.join(outputPath, asset.name)
})
// Analyze the assets and update sizes on assets and modules
analyzeBundle(statsData, assetSources)
const hasErrors = stats.hasErrors()
sendData([
{
type: 'status',
value: hasErrors ? 'Failed' : 'Success'
},
{
type: 'progress',
value: 1
},
{
type: 'operations',
value: `idle${getTimeMessage(timer)}`
}
])
inProgress = false
const statsFile = path.resolve(process.cwd(), `./node_modules/.stats-${this.type}.json`)
fs.writeJson(statsFile, {
errors: hasErrors,
warnings: stats.hasWarnings(),
data: statsData
}).then(() => {
sendData([
{
type: 'stats'
}
])
if (!this.watching) {
this.cleanup()
}
}).catch(error => {
console.error(error)
})
})
}
}
module.exports = DashboardPlugin

View File

@ -0,0 +1,86 @@
const fs = require('fs-extra')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
class ModernModePlugin {
constructor ({ targetDir, isModuleBuild }) {
this.targetDir = targetDir
this.isModuleBuild = isModuleBuild
}
apply (compiler) {
if (!this.isModuleBuild) {
this.applyLegacy(compiler)
} else {
this.applyModule(compiler)
}
}
applyLegacy (compiler) {
const ID = `vue-cli-legacy-bundle`
compiler.hooks.compilation.tap(ID, compilation => {
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(ID, async (data, cb) => {
// get stats, write to disk
await fs.ensureDir(this.targetDir)
const htmlName = path.basename(data.plugin.options.filename)
// Watch out for output files in sub directories
const htmlPath = path.dirname(data.plugin.options.filename)
const tempFilename = path.join(this.targetDir, htmlPath, `legacy-assets-${htmlName}.json`)
await fs.mkdirp(path.dirname(tempFilename))
let tags = data.bodyTags
if (data.plugin.options.scriptLoading === 'defer') {
tags = data.headTags
}
await fs.writeFile(tempFilename, JSON.stringify(tags))
cb()
})
})
}
applyModule (compiler) {
const ID = `vue-cli-modern-bundle`
compiler.hooks.compilation.tap(ID, compilation => {
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(ID, async (data, cb) => {
let tags = data.bodyTags
if (data.plugin.options.scriptLoading === 'defer') {
tags = data.headTags
}
// use <script type="module"> for modern assets
tags.forEach(tag => {
if (tag.tagName === 'script' && tag.attributes) {
tag.attributes.type = 'module'
}
})
// use <link rel="modulepreload"> instead of <link rel="preload">
// for modern assets
data.headTags.forEach(tag => {
if (tag.tagName === 'link' &&
tag.attributes.rel === 'preload' &&
tag.attributes.as === 'script') {
tag.attributes.rel = 'modulepreload'
}
})
// inject links for legacy assets as <script nomodule>
const htmlName = path.basename(data.plugin.options.filename)
// Watch out for output files in sub directories
const htmlPath = path.dirname(data.plugin.options.filename)
const tempFilename = path.join(this.targetDir, htmlPath, `legacy-assets-${htmlName}.json`)
const legacyAssets = JSON.parse(await fs.readFile(tempFilename, 'utf-8'))
.filter(a => a.tagName === 'script' && a.attributes)
legacyAssets.forEach(a => { a.attributes.nomodule = '' })
tags.push(...legacyAssets)
await fs.remove(tempFilename)
cb()
})
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tap(ID, data => {
data.html = data.html.replace(/\snomodule="">/g, ' nomodule>')
})
})
}
}
module.exports = ModernModePlugin

View File

@ -0,0 +1,16 @@
const fs = require('fs-extra')
module.exports = class MovePlugin {
constructor (from, to) {
this.from = from
this.to = to
}
apply (compiler) {
compiler.hooks.done.tap('move-plugin', () => {
if (fs.existsSync(this.from)) {
fs.moveSync(this.from, this.to, { overwrite: true })
}
})
}
}

View File

@ -0,0 +1,71 @@
// https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc
const safariFix = `!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();`
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { semver } = require('@vue/cli-shared-utils')
const { projectModuleTargets } = require('../util/targets')
const minSafariVersion = projectModuleTargets.safari
const minIOSVersion = projectModuleTargets.ios
const supportsSafari10 =
(minSafariVersion && semver.lt(semver.coerce(minSafariVersion), '11.0.0')) ||
(minIOSVersion && semver.lt(semver.coerce(minIOSVersion), '11.0.0'))
const needsSafariFix = supportsSafari10
class SafariNomoduleFixPlugin {
constructor ({ unsafeInline, jsDirectory }) {
this.unsafeInline = unsafeInline
this.jsDirectory = jsDirectory
}
apply (compiler) {
if (!needsSafariFix) {
return
}
const { RawSource } = compiler.webpack
? compiler.webpack.sources
: require('webpack-sources')
const ID = 'SafariNomoduleFixPlugin'
compiler.hooks.compilation.tap(ID, compilation => {
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tap(ID, data => {
let scriptTag
if (this.unsafeInline) {
// inject inline Safari 10 nomodule fix
scriptTag = {
tagName: 'script',
closeTag: true,
innerHTML: safariFix
}
} else {
// inject the fix as an external script
const safariFixPath = path.join(this.jsDirectory, 'safari-nomodule-fix.js')
const fullSafariFixPath = path.join(compilation.options.output.publicPath, safariFixPath)
compilation.assets[safariFixPath] = new RawSource(safariFix)
scriptTag = {
tagName: 'script',
closeTag: true,
attributes: {
src: fullSafariFixPath
}
}
}
let tags = data.bodyTags
if (data.plugin.options.scriptLoading === 'defer') {
tags = data.headTags
}
// insert just before the first actual script tag,
// and after all other tags such as `meta`
const firstScriptIndex = tags.findIndex(tag => tag.tagName === 'script')
tags.splice(firstScriptIndex, 0, scriptTag)
})
})
}
}
SafariNomoduleFixPlugin.safariFix = safariFix
module.exports = SafariNomoduleFixPlugin

View File

@ -0,0 +1,446 @@
// From https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/4abac503c789bac94118e5bbfc410686fb5112c7/src/parseUtils.js
// Modified by Guillaume Chau (Akryum)
const acorn = require('acorn')
const walk = require('acorn-walk')
const mapValues = require('lodash.mapvalues')
const zlib = require('zlib')
const { warn } = require('@vue/cli-shared-utils')
exports.analyzeBundle = function analyzeBundle (bundleStats, assetSources) {
// Picking only `*.js` assets from bundle that has non-empty `chunks` array
const jsAssets = []
const otherAssets = []
// Separate JS assets
bundleStats.assets.forEach(asset => {
if (asset.name.endsWith('.js') && asset.chunks && asset.chunks.length) {
jsAssets.push(asset)
} else {
otherAssets.push(asset)
}
})
// Trying to parse bundle assets and get real module sizes
let bundlesSources = null
let parsedModules = null
bundlesSources = {}
parsedModules = {}
for (const asset of jsAssets) {
const source = assetSources.get(asset.name)
let bundleInfo
try {
bundleInfo = parseBundle(source)
} catch (err) {
const msg = (err.code === 'ENOENT') ? 'no such file' : err.message
warn(`Error parsing bundle asset "${asset.fullPath}": ${msg}`)
continue
}
bundlesSources[asset.name] = bundleInfo.src
Object.assign(parsedModules, bundleInfo.modules)
}
if (!Object.keys(bundlesSources).length) {
bundlesSources = null
parsedModules = null
warn('\nNo bundles were parsed. Analyzer will show only original module sizes from stats file.\n')
}
// Update sizes
bundleStats.modules.forEach(module => {
const parsedSrc = parsedModules && parsedModules[module.id]
module.size = {
stats: module.size
}
if (parsedSrc) {
module.size.parsed = parsedSrc.length
module.size.gzip = getGzipSize(parsedSrc)
} else {
module.size.parsed = module.size.stats
module.size.gzip = 0
}
})
jsAssets.forEach(asset => {
const src = bundlesSources && bundlesSources[asset.name]
asset.size = {
stats: asset.size
}
if (src) {
asset.size.parsed = src.length
asset.size.gzip = getGzipSize(src)
} else {
asset.size.parsed = asset.size.stats
asset.size.gzip = 0
}
}, {})
otherAssets.forEach(asset => {
const src = assetSources.get(asset.name)
asset.size = {
stats: asset.size,
parsed: asset.size
}
if (src) {
asset.size.gzip = getGzipSize(src)
} else {
asset.size.gzip = 0
}
})
}
function parseBundle (bundleContent) {
const ast = acorn.parse(bundleContent, {
sourceType: 'script',
// I believe in a bright future of ECMAScript!
// Actually, it's set to `2050` to support the latest ECMAScript version that currently exists.
// Seems like `acorn` supports such weird option value.
ecmaVersion: 2050
})
const walkState = {
locations: null,
expressionStatementDepth: 0
}
walk.recursive(
ast,
walkState,
{
ExpressionStatement (node, state, c) {
if (state.locations) return
state.expressionStatementDepth++
if (
// Webpack 5 stores modules in the the top-level IIFE
state.expressionStatementDepth === 1 &&
ast.body.includes(node) &&
isIIFE(node)
) {
const fn = getIIFECallExpression(node)
if (
// It should not contain neither arguments
fn.arguments.length === 0 &&
// ...nor parameters
fn.callee.params.length === 0
) {
// Modules are stored in the very first variable declaration as hash
const firstVariableDeclaration = fn.callee.body.body.find(n => n.type === 'VariableDeclaration')
if (firstVariableDeclaration) {
for (const declaration of firstVariableDeclaration.declarations) {
if (declaration.init) {
state.locations = getModulesLocations(declaration.init)
if (state.locations) {
break
}
}
}
}
}
}
if (!state.locations) {
c(node.expression, state)
}
state.expressionStatementDepth--
},
AssignmentExpression (node, state) {
if (state.locations) return
// Modules are stored in exports.modules:
// exports.modules = {};
const { left, right } = node
if (
left &&
left.object && left.object.name === 'exports' &&
left.property && left.property.name === 'modules' &&
isModulesHash(right)
) {
state.locations = getModulesLocations(right)
}
},
CallExpression (node, state, c) {
if (state.locations) return
const args = node.arguments
// Main chunk with webpack loader.
// Modules are stored in first argument:
// (function (...) {...})(<modules>)
if (
node.callee.type === 'FunctionExpression' &&
!node.callee.id &&
args.length === 1 &&
isSimpleModulesList(args[0])
) {
state.locations = getModulesLocations(args[0])
return
}
// Async Webpack < v4 chunk without webpack loader.
// webpackJsonp([<chunks>], <modules>, ...)
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
if (
node.callee.type === 'Identifier' &&
mayBeAsyncChunkArguments(args) &&
isModulesList(args[1])
) {
state.locations = getModulesLocations(args[1])
return
}
// Async Webpack v4 chunk without webpack loader.
// (window.webpackJsonp=window.webpackJsonp||[]).push([[<chunks>], <modules>, ...]);
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
if (isAsyncChunkPushExpression(node)) {
state.locations = getModulesLocations(args[0].elements[1])
return
}
// Webpack v4 WebWorkerChunkTemplatePlugin
// globalObject.chunkCallbackName([<chunks>],<modules>, ...);
// Both globalObject and chunkCallbackName can be changed through the config, so we can't check them.
if (isAsyncWebWorkerChunkExpression(node)) {
state.locations = getModulesLocations(args[1])
return
}
// Walking into arguments because some of plugins (e.g. `DedupePlugin`) or some Webpack
// features (e.g. `umd` library output) can wrap modules list into additional IIFE.
args.forEach(arg => c(arg, state))
}
}
)
let modules
if (walkState.locations) {
modules = mapValues(walkState.locations,
loc => bundleContent.slice(loc.start, loc.end)
)
} else {
modules = {}
}
return {
modules: modules,
src: bundleContent,
runtimeSrc: getBundleRuntime(bundleContent, walkState.locations)
}
}
function getGzipSize (buffer) {
return zlib.gzipSync(buffer).length
}
/**
* Returns bundle source except modules
*/
function getBundleRuntime (content, modulesLocations) {
const sortedLocations = Object.values(modulesLocations || {})
.sort((a, b) => a.start - b.start)
let result = ''
let lastIndex = 0
for (const { start, end } of sortedLocations) {
result += content.slice(lastIndex, start)
lastIndex = end
}
return result + content.slice(lastIndex, content.length)
}
function isIIFE (node) {
return (
node.type === 'ExpressionStatement' &&
(
node.expression.type === 'CallExpression' ||
(node.expression.type === 'UnaryExpression' && node.expression.argument.type === 'CallExpression')
)
)
}
function getIIFECallExpression (node) {
if (node.expression.type === 'UnaryExpression') {
return node.expression.argument
} else {
return node.expression
}
}
function isModulesList (node) {
return (
isSimpleModulesList(node) ||
// Modules are contained in expression `Array([minimum ID]).concat([<module>, <module>, ...])`
isOptimizedModulesArray(node)
)
}
function isSimpleModulesList (node) {
return (
// Modules are contained in hash. Keys are module ids.
isModulesHash(node) ||
// Modules are contained in array. Indexes are module ids.
isModulesArray(node)
)
}
function isModulesHash (node) {
return (
node.type === 'ObjectExpression' &&
node.properties
.map(p => p.value)
.every(isModuleWrapper)
)
}
function isModulesArray (node) {
return (
node.type === 'ArrayExpression' &&
node.elements.every(elem =>
// Some of array items may be skipped because there is no module with such id
!elem ||
isModuleWrapper(elem)
)
)
}
function isOptimizedModulesArray (node) {
// Checking whether modules are contained in `Array(<minimum ID>).concat(...modules)` array:
// https://github.com/webpack/webpack/blob/v1.14.0/lib/Template.js#L91
// The `<minimum ID>` + array indexes are module ids
return (
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
// Make sure the object called is `Array(<some number>)`
node.callee.object.type === 'CallExpression' &&
node.callee.object.callee.type === 'Identifier' &&
node.callee.object.callee.name === 'Array' &&
node.callee.object.arguments.length === 1 &&
isNumericId(node.callee.object.arguments[0]) &&
// Make sure the property X called for `Array(<some number>).X` is `concat`
node.callee.property.type === 'Identifier' &&
node.callee.property.name === 'concat' &&
// Make sure exactly one array is passed in to `concat`
node.arguments.length === 1 &&
isModulesArray(node.arguments[0])
)
}
function isModuleWrapper (node) {
return (
// It's an anonymous function expression that wraps module
((node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && !node.id) ||
// If `DedupePlugin` is used it can be an ID of duplicated module...
isModuleId(node) ||
// or an array of shape [<module_id>, ...args]
(node.type === 'ArrayExpression' && node.elements.length > 1 && isModuleId(node.elements[0]))
)
}
function isModuleId (node) {
return (node.type === 'Literal' && (isNumericId(node) || typeof node.value === 'string'))
}
function isNumericId (node) {
return (node.type === 'Literal' && Number.isInteger(node.value) && node.value >= 0)
}
function isChunkIds (node) {
// Array of numeric or string ids. Chunk IDs are strings when NamedChunksPlugin is used
return (
node.type === 'ArrayExpression' &&
node.elements.every(isModuleId)
)
}
function isAsyncChunkPushExpression (node) {
const {
callee,
arguments: args
} = node
return (
callee.type === 'MemberExpression' &&
callee.property.name === 'push' &&
callee.object.type === 'AssignmentExpression' &&
args.length === 1 &&
args[0].type === 'ArrayExpression' &&
mayBeAsyncChunkArguments(args[0].elements) &&
isModulesList(args[0].elements[1])
)
}
function mayBeAsyncChunkArguments (args) {
return (
args.length >= 2 &&
isChunkIds(args[0])
)
}
function isAsyncWebWorkerChunkExpression (node) {
const { callee, type, arguments: args } = node
return (
type === 'CallExpression' &&
callee.type === 'MemberExpression' &&
args.length === 2 &&
isChunkIds(args[0]) &&
isModulesList(args[1])
)
}
function getModulesLocations (node) {
if (node.type === 'ObjectExpression') {
// Modules hash
const modulesNodes = node.properties
return modulesNodes.reduce((result, moduleNode) => {
const moduleId = moduleNode.key.name || moduleNode.key.value
result[moduleId] = getModuleLocation(moduleNode.value)
return result
}, {})
}
const isOptimizedArray = (node.type === 'CallExpression')
if (node.type === 'ArrayExpression' || isOptimizedArray) {
// Modules array or optimized array
const minId = isOptimizedArray
// Get the [minId] value from the Array() call first argument literal value
? node.callee.object.arguments[0].value
// `0` for simple array
: 0
const modulesNodes = isOptimizedArray
// The modules reside in the `concat()` function call arguments
? node.arguments[0].elements
: node.elements
return modulesNodes.reduce((result, moduleNode, i) => {
if (moduleNode) {
result[i + minId] = getModuleLocation(moduleNode)
}
return result
}, {})
}
return {}
}
function getModuleLocation (node) {
return { start: node.start, end: node.end }
}

BIN
app_vue/node_modules/@vue/cli-service/logo.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

View File

@ -0,0 +1,16 @@
module.exports = (api) => {
if (api.hasPlugin('vue-next')) {
api.extendPackage({
devDependencies: {
'vue-cli-plugin-vue-next': null
}
},
{
prune: true
})
api.exitLog('vue-cli-plugin-vue-next is removed because Vue 3 support has been built into the core plugins.')
}
// TODO: lint-staged update
}

129
app_vue/node_modules/@vue/cli-service/package.json generated vendored Normal file
View File

@ -0,0 +1,129 @@
{
"name": "@vue/cli-service",
"version": "5.0.8",
"description": "local service for vue-cli projects",
"main": "lib/Service.js",
"typings": "types/index.d.ts",
"bin": {
"vue-cli-service": "bin/vue-cli-service.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue-cli.git",
"directory": "packages/@vue/cli-service"
},
"keywords": [
"vue",
"cli"
],
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/vue-cli/issues"
},
"homepage": "https://cli.vuejs.org/",
"dependencies": {
"@babel/helper-compilation-targets": "^7.12.16",
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
"@soda/get-current-script": "^1.0.2",
"@types/minimist": "^1.2.0",
"@vue/cli-overlay": "^5.0.8",
"@vue/cli-plugin-router": "^5.0.8",
"@vue/cli-plugin-vuex": "^5.0.8",
"@vue/cli-shared-utils": "^5.0.8",
"@vue/component-compiler-utils": "^3.3.0",
"@vue/vue-loader-v15": "npm:vue-loader@^15.9.7",
"@vue/web-component-wrapper": "^1.3.0",
"acorn": "^8.0.5",
"acorn-walk": "^8.0.2",
"address": "^1.1.2",
"autoprefixer": "^10.2.4",
"browserslist": "^4.16.3",
"case-sensitive-paths-webpack-plugin": "^2.3.0",
"cli-highlight": "^2.1.10",
"clipboardy": "^2.3.0",
"cliui": "^7.0.4",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.5.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"cssnano": "^5.0.0",
"debug": "^4.1.1",
"default-gateway": "^6.0.3",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"fs-extra": "^9.1.0",
"globby": "^11.0.2",
"hash-sum": "^2.0.0",
"html-webpack-plugin": "^5.1.0",
"is-file-esm": "^1.0.0",
"launch-editor-middleware": "^2.2.1",
"lodash.defaultsdeep": "^4.6.1",
"lodash.mapvalues": "^4.6.0",
"mini-css-extract-plugin": "^2.5.3",
"minimist": "^1.2.5",
"module-alias": "^2.2.2",
"portfinder": "^1.0.26",
"postcss": "^8.2.6",
"postcss-loader": "^6.1.1",
"progress-webpack-plugin": "^1.0.12",
"ssri": "^8.0.1",
"terser-webpack-plugin": "^5.1.1",
"thread-loader": "^3.0.0",
"vue-loader": "^17.0.0",
"vue-style-loader": "^4.1.3",
"webpack": "^5.54.0",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-chain": "^6.5.1",
"webpack-dev-server": "^4.7.3",
"webpack-merge": "^5.7.3",
"webpack-virtual-modules": "^0.4.2",
"whatwg-fetch": "^3.6.2"
},
"peerDependencies": {
"vue-template-compiler": "^2.0.0",
"webpack-sources": "*"
},
"peerDependenciesMeta": {
"cache-loader": {
"optional": true
},
"less-loader": {
"optional": true
},
"pug-plain-loader": {
"optional": true
},
"raw-loader": {
"optional": true
},
"sass-loader": {
"optional": true
},
"stylus-loader": {
"optional": true
},
"vue-template-compiler": {
"optional": true
},
"webpack-sources": {
"optional": true
}
},
"devDependencies": {
"cache-loader": "^4.1.0",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"stylus-loader": "^6.1.0",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vue-template-compiler": "^2.6.14",
"vuex": "^3.6.2"
},
"publishConfig": {
"access": "public"
},
"engines": {
"node": "^12.0.0 || >= 14.0.0"
},
"gitHead": "b154dbd7aca4b4538e6c483b1d4b817499d7b8eb"
}

View File

@ -0,0 +1,192 @@
import ChainableWebpackConfig = require('webpack-chain')
import { Configuration as WebpackOptions } from 'webpack'
type PredefinedOptions<T> = T & { [key: string]: any }
type PageEntry = string | string[];
interface PageConfig {
entry: PageEntry;
[key: string]: any;
}
interface LoaderOptions {
css?: object;
sass?: object;
scss?: object;
less?: object;
stylus?: object;
postcss?: object;
}
// mini-css-extract-plugin options
interface ExtractOptions {
filename?: string;
chunkFilename?: string;
}
interface CSSOptions {
/**
* Default: `true`
*
* By default, only files that ends in `*.module.[ext]` are treated as CSS modules
*/
requireModuleExtension?: boolean;
/**
* Default: `true`
*
* Whether to extract CSS in your components into a standalone CSS files (instead of inlined in JavaScript and injected dynamically)
*/
extract?: boolean | ExtractOptions;
/**
* Default: `false`
*
* Whether to enable source maps for CSS. Setting this to `true` may affect build performance
*/
sourceMap?: boolean;
/**
* Default: `{}`
*
* Pass options to CSS-related loaders
*/
loaderOptions?: LoaderOptions;
}
interface ProjectOptions {
/**
* Default: `'/'`
*
* The base URL your application bundle will be deployed at
*/
publicPath?: string;
/**
* Default: `'dist'`
*
* The directory where the production build files will be generated in when running `vue-cli-service build`
*/
outputDir?: string;
/**
* Default: `''`
*
* A directory (relative to `outputDir`) to nest generated static assets (js, css, img, fonts) under
*/
assetsDir?: string;
/**
* Default: `'index.html'`
*
* Specify the output path for the generated `index.html` (relative to `outputDir`). Can also be an absolute path
*/
indexPath?: string;
/**
* Default: `true`
*
* By default, generated static assets contains hashes in their filenames for better caching control
*/
filenameHashing?: boolean;
/**
* Default: `false`
*
* Whether to use the build of Vue core that includes the runtime compiler
*/
runtimeCompiler?: boolean;
/**
* Default: `false`
*
* If set to `true`, all dependencies in `node_modules` will be transpiled by Babel;
* Or, if you only want to selectively transpile some of the dependencies, you can list them
* in this option.
*/
transpileDependencies?: boolean | Array<string | RegExp>;
/**
* Default: `true`
*
* Setting this to `false` can speed up production builds if you don't need source maps for production
*/
productionSourceMap?: boolean;
/**
* Default: `require('os').cpus().length > 1`
*
* Whether to use `thread-loader` for Babel or TypeScript transpilation
*/
parallel?: boolean | number;
/**
* [All options for `webpack-dev-server`](https://webpack.js.org/configuration/dev-server/) are supported
*/
devServer?: { proxy?: string | object, [key: string]: any };
/**
* Default: `undefined`
*
* Build the app in multi-page mode
*/
pages?: {
[key: string]: PageEntry | PageConfig;
};
/**
* Default: `undefined`
*
* Configure the `crossorigin` attribute on `<link rel="stylesheet">` and `<script>` tags in generated HTML
*/
crossorigin?: '' | 'anonymous' | 'use-credentials';
/**
* Default: `false`
*
* Set to `true` to enable [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) (SRI) on `<link rel="stylesheet">` and `<script>` tags in generated HTML
*/
integrity?: boolean;
css?: CSSOptions;
/**
* A function that will receive an instance of `ChainableConfig` powered by [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain)
*/
chainWebpack?: (config: ChainableWebpackConfig) => void;
/**
* Set webpack configuration. If the value is `Object`, will be merged into config. If value is `Function`, will receive current config as argument
*/
configureWebpack?: WebpackOptions | ((config: WebpackOptions) => (WebpackOptions | void));
/**
* Default: `'default'`
*
* Whether to perform lint-on-save during development using [eslint-loader](https://github.com/webpack-contrib/eslint-loader)
*/
lintOnSave?: boolean | 'default' | 'warning' | 'error';
/**
* Pass options to the [PWA Plugin](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa)
*/
pwa?: object;
/**
* set terser-webpack-plugin minify and terserOptions
*/
terser?: {
/**
* Supported minify: [terser](https://github.com/webpack-contrib/terser-webpack-plugin#minify), [esbuild](https://github.com/webpack-contrib/terser-webpack-plugin#esbuild), [swc](https://github.com/webpack-contrib/terser-webpack-plugin#swc), [uglifyJs](https://github.com/webpack-contrib/terser-webpack-plugin#uglify-js). currently we do not allow custom minify function
*
* In the non-terser case, you should install the corresponding package (eg. `npm i esbuild -D`)
*
*/
minify: 'terser' | 'esbuild' | 'swc' | 'uglifyJs';
/**
* `terserOptions` options will be passed to minify
*
* [All options for `terser`](https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions)
*
* [All options for `esbuild`](https://github.com/evanw/esbuild/blob/master/lib/shared/types.ts#L160-L174)
*
* [All options for `swc`](https://swc.rs/docs/config-js-minify)
*
* [All options for `uglifyJs`](https://github.com/mishoo/UglifyJS#minify-options)
*/
terserOptions?: PredefinedOptions<import("terser").MinifyOptions>;
};
/**
* This is an object that doesn't go through any schema validation, so it can be used to pass arbitrary options to 3rd party plugins
*/
pluginOptions?: object;
}
type ConfigFunction = () => ProjectOptions
export { ProjectOptions, ConfigFunction }

View File

@ -0,0 +1,64 @@
import { ServicePlugin } from '@vue/cli-service'
const servicePlugin: ServicePlugin = (api, options) => {
const version = api.version
api.assertVersion(4)
api.assertVersion('^100')
api.getCwd()
api.resolve('src/main.js')
api.hasPlugin('eslint')
api.registerCommand(
'lint',
{
description: 'lint and fix source files',
usage: 'vue-cli-service lint [options] [...files]',
options: {
'--format [formatter]': 'specify formatter (default: stylish)'
},
details: 'For more options, see https://eslint.org/docs/user-guide/command-line-interface#options'
},
async args => {
await require('./lint')(args, api)
}
)
api.registerCommand('lint', args => {})
api.chainWebpack(webpackConfig => {
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
webpackConfig.devtool('eval-cheap-module-source-map')
webpackConfig.plugin('hmr').use(require('webpack/lib/HotModuleReplacementPlugin'))
webpackConfig.output.globalObject(`(typeof self !== 'undefined' ? self : this)`)
}
})
api.configureWebpack(config => {
config.output = {
path: 'test-dist-2'
}
})
api.configureWebpack(config => {
return {
devtool: config.devtool || 'source-map'
}
})
api.resolveWebpackConfig()
api.resolveWebpackConfig(api.resolveChainableWebpackConfig())
const { cacheIdentifier, cacheDirectory } = api.genCacheConfig(
'babel-loader',
{
'@babel/core': require('@babel/core/package.json').version,
'@vue/babel-preset-app': require('@vue/babel-preset-app/package.json').version,
'babel-loader': require('babel-loader/package.json').version,
modern: !!process.env.VUE_CLI_MODERN_BUILD,
browserslist: api.service.pkg.browserslist
},
['babel.config.js', '.browserslistrc']
)
}
export = servicePlugin

138
app_vue/node_modules/@vue/cli-service/types/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,138 @@
import minimist = require('minimist')
import ChainableConfig = require('webpack-chain')
import webpack = require('webpack')
import WebpackDevServer = require('webpack-dev-server')
import express = require('express') // @types/webpack-dev-server depends on @types/express
import { ProjectOptions, ConfigFunction } from './ProjectOptions'
type RegisterCommandFn = (args: minimist.ParsedArgs, rawArgv: string[]) => any
type RegisterCommandOpts = Partial<{
description: string
usage: string
options: {
[flags: string]: string
}
details: string
}>
type WebpackChainFn = (chainableConfig: ChainableConfig) => void
type webpackRawConfigFn = ((config: webpack.Configuration) => webpack.Configuration | void) | webpack.Configuration
type DevServerConfigFn = (app: express.Application, server: WebpackDevServer) => void
interface CacheConfig {
cacheDirectory: string
cacheIdentifier: string
}
declare class PluginAPI {
id: string
service: any
readonly version: string
assertVersion(range: number | string): void
/**
* Current working directory.
*/
getCwd(): string
/**
* Resolve path for a project.
*
* @param _path - Relative path from project root
* @return The resolved absolute path.
*/
resolve(_path: string): string
/**
* Check if the project has a given plugin.
*
* @param id - Plugin id, can omit the (@vue/|vue-|@scope/vue)-cli-plugin- prefix
* @return `boolean`
*/
hasPlugin(id: string): boolean
/**
* Register a command that will become available as `vue-cli-service [name]`.
*
* @param name
* @param [opts]
* @param fn
*/
registerCommand(name: string, fn: RegisterCommandFn): void
registerCommand(name: string, opts: RegisterCommandOpts, fn: RegisterCommandFn): void
/**
* Register a function that will receive a chainable webpack config
* the function is lazy and won't be called until `resolveWebpackConfig` is
* called
*
* @param fn
*/
chainWebpack(fn: WebpackChainFn): void
/**
* Register
* - a webpack configuration object that will be merged into the config
* OR
* - a function that will receive the raw webpack config.
* the function can either mutate the config directly or return an object
* that will be merged into the config.
*
* @param fn
*/
configureWebpack(fn: webpackRawConfigFn): void
/**
* Register a dev serve config function. It will receive the express `app`
* instance of the dev server.
*
* @param fn
*/
configureDevServer(fn: DevServerConfigFn): void
/**
* Resolve the final raw webpack config, that will be passed to webpack.
*
* @param [chainableConfig]
* @return Raw webpack config.
*/
resolveWebpackConfig(chainableConfig?: ChainableConfig): webpack.Configuration
/**
* Resolve an intermediate chainable webpack config instance, which can be
* further tweaked before generating the final raw webpack config.
* You can call this multiple times to generate different branches of the
* base webpack config.
* See https://github.com/mozilla-neutrino/webpack-chain
*
* @return ChainableWebpackConfig
*/
resolveChainableWebpackConfig(): ChainableConfig
/**
* Generate a cache identifier from a number of variables
*/
genCacheConfig(id: string, partialIdentifier: any, configFiles?: string | string[]): CacheConfig
}
/**
* Service plugin serves for modifying webpack config,
* creating new vue-cli service commands or changing existing commands
*
* @param api - A PluginAPI instance
* @param options - An object containing project local options specified in vue.config.js,
* or in the "vue" field in package.json.
*/
type ServicePlugin = (
api: PluginAPI,
options: ProjectOptions
) => any
export { ProjectOptions, ServicePlugin, PluginAPI }
type UserConfig = ProjectOptions | ConfigFunction
export function defineConfig(config: UserConfig): UserConfig

View File

@ -0,0 +1,22 @@
{
"files": [
"cli-service-test.ts",
"index.d.ts",
"ProjectOptions.d.ts"
],
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"esModuleInterop": true,
"strictFunctionTypes": true,
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": "."
}
}

View File

@ -0,0 +1,12 @@
// this file is for cases where we need to access the
// webpack config as a file when using CLI commands.
let service = process.VUE_CLI_SERVICE
if (!service || process.env.VUE_CLI_API_MODE) {
const Service = require('./lib/Service')
service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
service.init(process.env.VUE_CLI_MODE || process.env.NODE_ENV)
}
module.exports = service.resolveWebpackConfig()