1. 安装postCss
npm install postcss-plugin-px2rem@0.8.1
// 配置postcss
const px2rem = require('postcss-plugin-px2rem')
const postcss = px2rem({
rootValue: 16, // 换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
exclude: /(node_module)/, // 默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
// selectorBlackList: [], //要忽略并保留为px的选择器
// ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
// replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
mediaQuery: false, // (布尔值)允许在媒体查询中转换px。
minPixelValue: 3 // 设置要替换的最小像素值(3px会被转rem)。 默认 0
})
css: {
loaderOptions: {
postcss: {
plugins: [
postcss // 配置postcss
]
},
scss: {
// 全局使用的scss
prependData: `@import "~@/styles/mixin.scss";`
}
}
},
2. 单线程压缩js代码(速度慢)
“uglifyjs-webpack-plugin”: “^2.2.0”
// 代码压缩
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
configureWebpack: config => {
// 代码压缩
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
output: {
// 是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,可以设置为false
beautify: false,
// 是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为false
comments: false
},
// 生产环境自动删除console
compress: {
// warnings: false, // 若打包错误,则注释这行
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
})
)
}
3. 多线程js代码压缩(第三方不维护)
“webpack-parallel-uglify-plugin”: “^1.1.4”
// 多线程js压缩
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
configureWebpack: config => {
// JS多线程压缩
config.plugins.push(
new ParallelUglifyPlugin({
cacheDir: '.cache/',
test: /.js$/,
uglifyJS: {
output: {
beautify: false,
comments: false
},
warnings: false,
compress: {
drop_console: true,
collapse_vars: true,
reduce_vars: true
}
},
sourceMap: false
})
)
}
4 terser JS多线程压缩(官方维护)
npm i terser-webpack-plugin@1.4.5
// 多线程官方js压缩
const TerserPlugin = require('terser-webpack-plugin')
configureWebpack: config => {
config.plugins.push(
new TerserPlugin({
terserOptions: {
ecma: undefined,
warnings: false,
parse: {},
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: ['console.log'] // 移除console
}
}
})
)
}
5. 图形化分析压缩体积
“webpack-bundle-analyzer”: “^4.5.0”,
// 实时查看构建分析
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const analyzer = new BundleAnalyzerPlugin({
analyzerPort: 9999
})
config.plugin('webpack-bundle-analyzer').use(analyzer)
6.0 压缩css代码
npm i optimize-css-assets-webpack-plugin@5.0.4
// optimizeCssPlugin CSS文件压缩插件
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin')
// 压缩css
config.optimization.minimizer.push(
new OptimizeCssPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: { removeAll: true }},
canPrint: true
})
)
7.0 Gzip
npm i compression-webpack-plugin@5.0.1
// gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// gzip压缩
// const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|css|json|txt|ico|svg)(\?.*)?$/i,
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
配置的全部代码
'use strict'
const path = require('path')
// 配置postcss
const px2rem = require('postcss-plugin-px2rem')
const postcss = px2rem({
rootValue: 16, // 换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
exclude: /(node_module)/, // 默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
// selectorBlackList: [], //要忽略并保留为px的选择器
// ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
// replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
mediaQuery: false, // (布尔值)允许在媒体查询中转换px。
minPixelValue: 3 // 设置要替换的最小像素值(3px会被转rem)。 默认 0
})
// cdn链接
const cdn = {
// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)
externals: {
vue: 'Vue',
vuex: 'Vuex',
vant: 'vant',
'vue-router': 'VueRouter',
axios: 'axios',
moment: 'moment',
'vue-clipboard2': 'VueClipboard'
},
// cdn的css链接
css: [
'https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css'
],
// cdn的js链接
js: [
'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js',
'https://unpkg.com/vue-router@3.2.0/dist/vue-router.min.js',
'https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js',
'https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js',
'https://cdn.jsdelivr.net/npm/moment@2.18.1/min/moment.min.js',
'https://cdn.jsdelivr.net/npm/vue-clipboard2@0.3.1/dist/vue-clipboard.min.js'
]
}
// 单线程js代码压缩
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
// gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// 多线程js压缩
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
// 多线程官方js压缩
const TerserPlugin = require('terser-webpack-plugin')
// 实时查看构建分析
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
// optimizeCssPlugin CSS文件压缩插件
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin')
function resolve(dir) {
return path.join(__dirname, dir)
}
const isProduction = process.env.NODE_ENV === 'production'
// const name = defaultSettings.title || 'vue Admin Template' // page title
const port = process.env.port || process.env.npm_config_port || 9528 // dev port
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/production-sub-path/'
: '/',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
productionSourceMap: false,
devServer: {
open: true,
host: '0.0.0.0', // localhost
port: port,
proxy: {
// 写你的接口
[process.env.VUE_APP_BASE_API]: {
// target: `http://localhost:8081/ipamPortal`, //本机IP
target: `http://0.0.0.0:8080/zoneportal/`, // 内网IP
// target: `http://0.0.0.0:8080/zoneportal/`, // 外网
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
overlay: { // 设置让浏览器 overlay 同时显示警告和错误
warnings: false,
errors: true
},
before: require('./mock/mock-server.js')
},
css: {
loaderOptions: {
postcss: {
plugins: [
postcss // 配置postcss
]
},
scss: {
// 全局使用的scss
prependData: `@import "~@/styles/mixin.scss";`
}
}
},
configureWebpack: config => {
// 生产环境
if (isProduction) {
// 为生产环境修改配置...
config.mode = 'production'
// 用cdn方式引入,则构建时要忽略相关资源
config.externals = cdn.externals
config.output.filename = `js/[name].[chunkhash:8].js`
config.output.chunkFilename = `js/[name].[chunkhash:8].js`
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
output: {
// 是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,可以设置为false
beautify: false,
// 是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为false
comments: false
},
// 生产环境自动删除console
compress: {
// warnings: false, // 若打包错误,则注释这行
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
}))
// gzip压缩
// const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|css|json|txt|ico|svg)(\?.*)?$/i,
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
// JS多线程压缩---缓存形式
config.plugins.push(
new ParallelUglifyPlugin({
cacheDir: '.cache/',
test: /.js$/,
uglifyJS: {
output: {
beautify: false,
comments: false
},
warnings: false,
compress: {
drop_console: true,
collapse_vars: true,
reduce_vars: true
}
},
sourceMap: false
})
)
// 压缩css
config.plugins.push(
new OptimizeCssPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: { removeAll: true }},
canPrint: true
})
)
// 多线程压缩js
config.plugins.push(
new TerserPlugin({
test: /\.js(\?.*)?$/i, // 匹配参与压缩的文件
parallel: true, // 使用多进程并发运行
terserOptions: {
output: { comments: false },
ecma: undefined,
warnings: false,
parse: {},
extractComments: false, // 将注释剥离到单独的文件中
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: ['console.log'] // 移除console
}
}
})
)
}
// 取消webpack警告的性能提示
config.performance = {
hints: 'warning',
// 入口起点的最大体积
maxEntrypointSize: 10000 * 1000,
// 生成文件的最大体积
maxAssetSize: 30000 * 1000,
// 只给出 js 文件的性能提示
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js')
}
}
},
chainWebpack(config) {
// 添加别名
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('api', resolve('src/api'))
.set('views', resolve('src/views'))
.set('components', resolve('src/components'))
// 压缩图片
const imagesRule = config.module.rule('images')
imagesRule.uses.clear()
imagesRule.use('file-loader')
.loader('url-loader')
.options({
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
outputPath: 'static/images'
}
}
})
// set svg-sprite-loader
config.module
.rule('svg')
.exclude.add(resolve('src/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
config
.when(process.env.NODE_ENV !== 'development',
config => {
config.plugins.delete('preload')
config.plugins.delete('prefetch')
const analyzer = new BundleAnalyzerPlugin({
analyzerPort: 9999
})
config.plugin('webpack-bundle-analyzer').use(analyzer).end()
// csshansh
config.plugin('extract-css').tap(args => [{
filename: `css/[name].[contenthash:8].css`,
chunkFilename: `css/[name].[contenthash:8].css`
}])
// ============注入cdn start============
config.plugin('html').tap(args => {
// 生产环境或本地需要cdn时,才注入cdn
args[0].cdn = cdn
return args
})
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
inline: /runtime\..*\.js$/
}])
.end()
config
.optimization.splitChunks({
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 20000, // 依赖包超过20000bit将被单独打包
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`
}
}
}
})
config.optimization.minimize(true)
config.optimization.runtimeChunk('single')
}
)
}
}