今天我把vue2中webpack版本升级了

2,201 阅读4分钟

看我如何逆向思维实现一个老旧的vue项目打包升级

起因

  • 公司的一个vue老旧项目,最初搭建的方式不得而知,极有可能也是使用vue-cli搭建的,但是webpack打包配置均要自己配置管理,但是代码组织结构比较通用:
frontend
├── README.md
├── package-lock.json
├── package.json
├── src
|   ├── main.js
|   ├── App.vue
│   ├── assets
|   ├── components
|   ├── pages
|   ├── router
│   ├── store
│   └── utils
└── Other files
  • 公司有个新的需求是对打包后的代码进行更小粒度的切割,但之前webpack版本是3.x并不支持splitChunks,只能使用CommonsChunkPlugin插件进行打包优化,无法达到理想效果。
  • 基因以上因素,决定将现有的webpack构建架构进行升级

解决过程

  • 开始的想法儿是利用yarn或者npmwebpack版本进行升级,个人推荐使用yarn
// yarn升级依赖
// 需要手动选择升级的依赖包,按空格键选择,a 键切换所有,i 键反选选择
yarn upgrade-interactive --latest
// or
// 指定版本升级
yarn upgrade package@version

// npm升级依赖
npm update package

但这会遇到一个问题,就是webpack3以后的版本的配置和webpack3有些是不兼容的,包括api也有变动(比如废弃CommonsChunkPlugin,推荐使用更强大的splitChunks)。还有就是babel升级后的一些配置也会不兼容,升级后各种报错,打包跑不起来,遂放弃

  • 后来发现整个代码组织与现在的vue-cli创建的项目一样,思考是不是可以把vue-cli提供的service直接移植到本项目中,移除之前关于打包的代码。

    1. 首先比较一个最新的vue-cli创建的vue2项目中使用的打包相关的依赖,发现支撑打包和开发配置的是如下依赖:
    "devDependencies": {
        "@vue/cli-plugin-babel": "~4.5.0",
        "@vue/cli-plugin-eslint": "~4.5.0",
        "@vue/cli-service": "~4.5.0",
        "babel-eslint": "^10.1.0",
        "eslint": "^6.7.2",
        "eslint-plugin-vue": "^6.2.2",
        "vue-template-compiler": "^2.6.11"
    }
    

    重点是@vue/cli-service,围绕该服务有babeleslinttemplate-compiler等插件。

    1. 通过以上比较后在已有的项目中安装对应的依赖,并删除之前的webpack相关的依赖。
     "devDependencies": {
        "autoprefixer": "^7.1.2",
        "babel-core": "^6.26.3",
        "babel-helper-vue-jsx-merge-props": "^2.0.3",
        "babel-jest": "^21.0.2",
        "babel-loader": "^7.1.5",
        "babel-plugin-dynamic-import-node": "^1.2.0",
        "babel-plugin-syntax-jsx": "^6.18.0",
        "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
        "babel-plugin-transform-object-rest-spread": "^6.26.0",
        "babel-plugin-transform-runtime": "^6.22.0",
        "babel-plugin-transform-vue-jsx": "^3.5.0",
        "babel-preset-env": "^1.7.0",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-stage-2": "^6.22.0",
        "babel-register": "^6.22.0",
        "chalk": "^2.0.1",
        "chromedriver": "^2.27.2",
        "babel-eslint": "^10.1.0",
        "copy-webpack-plugin": "^4.0.1",
        "cross-spawn": "^5.0.1",
        "css-loader": "^0.28.0",
        "extract-text-webpack-plugin": "^3.0.0",
        "file-loader": "^1.1.11",
        "friendly-errors-webpack-plugin": "^1.6.1",
        "generate-asset-webpack-plugin": "^0.3.0",
        "html-webpack-plugin": "^2.30.1",
        "jest": "^22.0.4",
        "jest-serializer-vue": "^0.3.0",
        "nightwatch": "^0.9.12",
        "node-notifier": "^5.1.2",
        "optimize-css-assets-webpack-plugin": "^3.2.0",
        "ora": "^1.2.0",
        "portfinder": "^1.0.13",
        "postcss-import": "^11.0.0",
        "postcss-loader": "^2.0.8",
        "postcss-url": "^7.2.1",
        "rimraf": "^2.6.0",
        "selenium-server": "^3.0.1",
        "semver": "^5.3.0",
        "shelljs": "^0.7.6",
        "uglifyjs-webpack-plugin": "^1.1.1",
        "url-loader": "^0.5.8",
        "vue-jest": "^1.0.2",
        "vue-loader": "^13.3.0",
        "vue-style-loader": "^3.0.1",
        "vue-template-compiler": "^2.5.2",
        "webpack": "^3.12.0",
        "webpack-bundle-analyzer": "^2.9.0",
        "webpack-dev-server": "^2.9.1",
        "webpack-merge": "^4.1.0"
      }
    

    确实很惊人,项目之前需要自己安装和管理这么多依赖,这给后期维护升级带来不小的困难。

    1. 使用vue.config.js,使用vue-cli提供的开箱即用的服务,不用inject就可以对webpack进行配置,在根目录增加vue.config.js
    module.exports = {
      publicPath: './',
      devServer: {
        port: '9999'
      },
      // webpack配置
      configureWebpack: config =>{
        return {
          optimization: {
            splitChunks: {
              chunks: 'all',
              minSize: 30000,
              cacheGroups: {
                'element-ui': {
                  chunks: 'all',
                  name: `element-ui`,
                  test: /[\\/]node_modules[\\/]element-ui[\\/]/,
                  priority: 0,
                },
                'echarts': {
                  chunks: 'all',
                  name: `echarts`,
                  test: /[\\/]node_modules[\\/]echarts|zrender[\\/]/,
                  priority: 0,
                },
                'vendors': {
                  minChunks: 2,
                  name: `chunk-vendors`,
                  test: /[\\/]node_modules[\\/]/,
                  priority: -10,
                  chunks: 'initial'
                },
              }
            }
          },
          // webpack插件
          plugins: [
            // 打包分析插件
            // new BundleAnalyzerPlugin(),
            // 缓存插件,用于提升打包构建速度
            // new HardSourceWebpackPlugin(),
          ]
        }
      },
      chainWebpack: config => {
        // 这里删除js的prefetch,否则会把所有js都提前加载进来,有违按需加载的初衷了
        config.plugins.delete('prefetch')
      },
      runtimeCompiler: true
    }
    
    1. 删除之前项目中关于构建相关的buildconfig目录下webpack相关的配置代码。
    2. 修改package.jsonscripts
    "scripts": {
        "start": "vue-cli-service serve",
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint"
      },
    

通过以上几步的分析解决项目基本可以跑起来了,不仅升级了新的构建架构,代码组织结构也更清爽了。这里只是提供了一个可以偷懒的升级方法,由于手动升级会遇到各种版本问题造成的坑,所以使用开箱即用的工具集效果会更好。

番外

现在我们可以把改造后的项目跑起来,并实现了对webpack以及周边生态的依赖升级,同时也实现了对代码打包后的切割,这里面还有几个注意的点:

  • 由于之前eslint的规则和现行的eslint不一致会有大量的警告和错误,这里需要耐心处理一下,这里有个偷懒的方式先让项目跑起来,就是在.eslintrc.js中对报错的类型进行过滤,待后面慢慢解决。
    module.exports = {
      rules: {
         'no-unused-vars': 'warn',
         'no-empty-pattern': 'warn',
         'no-undef': 'warn',
         // some other config
      }
    }
    
  • 安装webpack-bundle-analyzer插件对打包后代码的分布情况进行分析可以很直观的发现哪个环节有问题,以便于针对性的进行优化。
  • 安装hard-source-webpack-plugin插件对已构建的过程进行缓存,这样在构建时如果命中缓存可以直接使用缓存,以提升构建速度。

搬砖