vxiao

悟已往之不谏,知来者之可追。实迷途其未远,觉今是而昨非。

0%

Vue项目自定义配置文件

  • Vue CLI为2.x
  • 目录结构与3.x、4.x不一致. webpack使用方式可参考

项目目录

区分develop环境和production环境

打包前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
├── build                                       // webpack配置文件
│ ├── build.js
│ ├── check-versions.js
│ ├── custom.conf.js // 引入自定义配置文件
│ ├── utils.js
│ ├── version.js // 打包时获取版本信息
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ ├── webpack.prod.conf.js
├── assets
│ ├── utils.js // 业务代码获取全局变量的入口
├── version
│ ├── index.html // Git版本信息(html模板)
├── static // 静态文件
│ ├── dev // 仅dev使用
│ │ ├── config.js // 配置文件
│ │ ├── config.json // 配置文件
├── index.html

打包后

1
2
3
4
5
├── index.html                                  // 入口文件
├── static // 项目打包路径
├── config // 源码目录
│ ├── config.js // 配置文件
│ ├── config.json // 公共组件

方案一:通过json文件存储全局变量

Vue项目中使用axios库 加载.json文件

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用axios发送请求
import Axios from 'axios'
// 区分调试环境与产品环境
let configPath = {
production: './config/',
development: './static/dev/'
}
// 文件夹路径
let folder = configPath[process.env.NODE_ENV]
// 配置路径
let path = folder + `config.json?v=${Math.random()}`
// 请求
Axios.get(path).then(result => {})

方案二:通过js文件存储全局变量

config.js存储全局变量

1
2
3
/* eslint-disable */
const CMP_SCROLL_LOAD = 1 // 控件滚动加载 0否1是
const WINDOW_RESIZE_RENDER = 1 //控件滚动加载 页面变化时渲染 0否1是

utils.js由业务代码调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 控件是否滚动加载
*/
export function isCmpScrollLoad () {
let isScroll = true
/* eslint-disable */
try {
if (CMP_SCROLL_LOAD === 0) {
isScroll = false
}
} catch (e) {}

/* eslint-enable */
return isScroll
}
/**
* 控件滚动加载 页面变化时渲染
*/
export function isResizeRender () {
let isResizeRender = true
/* eslint-disable */
try {
if (WINDOW_RESIZE_RENDER === 1) {
isResizeRender = true
}
} catch (e) {}

/* eslint-enable */
return isResizeRender
}

custom.conf.js用于导出config.js的路径,

1
2
3
4
5
6
7
8
9
10
// 自定义配置项路径
exports.getPath = NODE_ENV => {
// console.log(process)
if (NODE_ENV === 'prod') {
return './config/config.js?v=' + Math.random()
}
if (NODE_ENV === 'dev') {
return './static/dev/config.js?v=' + Math.random()
}
}

webpack.prod.conf.js通过webpack插件HtmlWebpackPlugin导出到index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 自定义配置
const customCfgPath = customConfig.getPath('prod')

new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency',
customCfgPath: customCfgPath,
isLoLoading: isLoLoading
})

在index.html中通过ejs语法引入

1
<script src="<%= htmlWebpackPlugin.options.customCfgPath %>"></script>

扩展

记录版本信息

在每次打包时记录git的commit信息、打包人信息等

1.新建模板文件version.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1,IE=11,IE=10">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes" />
<title>版本声明</title>
</head>

<body>
<p>commit: <%= htmlWebpackPlugin.options.buildInfo.commit %></p>
<p>commitUserName: <%= htmlWebpackPlugin.options.buildInfo.commitUserName %></p>
<p>commitDate: <%= htmlWebpackPlugin.options.buildInfo.commitDate %></p>
<p>buildUserName: <%= htmlWebpackPlugin.options.buildInfo.buildUserName %></p>
<p>buildUserMail: <%= htmlWebpackPlugin.options.buildInfo.buildUserMail %></p>
<p>buildDate: <%= htmlWebpackPlugin.options.buildInfo.buildDate %></p>
</body>

</html>

2.新建version.js用于执行命令、并导出获取的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const child_process = require('child_process')

// git 最后一次提交的 Head
const commit = child_process.execSync('git show -s --format=%H').toString().trim()
const commitUserName = child_process.execSync('git show -s --format=%cn').toString().trim()
const commitUserMail = child_process.execSync('git show -s --format=%ce').toString().trim()
const commitDateObj = new Date(child_process.execSync(`git show -s --format=%cd`).toString())
const commitDate = `${commitDateObj.getFullYear()+'-'+(commitDateObj.getMonth()+1)+'-'+commitDateObj.getDate()+' '+commitDateObj.getHours()+':'+commitDateObj.getMinutes()}`
const buildUserName = child_process.execSync('git config user.name').toString().trim()
const buildUserMail = child_process.execSync('git config user.email').toString().trim()
const nowDate = new Date()
const buildDate = `${nowDate.getFullYear()+'-'+(nowDate.getMonth()+1)+'-'+nowDate.getDate()+' '+nowDate.getHours()+':'+nowDate.getMinutes()}`

module.exports = {commit, commitUserName, commitUserMail, commitDate, buildUserName, buildUserMail, buildDate}

3.在webpack.prod.conf.js文件中 新增一个HtmlWebpackPlugin插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 打包版本信息
const BuildConfig = require('./version.js')

new HtmlWebpackPlugin({
filename: './static/version.html',
template: 'version/index.html',
inject: false,//不插入生成的js 仅用于版本声明
minify: {
removeComments: false,
collapseWhitespace: true,
removeAttributeQuotes: true
},
buildInfo: BuildConfig
})
  1. 执行npm run build后会在dist/static/version目录下生成index.html
    直接访问index.html可看到打包版本信息

打包时传入自定义参数

如判断npm run build -loloding

1
2
3
4
// 使用自定义loading
exports.isLoLoading = () => {
return !!process.env.npm_config_loloading
}

打包时忽略某些文件

使用CopyWebpackPlugin插件,例如忽略static/dev文件夹

1
2
3
4
5
6
7
8
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*', 'dev/**/*']
}
])

打包时去除colose.log和debugger

使用UglifyJsPlugin插件

1
2
3
4
5
6
7
8
9
10
11
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_debugger: true,
drop_console: true
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
})

完整代码

webpack.prod.conf.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const customConfig = require('./custom.conf.js')

const env = require('../config/prod.env')
// 打包版本信息
const BuildConfig = require('./version.js')
// 自定义配置
const customCfgPath = customConfig.getPath('prod')
// 自定义加载动画
const isLoLoading = customConfig.isLoLoading()

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: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_debugger: true,
drop_console: true
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency',
customCfgPath: customCfgPath,
isLoLoading: isLoLoading
}),
new HtmlWebpackPlugin({
filename: './static/version.html',
template: 'version/index.html',
inject: false,//不插入生成的js 仅用于版本声明
minify: {
removeComments: false,
collapseWhitespace: true,
removeAttributeQuotes: true
},
buildInfo: BuildConfig
}),
// keep module.id stable when vendor modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),

// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*', 'dev/**/*']
}
])
]
})

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

custom.conf.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 自定义配置项路径
exports.getPath = NODE_ENV => {
// console.log(process)
if (NODE_ENV === 'prod') {
return './config/config.js?v=' + Math.random()
}
if (NODE_ENV === 'dev') {
return './static/dev/config.js?v=' + Math.random()
}
}
// 使用自定义loading
exports.isLoLoading = () => {
return !!process.env.npm_config_loloading
}