vue如何自定義配置運行run命令
vue運行根據(jù)npm和yarn不同有不同的指令,不過大同小異,常用的一般只有本地運行和線上打包指令,vuecli3以下的為 npm run dev(本地運行)、npm run build(線上打包);vuecli3及以上的為 npm run serve(本地運行)、npm run build(線上打包)。
但是經(jīng)常也會遇到一種情況:線上也會有不同的環(huán)境,常用的有開發(fā)環(huán)境、測試環(huán)境、UAT環(huán)境、正式生產(chǎn)環(huán)境等等,不同的線上環(huán)境最常見的區(qū)別往往是訪問路徑不同,請求地址不同,當(dāng)然這些問題其實可以用Nginx反向代理解決,但還有一些特殊情況,比如某個功能只在正式生產(chǎn)環(huán)境開放,后端不方便用代碼,那么此時就需要前端獲取當(dāng)前打包的環(huán)境,這就是自定義配置運行命令的意義所在,當(dāng)你運行不同的指令生成不同環(huán)境的webpack包,必定可以獲取到當(dāng)前包的環(huán)境,可以在前端用代碼控制實現(xiàn)不同環(huán)境有不同的顯示操作
vue自定義配置運行命令有兩種,一種是vuecli3以下,此時webpack配置文件在本地,可以根據(jù)修改本地webpack配置文件進(jìn)行自定義;一種是在vuecli3以上,此時webpack配置在服務(wù)器上,不能通過修改本地配置文件來進(jìn)行自定義,則需要通過新建vue.config.js和.env.XXX文件來進(jìn)行自定義,下面我會分別記錄操作方法
1、vuecli3以下
此時webpack配置文件在本地,修改即可,只要知道webpack的打包流程,引用了哪些文件,然后就可以據(jù)此新增修改
打包第一個文件肯定是package.json,每一個指令的執(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打包,首先會執(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')
這說明build.js打包依賴config文件夾和webpack.prod.conf.js文件
下面我們再看看webpack.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
因為篇幅原因,我把一些注釋和與打包無關(guān)的代碼刪掉了,這里重點關(guān)注三條
const utils = require('./utils') const config = require('../config') const baseWebpackConfig = require('./webpack.base.conf')
這說明webpack.prod.conf.js依賴config文件夾、webpack.base.conf.js文件和utils.js文件
我們再來看看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文件還有一個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文件,就不單獨討論了
config文件夾
config文件夾下有多個文件,一般初始化至少有index.js、dev.env.js、prod.env.js,其中dev.env.js和prod.env.js里面是各自的專屬配置,本文想要實現(xiàn)的功能就由此類文件來完成,每個文件里都可以配置不同的請求域名(當(dāng)然也可以用Nginx反向代理),當(dāng)前環(huán)境的標(biāo)識等等
index.js
index.js里面就是config的常用配置,比如每個環(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打包大概就用到這幾個文件,當(dāng)然背后還有更多的依賴,但是我們能控制的就這幾個,那么想配置一個新的指令只要按照這個流程新增或者修改對應(yīng)的文件就可以了,下面我以新增一個npm run test指令為例(因為我已經(jīng)做完了這個,其實上面貼出來的代碼細(xì)心的已經(jīng)看到了)
新增npm run test指令
新增文件
需要新增的文件有build/test.js、build/webpack.test.conf.js、config/test.env.js
新增在我看來是最簡單的,只需要照著build的文件復(fù)制一份改名,然后把代碼里的config.build改為config.test,這里的config.build指的是config文件夾下index.js里的build對象,包含了打包時的一些配置,比如文件名,路徑等等
修改文件
需要修改的文件有package.json、build/utils.js、build/webpack.base.conf.js、build/vue-loader.conf.js、config/index.js
package.json
package.json仿照build新增一條指令,運行build/test.js文件
build/utils.js
utils文件需要在以前判斷的基礎(chǔ)上加上一個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,將原本只對production和dev的判斷加上一個test的判斷
vuecli3以下自定義webpack打包指令小結(jié)
- 1、在package.json新增一條指令
- 2、根據(jù)新增指令在指定位置(通常是build文件夾)新增文件
- 3、新增config文件夾下自定義配置文件
- 4、修改config文件夾下index.js文件,新增對自定義配置
- 5、新增webpack conf文件
- 6、修改build/utils文件,增加對自定義的判斷
- 7、修改webpack.base.conf.js文件。增加對自定義的判斷
- 8、修改build/vue-loader.conf.js文件,增加對自定義的判斷
2、vuecli3以上
此時webpack配置文件不在本地,想要修改打包配置需新建vue.config.js文件,vue.config.js文件和vuecli3以下時config文件夾下的index.js文件一樣,保存默認(rèn)的打包配置,當(dāng)然如果沒有.env.dev和.env.prod也可以新建,這兩個.env文件和vuecli3以下時config文件夾下的.env文件一樣,目的是保存當(dāng)前環(huán)境下的配置。這幾個文件都在vue項目第一級目錄下,與src文件夾平級。
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 是否在保存的時候檢查 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ū)分可以配置一個字段如VUE_APP_CURRENTMODE為test與prod區(qū)分開,如果需要判斷當(dāng)前環(huán)境可以用此字段判別
NODE_ENV = 'production' VUE_APP_CURRENTMODE = 'test'
修改文件
修改vue.config.js,增加對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文件,如無可新建
2、新增.env.test文件
3、修改vue.config.js文件
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue3路由配置createRouter、createWebHistory、useRouter和useRoute詳解
Vue3和Vue2基本差不多,只不過需要將createRouter、createWebHistory從vue-router中引入,再進(jìn)行使用,下面這篇文章主要給大家介紹了關(guān)于Vue3路由配置createRouter、createWebHistory、useRouter和useRoute的相關(guān)資料,需要的朋友可以參考下2023-02-02從Vuex中取出數(shù)組賦值給新的數(shù)組,新數(shù)組push時報錯的解決方法
今天小編就為大家分享一篇從Vuex中取出數(shù)組賦值給新的數(shù)組,新數(shù)組push時報錯的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09Vuex處理用戶Token過期及優(yōu)化設(shè)置封裝本地存儲操作模塊
這篇文章主要為大家介紹了Vuex處理用戶Token優(yōu)化設(shè)置封裝本地存儲操作模塊及Token?過期問題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09詳解Vue項目編譯后部署在非網(wǎng)站根目錄的解決方案
這篇文章主要介紹了Vue項目編譯后部署在非網(wǎng)站根目錄的解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04vue?proxytable代理根路徑的同時增加其他代理方式
這篇文章主要介紹了vue?proxytable代理根路徑的同時增加其他代理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04利用vue + element實現(xiàn)表格分頁和前端搜索的方法
眾所周知Element 是一套 Vue.js 后臺組件庫,它能夠幫助你更輕松更快速地開發(fā)后臺項目。下面這篇文章主要給大家介紹了關(guān)于利用vue + element實現(xiàn)表格分頁和前端搜索的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-12-12