Vue屎山老项目迁移Rspack指南

Rspack是最近出来的基于 Rust 的高性能 Web 构建工具,它的API及配置方式、插件等基本对齐webpack(v5)生态,具有如下的主要特性(取自官方文档):

  • 启动速度极快
  • 闪电般的 HMR
  • 兼容 webpack
  • 内置常见构建能力
  • 默认生产优化
  • 框架无关

很多公司或团队应该还有很多庞大而臃肿的老项目都是基于vue 2,经常本地开发以及发布时的打包时间都要好几分钟甚至十几分钟,大大影响了开发及发布效率,所以今天我们主要介绍基于vue 2(vue-cli或者webpack配置)的老项目如何迁移至Rspack以此来提升打包部署的速度。

升级@vue/cli v4 -> v5(可选)

如果你的vue项目是基于@vue/cli v4的,可以先升级到v5(升级文档),升级的原因是v4是基于webpack4的,而rspack只支持webpack5,如果你本身直接依赖了webpack4的一些插件loader啥的,需要自己删掉重装webpack5相关的依赖,当然这是可选的,你可以直接无视,正常来说无脑升级就可以搞定:

@vue/cli的各种插件、ESLint配置

如果你之前用的是@vue/cli的各种插件来配置eslint的,很多都得去掉,直接用eslint对应vue的插件,主要就是@vue/xxx开头的这些库,如@vue/cli-plugin-babel,@vue/cli-plugin-eslint, @vue/eslint-config-prettier等,以及删除babel相关的库;

对于ESLint来说,保留eslint-plugin-xxx相关的即可,如eslint-plugin-vue,之前用vue-cli-service lint的后面直接用eslint --ext .ts,.js,.vue --fix这种命令;

对于TypeScript来说,eslint里parserOptions.parser直接使用@typescript-eslint/parserextends里使用plugin:@typescript-eslint/recommended,去掉@vue/typescript(如果有用的话);

对于Prettier来说,去掉@vue/prettier(如果有的话),直接使用plugin:prettier/recommended

对于Githooks来说,@vue/cli自带了pre-commit能力,通过package.json里gitHooks配置,当迁移完之后就没有了,需要自己安装husky库添加hook。

json 复制代码
// 这个得去掉
{
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
}

安装Rspack及基本配置

接下来先安装rspack库:

bash 复制代码
npm i @rspack/cli -D
# 安装html plugin,可选,也可以用自带的
npm i @rspack/plugin-html -D

安装完创建rspack.config.js,配置方式跟webpack雷同,entry,outputresolve.alias, devServer, devtool等这些常规项目基本可以无脑copy过来。

builtins 选项

builtins选项里是rspack自带的一些配置能力,无需额外插件(可能在后续的更新中为了对齐webpack又把一些配置以单独的插件来处理),常用的如下,更多的请查看builtins文档

js 复制代码
{
  // ...  
  builtins: {
    // 压缩的一些配置,比如去掉console
    minifyOptions: {
      dropConsole: true
    },
    // 设置一些环境变量在app里使用
    define: {
      'process.env.APP_VERSION': JSON.stringify('1.0.0')
    },
    // 类似copy-webpack-plugin的作用,直接复制相关文件
    copy: {
      patterns: [
        {
          from: './public'
        }
      ]
    }
  }
}

添加vue支持

Rspack从v0.2开始支持vue,vue3的话需要vue-loader >= 17.2.2,而要支持vue2的话需要vue-loader@15,我们先来看下配置,在rspack.config.js

js 复制代码
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
  //...
  modules: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          compilerOptions: {
            // 替换老的compilerOptions.preserveWhitespace=false
            whitespace: 'condense'
          }
        }
      },
      {
        // 处理使用ts的vue文件
        resourceQuery: /lang=ts/,
        type: 'typescript'
      },
      {
        // 处理vue文件里使用less的style标签
        resourceQuery: /lang=less/,
        use: [
          'vue-style-loader',
          {
            loader: 'css-loader',
            options: {
              // dev下使用sourceMap
              sourceMap: !isProd
            }
          },
          {
            loader: 'less-loader',
            options: {
              sourceMap: !isProd,
              lessOptions: {
                // 一些第三方ui库需要这个为true
                javascriptEnabled: true
              }
            }
          }
        ],
        type: 'javascript/auto'
      },
      {
        resourceQuery: /lang=css/,
        use: ['vue-style-loader', 'css-loader'],
        type: 'javascript/auto'
      },
      {
        // 单纯的less文件
        test: /\.less$/,
        loader: 'less-loader',
        options: {
          sourceMap: !isProd,
          lessOptions: {
            javascriptEnabled: true
          }
        },
        type: 'css'
      },
      {
        // 单纯的css文件
        test: /\.css$/,
        type: 'css'
      },
      {
        // 静态资源
        test: /\.(svg|png|jpe?g|gif|webp|woff2?|eot|ttf)$/i,
        type: 'asset'
      }
    ]
  }
}

上面一堆loader配下来,如果运气好的话就大功告成了,接下来我们再来看下还有哪些需要注意的(如果在自己项目中有用到的话):

