• vuecli2.x webpack3.x升级webpack5.37.0


    随着项目的页面越来越多体积越来越大,dev构建速度和pro打包速度越来越慢,然后就抽时间对项目进行了webpack升级来提升一下速度
    升级过程中遇到了很多的坑,基本都是plugin和loader升级后的一些用法问题,花了一个晚上和一个上午时间,过程很痛苦,但是看到
    速度的大幅度提示,还是很开心的
    先上图看一下对比效果
    webpack3 dev构建

    webpack3 pro打包

    webpack5 dev构建 提升60%

    webpack5 pro 构建 提升61%

    看的处理效果还是很不错的

    1.首先是对webpack进行升级,升级后的版本如图

    升级后一些用法发生了改变
    webpack-merge的变化

    dev启动命令变化

    2.由于wepback的升级造成了其他一些插件或者loader的不能正常使用,索性使用yarn upgrade-interactive --latest升级了所有的依赖包
    3.升级后报错babel-core6.x的版本需要使用babel-loader7的版本然后重新安装yarn add -D babel-loader@7
    4.安装mini-css-extract-plugin替换extract-text-webpack-plugin
    webpack.base.config.js

    'use strict'
    const path = require('path')
    const utils = require('./utils')
    const config = require('../config')
    const { VueLoaderPlugin } = require('vue-loader')
    
    function resolve(dir) {
        return path.join(__dirname, '..', dir)
    }
    
    
    
    module.exports = {
        devtool:'eval-source-map',
        context: path.resolve(__dirname, '../'),
        entry: {
            app: './src/main.js'
        },
        output: {
            path: config.build.assetsRoot,
            filename: '[name].js',
            publicPath: process.env.NODE_ENV === 'production' ?
                config.build.assetsPublicPath : config.dev.assetsPublicPath
        },
        resolve: {
            extensions: ['.js', '.vue', '.json'],
            alias: {
                'vue$': 'vue/dist/vue.esm.js',
                '@': resolve('src'),
            }
        },
        module: {
            rules: [{
                test: /.vue$/,
                use: {
                    loader: 'vue-loader'
                }
            },
            {
                test: /.js$/,
                use: {
                    loader: 'babel-loader'
                },
                exclude: resolve('node_modules'),
                include: resolve('src')
            },
            {
                test: /.(png|jpe?g|gif|svg)(?.*)?$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 10 * 1024 // 10kb
                    }
                },
                generator: {
                    filename: utils.assetsPath('img/[name].[hash:7].[ext]')
                }
            },
            {
                test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: utils.assetsPath('media/[name].[hash:7].[ext]')
                }
            },
            {
                test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name: utils.assetsPath('fonts/[name].[hash:7].[ext]'),
                    publicPath: '../../'
                }
            }]
        },
        node: {
            global: false
        },
        plugins: [
            new VueLoaderPlugin()
        ]
    }
    

    utils.js

    'use strict'
    const path = require('path')
    const config = require('../config')
    const MiniCssExtractPlugin = require("mini-css-extract-plugin")
    const packageConfig = require('../package.json')
    
    exports.assetsPath = function (_path) {
      const assetsSubDirectory = process.env.NODE_ENV === 'production'
        ? config.build.assetsSubDirectory
        : config.dev.assetsSubDirectory
    
      return path.posix.join(assetsSubDirectory, _path)
    }
    
    exports.cssLoaders = function (options) {
      options = options || {}
    
      const cssLoader = {
        loader: 'css-loader',
        options: {
          sourceMap: options.sourceMap
        }
      }
    
      const postcssLoader = {
        loader: 'postcss-loader',
        options: {
          sourceMap: options.sourceMap
        }
      }
    
      // generate loader string to be used with extract text plugin
      function generateLoaders(loader, loaderOptions) {
        const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
    
        if (loader) {
          loaders.push({
            loader: loader + '-loader',
            options: Object.assign({}, loaderOptions, {
              sourceMap: options.sourceMap
            })
          })
        }
    
        // Extract CSS when that option is specified
        // (which is the case during production build)
        if (options.extract) {
          return [
            {
              loader: MiniCssExtractPlugin.loader,
              options: {
                publicPath: '../../' //修改路径处理图片路径错误
              }
            }
          ].concat(loaders)
        } else {
          return [
            {
              loader: 'vue-style-loader'
            }
          ].concat(loaders)
        }
      }
    
      // https://vue-loader.vuejs.org/en/configurations/extract-css.html
      return {
        css: generateLoaders(),
        postcss: generateLoaders(),
        less: generateLoaders('less'),
        // sass: generateLoaders('sass', { indentedSyntax: true }),
        // scss: generateLoaders('sass'),
        // stylus: generateLoaders('stylus'),
        // styl: generateLoaders('stylus')
      }
    }
    
    // Generate loaders for standalone style files (outside of .vue)
    exports.styleLoaders = function (options) {
      const output = []
      const loaders = exports.cssLoaders(options)
    
      for (const extension in loaders) {
        const loader = loaders[extension]
        output.push({
          test: new RegExp('\.' + extension + '$'),
          use: loader
        })
      }
    
      return output
    }
    
    exports.createNotifierCallback = () => {
      const notifier = require('node-notifier')
    
      return (severity, errors) => {
        if (severity !== 'error') return
    
        const error = errors[0]
        const filename = error.file && error.file.split('!').pop()
    
        notifier.notify({
          title: packageConfig.name,
          message: severity + ': ' + error.name,
          subtitle: filename || '',
          icon: path.join(__dirname, 'logo.png')
        })
      }
    }
    

    webpack.dev.conf.js

    'use strict'
    const utils = require('./utils')
    const webpack = require('webpack')
    const config = require('../config')
    const { merge } = require('webpack-merge')
    const path = require('path')
    const baseWebpackConfig = require('./webpack.base.conf')
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
    const portfinder = require('portfinder')
    
    const HOST = process.env.HOST
    const PORT = process.env.PORT && Number(process.env.PORT)
    
    const devWebpackConfig = merge(baseWebpackConfig, {
    	mode: 'development',
    	module: {
    		rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
    	},
    	// cheap-module-eval-source-map is faster for development
    	devtool: config.dev.devtool,
    
    	// these devServer options should be customized in /config/index.js
    	devServer: {
    		clientLogLevel: 'warning',
    		historyApiFallback: {
    			rewrites: [
    				{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
    			],
    		},
    		hot: true,
    		contentBase: false, // since we use CopyWebpackPlugin.
    		compress: true,
    		host: HOST || config.dev.host,
    		port: PORT || config.dev.port,
    		open: config.dev.autoOpenBrowser,
    		overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false,
    		publicPath: config.dev.assetsPublicPath,
    		proxy: config.dev.proxyTable,
    		quiet: true, // necessary for FriendlyErrorsPlugin
    		watchOptions: {
    			poll: config.dev.poll,
    		}
    	},
    	plugins: [
    		new webpack.DefinePlugin({
    			'process.env': require('../config/dev.env'),
    			BASEURL: '"//test.com"', 
    		}),
    		new webpack.HotModuleReplacementPlugin(),
    		// new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    		// new webpack.NoEmitOnErrorsPlugin(),
    		// https://github.com/ampedandwired/html-webpack-plugin
    		new HtmlWebpackPlugin({
    			filename: 'index.html',
    			template: 'index.html',
    			inject: true,
    			chunkSortMode: 'auto'
    		}),
    		// copy custom static assets
    		new CopyWebpackPlugin({
    			patterns: [
    				{
    					from: path.resolve(__dirname, '../static'),
    					to: config.dev.assetsSubDirectory,
    					globOptions: {
    						dot: true,
    						gitignore: true,
    						ignore: ['.*'],
    					}
    				},
    			]
    		})
    	]
    })
    
    module.exports = new Promise((resolve, reject) => {
    	portfinder.basePort = process.env.PORT || config.dev.port
    	portfinder.getPort((err, port) => {
    		if (err) {
    			reject(err)
    		} else {
    			// publish the new Port, necessary for e2e tests
    			process.env.PORT = port
    			// add port to devServer config
    			devWebpackConfig.devServer.port = port
    
    			// Add FriendlyErrorsPlugin
    			devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
    				compilationSuccessInfo: {
    					messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
    				},
    				onErrors: config.dev.notifyOnErrors ?
    					utils.createNotifierCallback() : undefined
    			}))
    
    			resolve(devWebpackConfig)
    		}
    	})
    })
    

    webpack.prod.conf.js

    '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 MiniCssExtractPlugin = require("mini-css-extract-plugin")
    const TerserWebpackPlugin = require('terser-webpack-plugin')
    const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
    
    const env = require('../config/prod.env')
    let envOptions = {}
    if (process.env.BUILD_ENV === "production") {
      envOptions = {
        'BASEURL': '"//test.com"',
      }
    } else {
      envOptions = {
        'BASEURL': '"//test.com"',  
      }
    }
    
    const webpackConfig = merge(baseWebpackConfig, {
      mode: 'production',
      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].[hash:7].js'),
        chunkFilename: utils.assetsPath('js/[name].[hash:7].js'),
        clean: true
      },
    
      optimization: {
        minimize: true,
        minimizer: [
          new TerserWebpackPlugin(),
          new OptimizeCSSPlugin(),
        ],
        runtimeChunk: { name: 'runtime' },
        concatenateModules: true,
        splitChunks: {
          cacheGroups: {
            vendor: {
              test: /[\/]node_modules[\/]/,
              name: 'vendor',
              chunks: 'all',
              priority: -10
            },
            'async-vendors': {
              test: /[\/]node_modules[\/]/,
              minChunks: 2,
              chunks: 'async',
              name: 'async-vendors'
            }
          },
        },
        moduleIds: 'deterministic'
      },
      plugins: [
        // http://vuejs.github.io/vue-loader/en/workflow/production.html
        new webpack.DefinePlugin({
          'process.env': env,
          ...envOptions,
        }),
        new MiniCssExtractPlugin({
          filename: utils.assetsPath('css/[name].[contenthash].css'),
          chunkFilename: utils.assetsPath('css/[name].[contenthash].css')
        }),
        new HtmlWebpackPlugin({
          filename: config.build.index,
          template: 'index.html',
          inject: true,
          scriptLoading: 'blocking',
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true
          },
          chunksSortMode: 'auto'
        }),
        new CopyWebpackPlugin({
          patterns: [
            {
              from: path.resolve(__dirname, '../static'),
              to: config.build.assetsSubDirectory,
              globOptions: {
                dot: true,
                gitignore: true,
                ignore: ['.*'],
              }
            },
          ]
        })
      ]
    })
    
    if (config.build.productionGzip) {
      const CompressionWebpackPlugin = require('compression-webpack-plugin');
      webpackConfig.plugins.push(
        new CompressionWebpackPlugin({
          filename: '[path][base].gz[query]',
          algorithm: 'gzip',
          test: /.(js|css|json|txt|html|ico|svg)(?.*)?$/i,
          threshold: 10240,
          minRatio: 0.8,
          deleteOriginalAssets: false//保留源文件
        })
      )
    }
    
    if (config.build.bundleAnalyzerReport) {
      const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
      webpackConfig.plugins.push(new BundleAnalyzerPlugin())
    }
    
    module.exports = webpackConfig
    
    
  • 相关阅读:
    数据库——数据操作——数据的增删改(8)
    数据库——完整性约束(7)
    数据库——数据类型(6)
    生成代码的代码 之 POJO生成器 之二 模板实现
    生成代码的代码 之 错误代码类生成器
    生成代码的代码 之 POJO生成器
    [翻译] Trident-ML:基于storm的实时在线机器学习库
    Vim实用技巧系列
    基于循环数组的无锁队列
    Vim实用技巧系列
  • 原文地址:https://www.cnblogs.com/samsara-yx/p/14844605.html
Copyright © 2020-2023  润新知