vue如何自定義配置運(yùn)行run命令
vue運(yùn)行根據(jù)npm和yarn不同有不同的指令,不過(guò)大同小異,常用的一般只有本地運(yùn)行和線上打包指令,vuecli3以下的為 npm run dev(本地運(yùn)行)、npm run build(線上打包);vuecli3及以上的為 npm run serve(本地運(yùn)行)、npm run build(線上打包)。
但是經(jīng)常也會(huì)遇到一種情況:線上也會(huì)有不同的環(huán)境,常用的有開發(fā)環(huán)境、測(cè)試環(huán)境、UAT環(huán)境、正式生產(chǎn)環(huán)境等等,不同的線上環(huán)境最常見的區(qū)別往往是訪問(wèn)路徑不同,請(qǐng)求地址不同,當(dāng)然這些問(wèn)題其實(shí)可以用Nginx反向代理解決,但還有一些特殊情況,比如某個(gè)功能只在正式生產(chǎn)環(huán)境開放,后端不方便用代碼,那么此時(shí)就需要前端獲取當(dāng)前打包的環(huán)境,這就是自定義配置運(yùn)行命令的意義所在,當(dāng)你運(yùn)行不同的指令生成不同環(huán)境的webpack包,必定可以獲取到當(dāng)前包的環(huán)境,可以在前端用代碼控制實(shí)現(xiàn)不同環(huán)境有不同的顯示操作
vue自定義配置運(yùn)行命令有兩種,一種是vuecli3以下,此時(shí)webpack配置文件在本地,可以根據(jù)修改本地webpack配置文件進(jìn)行自定義;一種是在vuecli3以上,此時(shí)webpack配置在服務(wù)器上,不能通過(guò)修改本地配置文件來(lái)進(jìn)行自定義,則需要通過(guò)新建vue.config.js和.env.XXX文件來(lái)進(jìn)行自定義,下面我會(huì)分別記錄操作方法
1、vuecli3以下
此時(shí)webpack配置文件在本地,修改即可,只要知道webpack的打包流程,引用了哪些文件,然后就可以據(jù)此新增修改
打包第一個(gè)文件肯定是package.json,每一個(gè)指令的執(zhí)行都定義在此
package.json
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"e2e": "node test/e2e/runner.js",
"lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
"test": "node build/test.js",
"build": "node build/build.js"
},
首先看默認(rèn)的npm run build打包,首先會(huì)執(zhí)行build文件夾下的build.js文件
build/build.js
'use strict'
require('./check-versions')()
process.env.NODE_ENV = 'production'
...
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
})
主要關(guān)注這兩條
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
這說(shuō)明build.js打包依賴config文件夾和webpack.prod.conf.js文件
下面我們?cè)倏纯磜ebpack.prod.conf.js文件
webpack.prod.conf.js
'use strict'
const utils = require('./utils')
......
const config = require('../config')
......
const baseWebpackConfig = require('./webpack.base.conf')
......
const env = process.env.NODE_ENV === 'test'
? require('../config/test.env')
: require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
......
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
? 'index.html'
: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
chunksSortMode: 'dependency'
}),
......
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
因?yàn)槠?我把一些注釋和與打包無(wú)關(guān)的代碼刪掉了,這里重點(diǎn)關(guān)注三條
const utils = require('./utils')
const config = require('../config')
const baseWebpackConfig = require('./webpack.base.conf')
這說(shuō)明webpack.prod.conf.js依賴config文件夾、webpack.base.conf.js文件和utils.js文件
我們?cè)賮?lái)看看build/utils.js文件
build/utils.js
'use strict'
const path = require('path')
const config = require('../config')
......
exports.assetsPath = function (_path) {
let assetsSubDirectory = ''
if (process.env.NODE_ENV === 'production') {
assetsSubDirectory = config.build.assetsSubDirectory
} else if (process.env.NODE_ENV === 'test') {
assetsSubDirectory = config.test.assetsSubDirectory
} else {
assetsSubDirectory = config.dev.assetsSubDirectory
}
return path.posix.join(assetsSubDirectory, _path)
}
......
可以看出utils.js依舊依賴config文件夾
build/webpack.base.conf.js
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
......
let outputPath = config.build.assetsRoot
let outputPublicPath = ''
if (process.env.NODE_ENV === 'production') {
outputPublicPath = config.build.assetsPublicPath
} else if (process.env.NODE_ENV === 'test') {
outputPath = config.test.assetsRoot
outputPublicPath = config.test.assetsPublicPath
} else {
outputPublicPath = config.dev.assetsPublicPath
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: ['babel-polyfill', './src/main.js']
},
output: {
path: outputPath,
filename: '[name].js',
publicPath: outputPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
......
]
},
node: {
setImmediate: false,
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
可以看出webpack.base.conf.js除了依賴config文件夾和utils.js文件還有一個(gè)vue-loader.conf.js文件
build/vue-loader.conf.js
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test')
let sourceMapEnabled = ''
if (process.env.NODE_ENV === 'production') {
sourceMapEnabled = config.build.productionSourceMap
} else if (process.env.NODE_ENV === 'test') {
sourceMapEnabled = config.test.productionSourceMap
} else {
sourceMapEnabled = config.dev.cssSourceMap
}
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
vue-loader.conf.js常規(guī)引用config文件夾和utils.js文件,就不單獨(dú)討論了
config文件夾
config文件夾下有多個(gè)文件,一般初始化至少有index.js、dev.env.js、prod.env.js,其中dev.env.js和prod.env.js里面是各自的專屬配置,本文想要實(shí)現(xiàn)的功能就由此類文件來(lái)完成,每個(gè)文件里都可以配置不同的請(qǐng)求域名(當(dāng)然也可以用Nginx反向代理),當(dāng)前環(huán)境的標(biāo)識(shí)等等
index.js
index.js里面就是config的常用配置,比如每個(gè)環(huán)境下的路徑、目錄、文件名等等配置都由此處配置
'use strict'
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: '0.0.0.0', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false,
useEslint: true,
showEslintErrorsInOverlay: false,
......
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './',
productionSourceMap: true,
......
},
test: {
// Template for index.html
index: path.resolve(__dirname, '../dist-test/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist-test'),
assetsSubDirectory: 'static',
assetsPublicPath: './',
......
}
}
vuecli3以下打包流程

