1.原始篇
let path = require('path');
const webpack = require('webpack');
const ThemeColorReplacer = require('webpack-theme-color-replacer');
const { getThemeColors, modifyVars } = require('./src/utils/themeUtil');
const { resolveCss } = require('./src/utils/theme-color-replacer-extend');
const CompressionWebpackPlugin = require('compression-webpack-plugin');// const productionGzipExtensions = ['js', 'css'];
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i;
const isProd = process.env.NODE_ENV === 'production';const assetsCDN = {// webpack build externalsexternals: {// vue: 'Vue',// 'vue-router': 'VueRouter',// vuex: 'Vuex',// axios: 'axios',// nprogress: 'NProgress',// clipboard: 'ClipboardJS',// '@antv/data-set': 'DataSet',// 'js-cookie': 'Cookies',// AMap: "window.AMap"},css: [// '//at.alicdn.com/t/font_2338481_gghb7xktb5.css'],js: [// '//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',// '//cdn.jsdelivr.net/npm/vue-router@3.3.4/dist/vue-router.min.js',// '//cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js',// '//cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',// '//cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js',// '//cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js',// '//cdn.jsdelivr.net/npm/@antv/data-set@0.11.4/build/data-set.min.js',// '//cdn.jsdelivr.net/npm/js-cookie@2.2.1/src/js.cookie.min.js']
};module.exports = {lintOnSave: false,devServer: {// host: "localhost",open: true,port: 8088,//配置几个跨域接口proxy: {'/v2/city/lookup': {target: 'https://geoapi.qweather.com', //请求城市定位区域接口地址changeOrigin: true, //是否跨域// pathRewrite: {// '^/api': '' //路径重写// }},'/v7/weather/now': {target: 'https://devapi.qweather.com', //请求指定区域的接口changeOrigin: true, //是否跨域// pathRewrite: {// '^/api': '' //路径重写// }}}},pluginOptions: {'style-resources-loader': {preProcessor: 'less',patterns: [path.resolve(__dirname, "./src/theme/theme.less")],}},configureWebpack: config => {config.entry.app = ["babel-polyfill", "whatwg-fetch", "./src/main.js"];config.performance = {hints: false};config.plugins.push(new ThemeColorReplacer({fileName: 'css/theme-colors-[contenthash:8].css',matchColors: getThemeColors(),injectCss: true,resolveCss}));// Ignore all locale files of moment.jsconfig.plugins.push(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))// 生产环境下将资源压缩成gzip格式if (isProd) {// add `CompressionWebpack` plugin to webpack pluginsconfig.plugins.push(new CompressionWebpackPlugin({algorithm: 'gzip',// test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),test: productionGzipExtensions,threshold: 4096,minRatio: 0.8}))}// if prod, add externalsif (isProd) {config.externals = assetsCDN.externals}},chainWebpack: config => {// 生产环境下关闭css压缩的 colormin 项,因为此项优化与主题色替换功能冲突 if (isProd) {config.plugin('optimize-css').tap(args => {args[0].cssnanoOptions.preset[1].colormin = false;return args})}// 生产环境下使用CDNif (isProd) {config.plugin('html').tap(args => {args[0].cdn = assetsCDN;return args})}},css: {loaderOptions: {less: {lessOptions: {modifyVars: modifyVars(),javascriptEnabled: true}}}},publicPath: './',outputDir: 'distM',assetsDir: '',productionSourceMap: false
};
2.改进篇
let path = require('path');
const webpack = require('webpack');
const ThemeColorReplacer = require('webpack-theme-color-replacer');
const { getThemeColors, modifyVars } = require('./src/utils/themeUtil');
const { resolveCss } = require('./src/utils/theme-color-replacer-extend');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
// const productionGzipExtensions = ["js", "css"];
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i;
const isProd = process.env.NODE_ENV === 'production';const assetsCDN = {// webpack build externalsexternals: {//不需要打包进来的资源// vue: 'Vue',// vuex: 'Vuex',// 'vue-router': 'VueRouter',// axios: 'axios',// nprogress: 'NProgress',// clipboard: 'ClipboardJS',// '@antv/data-set': 'DataSet',// 'js-cookie': 'Cookies',// AMap: "window.AMap"},css: [// '//at.alicdn.com/t/font_2338481_gghb7xktb5.css'],js: [// '//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',// '//cdn.jsdelivr.net/npm/vue-router@3.3.4/dist/vue-router.min.js',// '//cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js',// '//cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',// '//cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js',// '//cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js',// '//cdn.jsdelivr.net/npm/@antv/data-set@0.11.4/build/data-set.min.js',// '//cdn.jsdelivr.net/npm/js-cookie@2.2.1/src/js.cookie.min.js']
};
let timeStamp = new Date().getTime();
module.exports = {publicPath: './',outputDir: 'distM',assetsDir: '',productionSourceMap: false, // 是否为生产环境构建生成 source map?lintOnSave: false, //是否开启eslint保存检测,有效值: true || false || 'error'devServer: {// host: "localhost",open: true,port: 8087,overlay: {errors: false,warnings: false},//配置几个跨域接口proxy: {'/v2/city/lookup': {target: 'https://geoapi.qweather.com', //请求城市定位区域接口地址changeOrigin: true, //是否跨域// pathRewrite: {// '^/api': '' //路径重写// }},'/v7/weather/now': {target: 'https://devapi.qweather.com', //请求指定区域的接口changeOrigin: true, //是否跨域// pathRewrite: {// '^/api': '' //路径重写// }}}},pluginOptions: {'style-resources-loader': {preProcessor: 'less',patterns: [path.resolve(__dirname, "./src/theme/theme.less")]}},configureWebpack: config => {config.entry.app = ["babel-polyfill", "whatwg-fetch", "./src/main.js"];config.performance = {hints: false};config.plugins.push(new ThemeColorReplacer({fileName: 'css/theme-colors-[contenthash:8].css',matchColors: getThemeColors(),injectCss: true,resolveCss}));// 生产环境下将资源压缩成gzip格式if (isProd) {// add `CompressionWebpack` plugin to webpack pluginsconfig.plugins.push(// Ignore all locale files of moment.js 2024-01-18new webpack.IgnorePlugin(/^\.\/locale$/,/moment$/),new CompressionWebpackPlugin({algorithm: 'gzip',// test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"),test: productionGzipExtensions,threshold: 4096, //对4K以上的数据进行压缩minRatio: 0.8,}),/*** 新增限制 2024-01-18* maxChunks:使用大于或等于 1 的值,来限制 chunk 的最大数量。使用 1 防止添加任何其他额外的 chunk,这是因为 entry/main chunk 也会包含在计数之中。* minChunkSize: 设置 chunk 的最小大小。* 限制打包的个数(减少打包生成的js文件和css文件)*/new webpack.optimize.LimitChunkCountPlugin({maxChunks: 10,minChunkSize: 100}),)}// if prod, add externalsif (isProd) {config.externals = assetsCDN.externals}},chainWebpack: config => {if (isProd) {// 移除 prefetch 插件config.plugins.delete('prefetch');// 移除 preload 插件config.plugins.delete('preload');// 压缩代码config.optimization.minimize(true);// 分割代码config.optimization.splitChunks({chunks: 'all'});// 生产环境下关闭css压缩的 colormin 项,因为此项优化与主题色替换功能冲突 config.plugin('optimize-css').tap(args => {args[0].cssnanoOptions.preset[1].colormin = false;return args})// 生产环境下使用CDNconfig.plugin('html').tap(args => {args[0].cdn = assetsCDN;return args})}},css: {extract: { // 打包后css文件名称添加时间戳 2024-01-18filename: `css/[name].[hash:8].${timeStamp}.css`,chunkFilename: `css/chunk.[id].[hash:8].${timeStamp}.css`,},loaderOptions: {less: {lessOptions: {modifyVars: modifyVars(),javascriptEnabled: true}}}},// chunks: ['chunk-vendors', 'chunk-common']
};
通过对chunk生成的css和js文件数量和大小做限制,对代码进行压缩和分割,线上生产环境下使用cdn方式等对webpack打包优化。