1. 安装postCss
npm install postcss-plugin-px2rem@0.8.1
// 配置postcssconst 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: {// 全局使用的scssprependData: `@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: {// 是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,可以设置为falsebeautify: false,// 是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为falsecomments: false},// 生产环境自动删除consolecompress: {// 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').BundleAnalyzerPluginconst 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')// 压缩cssconfig.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, // 只有大小大于该值的资源会被处理 10240minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理deleteOriginalAssets: false // 删除原文件}))
配置的全部代码
'use strict'const path = require('path')// 配置postcssconst 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 titleconst port = process.env.port || process.env.npm_config_port || 9528 // dev portmodule.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', // localhostport: port,proxy: {// 写你的接口[process.env.VUE_APP_BASE_API]: {// target: `http://localhost:8081/ipamPortal`, //本机IPtarget: `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: {// 全局使用的scssprependData: `@import "~@/styles/mixin.scss";`}}},configureWebpack: config => {// 生产环境if (isProduction) {// 为生产环境修改配置...config.mode = 'production'// 用cdn方式引入,则构建时要忽略相关资源config.externals = cdn.externalsconfig.output.filename = `js/[name].[chunkhash:8].js`config.output.chunkFilename = `js/[name].[chunkhash:8].js`config.plugins.push(new UglifyJsPlugin({uglifyOptions: {output: {// 是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,可以设置为falsebeautify: false,// 是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为falsecomments: false},// 生产环境自动删除consolecompress: {// 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, // 只有大小大于该值的资源会被处理 10240minRatio: 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}))// 压缩cssconfig.plugins.push(new OptimizeCssPlugin({assetNameRegExp: /\.css$/g,cssProcessor: require('cssnano'),cssProcessorOptions: { discardComments: { removeAll: true }},canPrint: true}))// 多线程压缩jsconfig.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-loaderconfig.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()// csshanshconfig.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时,才注入cdnargs[0].cdn = cdnreturn 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/packageNameconst packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]// npm package names are URL-safe, but some servers don't like @ symbolsreturn `npm.${packageName.replace('@', '')}`}}}})config.optimization.minimize(true)config.optimization.runtimeChunk('single')})}}