上圖就是vuecli3以下的webpack打包流程,可以看到webpack打包大概就用到這幾個(gè)文件,當(dāng)然背后還有更多的依賴,但是我們能控制的就這幾個(gè),那么想配置一個(gè)新的指令只要按照這個(gè)流程新增或者修改對(duì)應(yīng)的文件就可以了,下面我以新增一個(gè)npm run test指令為例(因?yàn)槲乙呀?jīng)做完了這個(gè),其實(shí)上面貼出來(lái)的代碼細(xì)心的已經(jīng)看到了)
新增npm run test指令
新增文件
需要新增的文件有build/test.js、build/webpack.test.conf.js、config/test.env.js
新增在我看來(lái)是最簡(jiǎn)單的,只需要照著build的文件復(fù)制一份改名,然后把代碼里的config.build改為config.test,這里的config.build指的是config文件夾下index.js里的build對(duì)象,包含了打包時(shí)的一些配置,比如文件名,路徑等等
修改文件
需要修改的文件有package.json、build/utils.js、build/webpack.base.conf.js、build/vue-loader.conf.js、config/index.js
package.json
package.json仿照build新增一條指令,運(yùn)行build/test.js文件
build/utils.js
utils文件需要在以前判斷的基礎(chǔ)上加上一個(gè)test的判斷
更改前
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
更改后
let assetsSubDirectory = ''
if (process.env.NODE_ENV === 'production') {
assetsSubDirectory = config.build.assetsSubDirectory
} else if (process.env.NODE_ENV === 'test') {
assetsSubDirectory = config.test.assetsSubDirectory
} else {
assetsSubDirectory = config.dev.assetsSubDirectory
}
build/webpack.base.conf.js、build/vue-loader.conf.js、config/index.js等其他文件參照build/utils,將原本只對(duì)production和dev的判斷加上一個(gè)test的判斷
vuecli3以下自定義webpack打包指令小結(jié)
- 1、在package.json新增一條指令
- 2、根據(jù)新增指令在指定位置(通常是build文件夾)新增文件
- 3、新增config文件夾下自定義配置文件
- 4、修改config文件夾下index.js文件,新增對(duì)自定義配置
- 5、新增webpack conf文件
- 6、修改build/utils文件,增加對(duì)自定義的判斷
- 7、修改webpack.base.conf.js文件。增加對(duì)自定義的判斷
- 8、修改build/vue-loader.conf.js文件,增加對(duì)自定義的判斷
2、vuecli3以上
此時(shí)webpack配置文件不在本地,想要修改打包配置需新建vue.config.js文件,vue.config.js文件和vuecli3以下時(shí)config文件夾下的index.js文件一樣,保存默認(rèn)的打包配置,當(dāng)然如果沒(méi)有.env.dev和.env.prod也可以新建,這兩個(gè).env文件和vuecli3以下時(shí)config文件夾下的.env文件一樣,目的是保存當(dāng)前環(huán)境下的配置。這幾個(gè)文件都在vue項(xiàng)目第一級(jí)目錄下,與src文件夾平級(jí)。
vue.config.js
const path = require('path');
let outputDir = ''
if (process.env.VUE_APP_CURRENTMODE === 'prod') {
// 為生產(chǎn)環(huán)境修改配置...
outputDir = 'dist';
} else {
// 為開發(fā)環(huán)境修改配置...
outputDir = 'dist-test';
}
module.exports = {
// 基本路徑
publicPath: './',
// 輸出文件目錄
outputDir,
// eslint-loader 是否在保存的時(shí)候檢查
lintOnSave: true,
configureWebpack: (config) => {
config.entry.app = ["babel-polyfill", "./src/main.js"];
if (process.env.NODE_ENV === 'production') {
// 為生產(chǎn)環(huán)境修改配置...
config.mode = 'production';
} else {
// 為開發(fā)環(huán)境修改配置...
config.mode = 'development';
}
Object.assign(config, {
// 開發(fā)生產(chǎn)共同配置
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@a': path.resolve(__dirname, './src/api'),
'@u': path.resolve(__dirname, './src/utils'),
'@p': path.resolve(__dirname, './src/pages'),
'@c': path.resolve(__dirname, './src/components'),
}
}
});
},
// 生產(chǎn)環(huán)境是否生成 sourceMap 文件
productionSourceMap: true,
// enabled by default if the machine has more than 1 cores
parallel: require('os').cpus().length > 1,
// PWA 插件相關(guān)配置
// see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
pwa: {},
// webpack-dev-server 相關(guān)配置
devServer: {
open: process.platform === 'darwin',
host: '0.0.0.0',
port: 8888,
https: false,
hotOnly: false,
},
// 第三方插件配置
pluginOptions: {
// ...
}
};
新增npm run test指令
新增文件
新增.env.test文件,仿照.env.prod新建,NODE_ENV最好和prod一樣,為做區(qū)分可以配置一個(gè)字段如VUE_APP_CURRENTMODE為test與prod區(qū)分開,如果需要判斷當(dāng)前環(huán)境可以用此字段判別
NODE_ENV = 'production' VUE_APP_CURRENTMODE = 'test'
修改文件
修改vue.config.js,增加對(duì)VUE_APP_CURRENTMODE的判斷
修改前
const path = require('path');
module.exports = {
// 基本路徑
publicPath: './',
// 輸出文件目錄
outputDir,
......
}
修改后
const path = require('path');
let outputDir = ''
if (process.env.VUE_APP_CURRENTMODE === 'prod') {
// 為生產(chǎn)環(huán)境修改配置...
outputDir = 'dist';
} else {
// 為開發(fā)環(huán)境修改配置...
outputDir = 'dist-test';
}
module.exports = {
// 基本路徑
publicPath: './',
// 輸出文件目錄
outputDir,
......
}
vuecli3以上自定義webpack打包指令小結(jié)
1、默認(rèn)需有.env.dev、.env.prod、vue.config.js文件,如無(wú)可新建
2、新增.env.test文件
3、修改vue.config.js文件
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
構(gòu)建Vue大型應(yīng)用的10個(gè)最佳實(shí)踐(小結(jié))
這篇文章主要介紹了構(gòu)建Vue大型應(yīng)用的10個(gè)最佳實(shí)踐(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Vue實(shí)現(xiàn)按鈕旋轉(zhuǎn)和移動(dòng)位置的實(shí)例代碼
這篇文章主要介紹了Vue實(shí)現(xiàn)按鈕旋轉(zhuǎn)和移動(dòng)位置的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08
vue?draggable組件實(shí)現(xiàn)拖拽及點(diǎn)擊無(wú)效問(wèn)題的解決
這篇文章主要介紹了vue?draggable組件實(shí)現(xiàn)拖拽及點(diǎn)擊無(wú)效問(wèn)題的解決,只需要在設(shè)置handle屬性就可以了,.defaultTypeTag 是要拖拽的塊的類名,要注意的是需要做點(diǎn)擊事件的項(xiàng)不能包含在這個(gè)類名里面,不然會(huì)無(wú)法觸發(fā)點(diǎn)擊事件,詳細(xì)解決辦法跟隨小編一起學(xué)習(xí)吧2022-05-05
Vue+Express實(shí)現(xiàn)登錄狀態(tài)權(quán)限驗(yàn)證的示例代碼
這篇文章主要介紹了Vue+Express實(shí)現(xiàn)登錄狀態(tài)權(quán)限驗(yàn)證的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05
vue使用數(shù)組splice方法失效,且總刪除最后一項(xiàng)的問(wèn)題及解決
這篇文章主要介紹了vue使用數(shù)組splice方法失效,且總刪除最后一項(xiàng)的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Vue2實(shí)現(xiàn)自適應(yīng)屏幕大小的兩種方法詳解
這篇文章主要為大家詳細(xì)介紹了Vue2實(shí)現(xiàn)自適應(yīng)屏幕大小的兩種方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
vue項(xiàng)目里面引用svg文件并給svg里面的元素賦值
這篇文章主要介紹了vue項(xiàng)目里面引用svg文件并給svg里面的元素賦值,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
聊聊Vue中provide/inject的應(yīng)用詳解
這篇文章主要介紹了聊聊Vue中provide/inject的應(yīng)用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
更強(qiáng)大的vue ssr實(shí)現(xiàn)預(yù)取數(shù)據(jù)的方式
這篇文章主要介紹了更強(qiáng)大的 vue ssr 預(yù)取數(shù)據(jù)的方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

