使用vue-cli開發項目,免不了需要做些配置。特別是項目比較復雜時。這里列出一些有用的配置。當然,每個項目需求不同,或許對你來說,這并不實用。
這里所用的都是基于vue-cli3的配置哦。vue是2.x的。還在用vue-cli2的童鞋,該換新了,比較vue3都出來了,當然了,老項目可能沒辦法(我說的是沒辦法去升級成vue-cli3,可能因為時間成本,想要這些配置,也是可以的,只是寫法和這里有區別罷了),至于vue3的,還沒去研究額,再說vue3多了個vite。
基本路徑 publickPath
如果你的項目部署在根目錄下,這或許不用去管。但是,如果項目部署在子路徑下,那就得改下咯
配置代碼示例:
module.exports={
publicPath: '/system/',
}
其中,system是訪問項目的子路徑,這里是和服務器對應的。也就是前端瀏覽器通過輸入http://test.com/system/類似的路徑訪問項目首頁
生產環境自動刪除console.log
應該 有很多程序員像我一樣,喜歡用console.log調試吧。額,雖然有人推薦debug,或者其他工具。但是習慣了console.log,也還沒到必須改的時候。但是,生產環境下,如果打印一大堆console.log,那體驗是不好的。當然如果你習慣看完就刪除或者注釋,也很好。這里說的是針對比較懶的那種人,比如我,不想動手,那就只能動代碼咯。
配置有多種方法,這里使用TerserPlugin插件
配置代碼示例:
const TerserPlugin=require('terser-webpack-plugin')
const isProduction = process.env.NODE_ENV === 'production'
module.exports={
configureWebpack: config => {
if (isProduction) {
// 為生產環境修改配置...
config.plugins.push(
//生產環境自動刪除console
new TerserPlugin({
terserOptions: {
ecma: undefined,
warnings: false,
parse: {},
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: ['console.log'] // 移除console
}
},
sourceMap: false,
parallel: true,
})
)
)
}
}
}
這里要注意的是terser-webpack-plugin版本,版本通常不能太高,插件沒有做向下兼容,我這里vue版本是2.6,terser-webpack-plugin版是 "^3.1.0",反正如果你已經安裝了以來,弄上去,報錯莫名其妙說什么東西沒有,那就是版本不兼容,通常需要降級。
開啟gip壓縮
開啟gzp壓縮是優化代碼體積用的,如果項目不大,那也沒必要。開啟gip壓縮需要后端配合才能生效,這里之說前端的配置。
使用 CompressionWebpackPlugin 插件
配置代碼示例:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const isProduction = process.env.NODE_ENV === 'production'
module.exports={
configureWebpack: config => {
if (isProduction) {
// 開啟gzp壓縮
config.plugins.push(
new CompressionWebpackPlugin({
// 正在匹配需要壓縮的文件后綴
test: /\.(js|css|svg|woff|ttf|json|html)$/,
// 大于10kb的會壓縮
threshold: 10240
// 其余配置查看compression-webpack-plugin
})
)
}
}
}
這里要注意的是CompressionWebpackPlugin版本,版本通常不能太高,插件沒有做向下兼容,我這里vue版本是2.6,CompressionWebpackPlugin版是 "^5.0.0"。反正如果你已經安裝了以來,弄上去,報錯莫名其妙說什么東西沒有,那就是版本不兼容,通常需要降級。
生成zip文件
懶人的福音,打包后,是不是要弄成壓縮包發給后端或者運營部署?可是就是不想動手!那就只能動代碼唄。當然,這可能帶來的后果就是,打包需要 更多的時間,因為需要處理文件,弄成zip。
需要使用兩個插件,BundleAnalyzerPlugin和FileManagerPlugin,結合node-cmd插件,并定義一個自己打開文件夾的類OpenFolderPlugin。很暖心有木有,文件夾都給你打開了,還想怎樣???
配置代碼示例:
const cmd = require("node-cmd")
const FileManagerPlugin = require("filemanager-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
const OUTPUT_FILE_NAME='my-zip-file-test' //這里定義最終打包的zip文件名,和文件夾名稱
class OpenFolderPlugin {
apply(compiler) {
compiler.hooks.done.tap("Open Folder Plugin", function() {
cmd.run("start .\\dist");
});
}
}//這是打開文件夾的類
module.exports={
// 輸出文件目錄
outputDir: `dist/${OUTPUT_FILE_NAME}`,
configureWebpack: config => {
if (["build", "build-dev"].includes(process.env.npm_lifecycle_event)) {
const outputFile = `./dist/${OUTPUT_FILE_NAME}.zip`;
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: "disabled",
generateStatsFile: true,
statsFilename: "../stats.json"http://這里是生成代碼分析文件,可以查看代碼性能喲。當然主要針對包模塊體積
}),
new FileManagerPlugin({
events:{
onStart:{
delete: ['./dist/'],
},
onEnd: {
archive: [
{
source: `./dist/${OUTPUT_FILE_NAME}`,
destination: outputFile
}
]
}
}
}),//這個webpack插件的功能挺多的,這里只用兩個,開始打包事件和打包結束事件,我們打包后的文件依然放在dist文件夾里面,只是里面多了分析文件,zip文件,還有吧未壓縮的生產環境用的文件單獨放在一個文件夾里面
new OpenFolderPlugin()
);
}
}
}
同樣,這里也要注意版本問題,因為這些插件到一定版本后,就會不兼容之前的版本。這里著實想吐槽一下,不過人家肯定也有難言之隱不是。我們就自己小心點了。
filemanager-webpack-plugin和webpack-bundle-analyzer,我這里都是用4.4.0版本哦。高了會報錯的,不兼容。
build和build-dev是打包運行的命令,這里是監聽命令的,因為我們只需要在打包時采用這個配置,通常來說,都是npm run build,如果你改了命令,這里也要做相應的更改。
微前端——乾坤 qiankun.js子項目配置
如果項目中使用了微前端,并且是使用qiankun開發的,那么這里就用上了。當然,只需要配置子項目,主項目不需要這個配置。
配置代碼示例:
const {name} = require('./package')
module.exports={
devServer: {
port:6661,//因為主項目需要通過訪問地址去訪問子項目,所以端口最好不要配置成容易被占用的,否則一旦你啟動多個項目,可能就得該代碼里面的訪問路徑
// 允許被主應用跨域fetch請求到,這里是必須的,不然跨越無法訪問
headers: {
'Access-Control-Allow-Origin':'*'
},
},
//需要配置打包模式,不然qiankun無法獲取。不要問為什么,qiankun要求的,可以問問qiankun為啥要這么做。當然這里要說的是,qiankun會通過package里面的包名去讀取文件,所以name必須是package的包名,不然獲取文件會失敗
configureWebpack: config=>{
// console.log(config)
config.output.library=name
config.output.libraryTarget= 'umd'
config.output.jsonpFunction=`webpackJsonp_${name}`
}
}
反向代理配置
什么時候需要配置反向代理?
開發換跨越,那是肯定出現的,因為是前后端分離項目,但是生產環境下,又不跨越,因為訪問域名和api請求域名是一致的了(當然如果不一致,也會跨越,但是這不是前端能解決的了)。這種情況下,我們不需要后端小伙伴或者運維去解決,前端配置反向代理就好了,而且用起來也省心,因為不需要在請求接口的時候加上域名。
通常來說,一個項目的請求域名,只有一個,如果項目使用hash模式,那么就簡單很多,直接在proxy那里寫上api域名即可。
如果使用了history模式,就不能這樣了,這會和服務器沖突的,必須要匹配路徑去配置。這里示例一下history模式的配置。
//因為可能會有很多個路徑匹配,這里不想寫一大串if語句,所以,搞了個函數,使用循環。
//其中,/code,/admin,/auth是api請求除去域名的部分的開頭,例如請求api路徑是 http://test.com/admin/user/add-user-info
let proxys=function (){
let apiPathArr=['/code','/auth','/admin']
let proxys={}
for(let i=0;i<apiPathArr.length;i++){
proxys[apiPathArr[i]]={
target: 'http://10.2.100.20',
ws: false,
changeOrigin: true,
pathRewrite:{
[`^${apiPathArr[i]}`]:apiPathArr[i]
}
}
}
return proxys
}()
module.exports={
devServer: {
proxy:proxys,// 配置多個代理
},
}
暫時就這些了,下面給個完整的代碼
const cmd = require("node-cmd")
const {name} = require('./package')
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const TerserPlugin=require('terser-webpack-plugin')
const isProduction = process.env.NODE_ENV === 'production'
const FileManagerPlugin = require("filemanager-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
const OUTPUT_FILE_NAME='loudi-wisdom-construction-site'
class OpenFolderPlugin {
apply(compiler) {
compiler.hooks.done.tap("Open Folder Plugin", function() {
cmd.run("start .\\dist");
});
}
}
let proxys=function (){
let apiPathArr=['/code','/auth','/admin']
let proxys={}
for(let i=0;i<apiPathArr.length;i++){
proxys[apiPathArr[i]]={
target: 'http://10.2.100.20',
ws: false,
changeOrigin: true,
pathRewrite:{
[`^${apiPathArr[i]}`]:apiPathArr[i]
}
}
}
return proxys
}()
module.exports = {
// 基本路徑
publicPath: '/system/',
// 輸出文件目錄
outputDir: `dist/${OUTPUT_FILE_NAME}`,
configureWebpack: config => {
config.output.library=name
config.output.libraryTarget= 'umd'
config.output.jsonpFunction=`webpackJsonp_${name}`
if (isProduction) {
// 為生產環境修改配置...
config.plugins.push(
//生產環境自動刪除console
new TerserPlugin({
terserOptions: {
ecma: undefined,
warnings: false,
parse: {},
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: ['console.log'] // 移除console
}
},
parallel: true,
})
)
// 開啟gzp壓縮
config.plugins.push(
new CompressionWebpackPlugin()
)
}
if (["build", "build-dev"].includes(process.env.npm_lifecycle_event)) {
const outputFile = `./dist/${OUTPUT_FILE_NAME}.zip`;
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: "disabled",
generateStatsFile: true,
statsFilename: "../stats.json"
}),
new FileManagerPlugin({
events:{
onStart:{
delete: ['./dist/'],
},
onEnd: {
archive: [
{
source: `./dist/${OUTPUT_FILE_NAME}`,
destination: outputFile
}
]
}
}
}),
new OpenFolderPlugin()
);
}
},
devServer: {
open: false, //配置自動啟動瀏覽器,想自動打開就設為true
port:6661,
// 允許被主應用跨域fetch請求到
headers: {
'Access-Control-Allow-Origin':'*'
},
proxy:proxys,// 配置多個代理
},
}