Vue 2.5.16 + Webpack 4 升级 Vue 2.7.16 + Webpack 5 记录

升级概览

本次升级是将一个基于 Vue 2.5.16 + Webpack 4 的项目升级到 Vue 2.7.16 + Webpack 5,主要涉及:

  • 核心依赖升级
  • Webpack 配置变更
  • 升级后问题修复

升级收益

  • ✅ 升级到 Vue 2.7.16(Vue2 最后一个版本,支持 Composition API,为后续可能的升级 Vue3 打下基础迁移至 Vue 2.7 - Vue.js 文档
  • ✅ 升级到 Webpack 5(更好的性能和缓存,启动文件缓存,热启动开发服务器只需从原先的 14s 提升到 1.3s, 本地打包构建少量的增量更新命中缓存编译只需要 2s,构建完成只需要不到 8s)

核心依赖升级

1.1 主要版本升级

json 复制代码
// Vue 相关
"vue": "^2.5.16" → "^2.7.16"
"vue-server-renderer": "^2.5.16" → "^2.7.16"
"vue-loader": "^14.2.2" → "^15.11.1"
"vue-template-compiler": "^2.5.16" → "^2.7.16"

// Webpack 核心
"webpack": "^4.44.1" → "^5.88.0"
"webpack-cli": "^3.2.0" → "^4.10.0"
"webpack-dev-server": "^3.11.0" → "^4.15.0"
"webpack-merge": "^4.2.1" → "^5.9.0"

1.2 新增依赖(webpack5 polyfills)

webpack5 不再自动提供 Node.js polyfills,需要手动安装。

json 复制代码
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.1",
"path-browserify": "^1.0.1",
"stream-browserify": "^3.0.0",
"util": "^0.12.5",
"postcss": "^8.5.6",
"postcss-loader": "^6.2.1",

1.3 移除的依赖(webpack5 内置替代)

json 复制代码
// 移除:不再需要的loader
"file-loader": "^3.0.1",  // 用Asset Modules替代
"url-loader": "^1.1.2",   // 用Asset Modules替代

Webpack Base Config 核心变更

2.1 移除 HappyPack,使用 webpack5 内置多线程

diff 复制代码
// 移除 webpack4 的 HappyPack 配置
- const HappyPack = require('happypack');
- const os = require('os');
- const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

2.2 添加 webpack5 缓存配置

javascript 复制代码
cache: {
  type: 'filesystem',
  buildDependencies: {
    config: [__filename]
  },
  cacheDirectory: path.resolve(__dirname, '../node_modules/.cache/webpack'),
  version: '1.0.0'
}

开启持久化缓存 (filesystem cache), 会在 node_modules/.cache/webpack 目录下生成缓存文件, 每次构建会优先使用缓存, 提升构建速度。

bash 复制代码
client/node_modules/.cache/webpack/
├── default-development/    # 开发环境缓存 (297M)
└── default-production/     # 生产环境缓存 (298M)

缓存重置触发条件:

  • 配置文件变更(webpack.config.js)
  • 依赖包更新(package.json)
  • 缓存版本升级(cache.version)
  • Node.js 版本变更

2.3 Asset Modules 替代传统 loader

javascript 复制代码
// 旧配置(url-loader)
{
  test: /\.(png|jpg|gif|svg|ico)$/,
  use: [{
    loader: "url-loader",
    options: {
      limit: 1000,
      name: "images/[name].[ext]"
    }
  }]
}

// 新配置(Asset Modules)
{
  test: /\.(png|jpg|gif|svg|ico)$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 1000
    }
  },
  generator: {
    filename: 'images/[name].[ext]'
  }
}

2.4 添加 Node.js polyfills

javascript 复制代码
// webpack5 不再自动提供 Node.js polyfills,需要手动安装。
resolve: {
  fallback: {
    "timers": false,
    "fs": false,
    "path": require.resolve("path-browserify"),
    "crypto": require.resolve("crypto-browserify"),
    "stream": require.resolve("stream-browserify"),
    "buffer": require.resolve("buffer"),
    "util": require.resolve("util")
  }
}

2.5 webpack5 优化配置

javascript 复制代码
// 实验性功能
experiments: {
  topLevelAwait: true
},

// 快照优化
snapshot: {
  module: { timestamp: true },
  resolve: { timestamp: true }
},

// 构建输出优化
stats: {
  children: false,
  chunks: false,
  modules: false,
  builtAt: false,
  timings: true,
  version: false
}

Webpack Client Config 变更

3.1 webpack-merge 导入方式变更

diff 复制代码
// 旧方式
- const merge = require('webpack-merge');

// 新方式
+ const { merge } = require('webpack-merge');

3.2 参数解析方式变更

在升级到 Webpack 5 + webpack-cli 4 后,原有的自定义参数传递方式失效:

bash 复制代码
# 报错:Unknown option '--swm=beta'
npm run build --swm=beta

# 原本期望的效果:通过--swm参数控制不同环境的构建

Webpack-cli 从 v3 升级到 v4 后,参数解析机制发生变化:

webpack-cli 版本 自定义参数支持 解析方式
v3.x ✅ 支持 --custom-arg=valueyargs.argv.customArg
v4.x ❌ 不支持 只支持预定义的 webpack 选项
diff 复制代码
// 旧方式
- const { swm = 'xxx', analysis = false, dll = false } = require('yargs').argv;