样式文件里的:export

使用webpack时我们比如可以在less文件里export变量出去,这样在js里也可以统一引用样式变量:

less 复制代码
@primary-color: #0a8afa;
@primary-pink-color: #ff6699;
:export {
  primaryColor: @primary-color;
  pinkPrimaryColor: @primary-pink-color;
}

然后在js里:

js 复制代码
import { primaryColor } from 'path/to/theme.less'

迁移后还是用其他解决方案吧,这个似乎已经不生效了。

expertments.css的问题

官方文档在vue2支持那边说了:

请确保在配置 Vue2 项目时关闭 experiments.css 或在 CSS 相关的规则中使用 Rule.type = "javascript/auto"

v0.2.11之后的版本不能把experiments.css=false,会直接编译失败,直接把这个配置去掉,用type=javascript/auto

unplugin及unplugin-auto-import的问题

越来越多的vue项目开始使用unplugin-auto-import及其他unplugin插件,特别是在使用composition api的时候,避免来回重复的各种import,插件会在编译时自动加上对应的macro,unplugin本身已支持Rspack,只是还是处于实验阶段,官方不建议使用到线上,可能导致的问题如笔者提到的这个issue

但是其实我们很多项目已经使用了,而且感觉回不去了,不然得修改很多代码,不太现实,这种情况下我们有2条路选择:

  1. 等官方更新修复
  2. 修改插件代码,使用自己修改过的plugin

第一个不着急的话可以慢慢等,如果急需提升线上打包速度的话就可能需要自己修改了,我们先来看下笔者在迁移时发现上面issue里的问题的根源是什么:

从上面unplugin的rspack插件的代码里看出当做转化的时候include无脑包含了所有的文件例如静态资源,导致打包出来的静态资源跟源文件不一样了,而且这里的include也不接收外面参数,导致外面使用的插件也无法修改,那我们要在哪里改呢,直接改这个include么,还是说让他接收外面参数,还是说有hook在外面用的地方可以再次修改compiler里面的数据?

我们再看下unplugin的readme的framework-specific-logic这块,它本身提供了rspack(compiler)的回调hook,也就是在这个回调里你还可以直接把compiler里面的东西给改掉,这看起来就是我们需要的。

那我们就试下,在使用unplugin-auto-import的时候加上,发现还是不行🥺,加上console看连hook都没执行,难道是个假hook?笔者再去看了下auto-import的代码,发现它压根没加rspack的hook回调支持(可能由于上层rspack支持还处于实验阶段),也就是你传了等于没传,真的是太难了😭。

最后笔者的临时方案还是改node_modules里unplugin-auto-import的相关代码使其能够接受用户options里的rspack hook,

注意这里的unplugin, unplugin-auto-import及其他使用的unplugin插件都需要固定版本,它打包出来的文件都是带hash的,如果没固定,自己修改过的代码引用的文件可能会不存在!

以unplugin-auto-import为例,修改里面的代码:

然后在rspack.config.js里使用修改过的版本:

js 复制代码
function unpluginRspackHook(compiler) {
  if (!compiler.options.module?.rules?.length) return
  for (const rule of compiler.options.module.rules) {
    if (rule.use?.loader?.includes('rspack/loaders/')) {
      if (!rule.include || String(rule.include).includes('.*')) {
        // 把这里改成只处理vue,js,ts相关文件
        rule.include = [/\.vue$/, /\.vue\?vue/, /\.tsx?$/, /\.jsx?$/]
      }
    }
  }
}
module.exports = {
  plugins: [
    // ...
    {
      AutoImport({
        imports: ['vue', 'vue-router'],
        rspack: unpluginRspackHook
      })
    }
  ]
}

这样搞完顺利编译通过,而且静态资源也正常了✅

总结

本文主要介绍了vue老项目迁移到Rspack的过程、遇到的一些坑及对应的一些解决思路,有遇到过其他坑的大佬们可以交流下;总的来说迁移后生产打包速度基本可以提升80%左右,本地开发也有大幅提升(跟vite的秒开可能还差点,毕竟实现思路不一样🤔),让屎山老项目再次焕发生机🍏。

希望能对已在迁移或准备迁移的项目有所帮助,少走些弯路!

相关推荐
嚣张农民2 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
落魄小二2 小时前
el-table 表格索引不展示问题
javascript·vue.js·elementui
neter.asia2 小时前
vue中如何关闭eslint检测?
前端·javascript·vue.js
~甲壳虫2 小时前
说说webpack中常见的Plugin?解决了什么问题?
前端·webpack·node.js
十一吖i3 小时前
前端将后端返回的文件下载到本地
vue.js·elementplus
光影少年3 小时前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js
Beamon__3 小时前
element-plus按需引入报错AutoImport is not a function
webpack·element-plus
CodeToGym3 小时前
Webpack性能优化指南:从构建到部署的全方位策略
前端·webpack·性能优化
~甲壳虫3 小时前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js
~甲壳虫3 小时前
说说webpack proxy工作原理?为什么能解决跨域
前端·webpack·node.js