github传送门:
1、h5主项目
2、项目脚手架
3、子项目模板
系列文章传送门:
vue简易微前端项目搭建(一):项目背景及简介
vue简易微前端项目搭建(二):子项目模板及项目脚手架搭建
vue简易微前端项目搭建(三):webpack相关配置
1、概述
由于项目是基于vue-cli4改造的,所以webpack相关配置我们就在vue.config.js里操刀,没有该文件的直接在项目根目录新建vue.config.js即可,具体配置api参考官方文档(传送门)
2、process.env
先说一下这个,因为后面会用到这里存储的变量值。
在系列文章上一篇中说到了.env文件,里面定义的变量会自动加入到process.env变量中,具体参考官方说明:传送门
这里再简单说明一下,先看目录:
(1) .env 这个是全局共用的
# 定义api地址的代理标识
VUE_APP_PROXY_CODE = '/proxy'
# 定义路由history模式是否开启(1开启 0关闭)
VUE_APP_HISTORY_OPEN = 0
# 定义路由history模式下项目在服务器上部署的基路径
VUE_APP_HISTORY_BASE = '/h5'
# 定义h5版本号
VUE_APP_H5_VERSION = '2.1.9.0'
(2).env.prod
这个是通过指定prod环境运行脚手架命令时会启用的
# 定义环境模式
VUE_APP_SERVER_ENV = 'prod'
# 定义服务器基础地址
VUE_APP_SERVER_URL = 'https://prod.com'
(3) 其他.env
其他的 .env.test 和 .env.beta 用法同上
(4)示例
例如运行脚手架命令:dyd start demo prod,能获取到的process.env变量有:
- .env文件里启用的:
process.env.VUE_APP_PROXY_CODE
process.env.VUE_APP_HISTORY_OPEN
process.env.VUE_APP_HISTORY_BASE
process.env.VUE_APP_H5_VERSION
- .env.prod文件里启用的:
process.env.VUE_APP_SERVER_ENV
process.env.VUE_APP_SERVER_URL
- 还有获取到的子项目名(代码目录:/build/processEnv.js):
process.env.VUE_APP_PROJECT_NAME = process.argv[3].split('---')[1]
- 还有自带的process.env.NODE_ENV
我这里做了改动,本地运行时值为development,打包时值为production(代码目录:/build/processEnv.js):
// 设置NODE_ENV
const runType = process.argv[2]
if (runType === 'serve') {
// 本地运行 npm run serve
process.env.NODE_ENV = 'development'
} else if (runType === 'build') {
// 打包项目 npm run build
process.env.NODE_ENV = 'production'
}
3、vue.config.js
所有配置改动最终都汇聚在这里,按照vue-cli官方配置导出一个配置对象即可。
(1)获取子项目名
前面已经把获取到的子项目存储到process.env.VUE_APP_PROJECT_NAME 里了
const projectName = process.env.VUE_APP_PROJECT_NAME
(2)入口文件及html模板
在chainWebpack里进行配置:
chainWebpack: config => {
// 入口文件
config
.entry('app')
.clear()
.add(`./src/projects/${projectName}/main.js`)
// html模板文件
config
.plugin('html')
.tap(args => {
args[0].template = `./src/projects/${projectName}/index.html`
args[0].templateParameters = {
FAVICON_PATH: './favicon.ico'
}
return args
})
},
(3)打包输出目录
子项目按文件夹进行了划分,那打包后文件也同样需要划分开,并列在dist文件夹里即可
outputDir: `dist/${projectName}`,
(4)部署应用的基路径
开启路由history模式和不开启的配置不太一样:
- 开启history模式时,基路径为 在服务器域名上部署的基目录 + 子项目名
- 未开启时,打包项目用相对路径 ‘./’,本地运行用绝对路径 ‘/’
publicPath: +process.env.VUE_APP_HISTORY_OPEN
? `${process.env.VUE_APP_HISTORY_BASE}/${projectName}`
: (process.env.NODE_ENV === 'production' ? './' : '/'),
process.env.VUE_APP_HISTORY_OPEN 和 process.env.VUE_APP_HISTORY_BASE 都配置在了.env文件里。
(5)代理服务配置
首先获取代理转发地址,还记得子项目模板里的config.js吗,本地dev启动就读取这个文件的地址:
// 获取代理服务器基础地址
let proxyServerUrl = process.env.VUE_APP_SERVER_URL
if (process.env.VUE_APP_SERVER_ENV === 'dev') {
const ChildProjectConfig = require(resolve(`./src/projects/${projectName}/config.js`))
proxyServerUrl = ChildProjectConfig.devServerUrl
}
然后配置devServer:
devServer: {
host: '0.0.0.0',
port: 8800,
open: false, // 是否自动打开浏览器
progress: false, // 是否显示进度
proxy: {
[process.env.VUE_APP_PROXY_CODE]: {
target: proxyServerUrl,
ws: true,
changeOrigin: true,
secure: false,
pathRewrite: {
['^' + `${process.env.VUE_APP_PROXY_CODE}/${process.env.VUE_APP_SERVER_ENV}`]: ''
}
}
}
},
(6)alias快捷路径标识
也是在chainWebpack里配置:
chainWebpack: config => {
config.resolve.alias
.set('@@', resolve('./src/resources'))
.set('@', resolve(`./src/projects/${projectName}`))
}
(7)去除prefetch
prefetch是一种性能优化方式,支持的浏览器会在空闲时提前下载解析,对于路由懒加载来说,这个功能会在你打开一个路由后把其他路由文件都加载下来,对于一整个关联性强的项目来说比较适用,比如后台管理系统,而对于本项目来说,主要应用场景是混合app内嵌h5页,页面比较分散,还有各种一次性活动页什么的,通常都会划分类别放在一个子项目里,不需要提前加载其他路由,所以不适合prefetch技术。
chainWebpack: config => {
config.plugins
.delete('prefetch')
}
(8)静态不打包目录
- 有时候需要引用第三方打包好的js文件,而这种文件一般不能做二次打包,就需要个静态不打包目录,vue-cli官方提供的public文件夹是可以,但子项目里的都扔进去也不合适,还是单独配置为好,
- 之前的子项目模板里默认有个static文件夹,就是预留给这个的,
- 通过configureWebpack里配置plugins,插件使用copy-webpack-plugin
const CopyWebpackPlugin = require('copy-webpack-plugin')
configureWebpack: config => {
const copyWebpackPlugin = new CopyWebpackPlugin([
{
from: Path.resolve(__dirname, '../src/projects/', projectName, 'static'),
to: 'static',
ignore: ['.*']
}
])
// 更新config
config.plugins = [...config.plugins, copyWebpackPlugin]
},
4、完整代码
vue.config.js
/**
* Created by hanxueqiang on 19/11/13
*/
require('./build/processEnv.js')
const Path = require('path')
const Plugins = require('./build/plugins')
const projectName = process.env.VUE_APP_PROJECT_NAME
function resolve (dir) {
return Path.resolve(__dirname, dir)
}
// 获取代理服务器基础地址
let proxyServerUrl = process.env.VUE_APP_SERVER_URL
if (process.env.VUE_APP_SERVER_ENV === 'dev') {
const ChildProjectConfig = require(resolve(`./src/projects/${projectName}/config.js`))
proxyServerUrl = ChildProjectConfig.devServerUrl
}
module.exports = {
publicPath: +process.env.VUE_APP_HISTORY_OPEN
? `${process.env.VUE_APP_HISTORY_BASE}/${projectName}`
: (process.env.NODE_ENV === 'production' ? './' : '/'),
outputDir: `dist/${projectName}`,
productionSourceMap: false,
lintOnSave: process.env.NODE_ENV !== 'production',
// 开发环境服务配置
devServer: {
host: '0.0.0.0',
port: 8800,
open: false,
progress: false,
proxy: {
[process.env.VUE_APP_PROXY_CODE]: {
target: proxyServerUrl,
ws: true,
changeOrigin: true,
secure: false,
pathRewrite: {
['^' + `${process.env.VUE_APP_PROXY_CODE}/${process.env.VUE_APP_SERVER_ENV}`]: ''
}
}
}
},
// 合并webpack配置
configureWebpack: config => {
// 性能提示
let myPerformance = {}
if (process.env.NODE_ENV === 'production') {
myPerformance = {
hints: 'warning',
maxEntrypointSize: 1024000,
maxAssetSize: 1024000
}
config.plugins.forEach(v => {
if (v.constructor.name === 'MiniCssExtractPlugin') {
// 去除 mini-css-extract-plugin 警告
v.options.ignoreOrder = true
}
})
}
// 更新config
config.plugins = [...config.plugins, ...Plugins]
config.performance = { ...config.performance, ...myPerformance }
},
// 修改webpack配置
chainWebpack: config => {
config.resolve.alias
.set('@@', resolve('./src/resources'))
.set('@', resolve(`./src/projects/${projectName}`))
config
.entry('app')
.clear()
.add(`./src/projects/${projectName}/main.js`)
config
.plugin('html')
.tap(args => {
args[0].template = `./src/projects/${projectName}/index.html`
args[0].templateParameters = {
FAVICON_PATH: './favicon.ico'
}
return args
})
// config.plugins
// .delete('preload')
config.plugins
.delete('prefetch')
// chunk分离优化
config.optimization
.splitChunks({
chunks: 'all',
maxAsyncRequests: 8,
maxInitialRequests: 6,
minSize: 20000,
cacheGroups: {
vue: {
name: 'chunk-vue',
test: /[\\/]node_modules[\\/](vue|vue-router)[\\/]/,
priority: 40
},
vconsole: {
name: 'chunk-vconsole',
test: /[\\/]node_modules[\\/]vconsole[\\/]/,
priority: 30
},
vendors: {
name: 'chunk-vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
})
},
// 指定babel-loader要编译的node_modules包
transpileDependencies: [],
css: {
loaderOptions: {
less: {
globalVars: {
'@imgBaseGlobal': '~@@/assets/images/',
'@imgBase': '~@/assets/images/'
}
}
}
}
}