// 新方式
+ const swm = process.env.SWM || 'xxx';
+ const analysis = process.argv.includes('--analysis') || false;
+ const dll = process.argv.includes('--dll') || false;

更新 package.json 脚本, 新增环境特定的构建脚本:

diff 复制代码
{
  "scripts": {
    // 原有脚本保持不变
    "build": "cross-env NODE_ENV=production webpack --config ./client/build/webpack.client.config.js --progress",

    // 新增环境特定的构建脚本
+   "build:beta": "cross-env SWM=beta NODE_ENV=production webpack --config ./client/build/webpack.client.config.js --progress",
+   "build:test": "cross-env SWM=test NODE_ENV=production webpack --config ./client/build/webpack.client.config.js --progress",

    // 修复原有的环境脚本
-   "upipe": "npm run build --swm app-dev"
+   "upipe": "cross-env SWM=app-dev npm run build"
  }
}

3.3 DevServer 配置升级

javascript 复制代码
// 旧配置
devServer: {
  contentBase: path.resolve(__dirname, "../dist"),
  disableHostCheck: true
}

// 新配置
devServer: {
  static: {
    directory: path.resolve(__dirname, "../dist")
  },
  allowedHosts: "all",
  client: {
    overlay: {
      errors: false,
      warnings: false
    }
  }
}

3.4 SplitChunks 策略优化

javascript 复制代码
// 生产环境 vs 开发环境差异化配置
splitChunks: isProduction
  ? {
      // 生产环境:复杂分包策略
      chunks: 'all',
      minSize: 20000,
      maxSize: 244000,
      cacheGroups: {
        vue: {
          /* Vue相关库 */
        },
        ui: {
          /* UI库 */
        },
        utils: {
          /* 工具库 */
        },
        vendors: {
          /* 其他第三方库 */
        },
      },
    }
  : {
      // 开发环境:简单分包策略(避免热更新冲突)
      chunks: 'async',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'initial',
          priority: 10,
        },
      },
    };

3.5 移除手动 TerserPlugin 配置

diff 复制代码
// 移除手动配置,使用 webpack5 内置
- minimize: process.env.NODE_ENV !== "development",
- minimizer: [new TerserPlugin({ parallel: 4 })]

// 改为
+ minimize: isProduction; // webpack5 自动多线程压缩

PostCSS 配置迁移问题与解决

4.1 PostCSS 配置变更

javascript 复制代码
// 旧方式:在 vue-loader 中配置
{
  loader: "vue-loader",
  options: {
    postcss: [
      autoprefixer({
        browsers: ["> 1%", "ie >= 9", "iOS >= 6", "Android >= 2.1"]
      }),
      px2rem({ remUnit: 75 })
    ]
  }
}

// 新方式:独立的 postcss-loader
{
  test: /\.(css|less)$/,
  use: [
    "style-loader",
    "css-loader",
    "postcss-loader",  // 新增
    "less-loader"
  ]
}

4.2 创建独立的 postcss.config.js

javascript 复制代码
// postcss.config.js
const autoprefixer = require('autoprefixer');
const px2rem = require('postcss-px2rem');

module.exports = {
  plugins: [
    autoprefixer({
      overrideBrowserslist: ['> 1%', 'ie >= 9', 'iOS >= 6', 'Android >= 2.1'],
      flexbox: 'no-2009', // 保留老式flexbox语法
      remove: false, // 不移除过时的前缀
    }),
    px2rem({ remUnit: 75 }),
  ],
};

4.3 样式坑:Autoprefixer 移除浏览器前缀

升级后发现部分样式异常,对比线上版本发现 -webkit-box-orient: vertical 等浏览器前缀样式被移除。原因是新版本 autoprefixer 默认会清理"过时"的前缀,但某些样式仍需兼容旧版浏览器。解决方案:

javascript 复制代码
// 在 postcss.config.js 中添加以下配置

autoprefixer({
  // 保留老式flexbox语法,阻止移除-webkit-box相关属性
  flexbox: 'no-2009',
  // 不移除过时的前缀
  remove: false,
});
相关推荐
啃火龙果的兔子2 小时前
修改 Lucide-React 图标样式的方法
前端·react.js·前端框架
前端 贾公子2 小时前
为何在 Vue 的 v-model 指令中不能使用可选链(Optional Chaining)?
前端·javascript·vue.js
潘多拉的面2 小时前
Vue的ubus emit/on使用
前端·javascript·vue.js
遗憾随她而去.2 小时前
js面试题 高频(1-11题)
开发语言·前端·javascript
hqxstudying5 小时前
J2EE模式---前端控制器模式
java·前端·设计模式·java-ee·状态模式·代码规范·前端控制器模式
Microsoft Word5 小时前
用户中心项目实战(springboot+vue快速开发管理系统)
vue.js·spring boot·后端
开开心心就好6 小时前
Excel数据合并工具:零门槛快速整理
运维·服务器·前端·智能手机·pdf·bash·excel
im_AMBER6 小时前
Web开发 05
前端·javascript·react.js
Au_ust6 小时前
HTML整理
前端·javascript·html
安心不心安7 小时前
npm全局安装后,依然不是内部或外部命令,也不是可运行的程序或批处理文件
前端·npm·node.js