Rspack 在 vue-cli 4.x + vue2.6 的项目集成和上线,提高5x构建速度!

背景

前端项目工程的开发和编译时间很慢,通过调研vite,发现开发环境的使用还是挺快的,所以在项目中进行开发模式的实践,最后也落地了一下vite开发的模式。

当前,公司项目编译还是采用webapck编译部署,项目部署普遍在3min以上,有的可能甚至更长,影响编译部署测试环境的体验。

所以想利用vite在部署编译上能不能有落地,但经过一段时间的研究发现,并不能vite生产编译不是很好,一些公司内部的webpack都需要进行重写,成本很高,构建速度甚至还不如webpack。随着rspack的推出,官方据说项目接入之后会有5-10倍的构建提升编译时间越长,优化空间也是巨大的 。所以对rspack研究了相当多的时间(几个月),现在已经在c2c这个大项目中进行了部署上线,取得了不错的效果。从之前的3-4min到现在的39s左右,算上部署过程中的安装包和部署校验啥的,总共花费时间也在1min之内。

填坑经历

接入

node版本使用14.20以上

非webpack5项目

升级项目到webpack5,已经是webpack5可以下一步

js 复制代码
使用"vue-loader" 指定版本 15.11.1

使用 @vue/cli-service@5.0.0-beta.6

@vue/cli-plugin-typescript@5.0.0-beta.6

@vue/cli-plugin-babel@5.0.0-beta.6

"@vue/babel-preset-app": "^5.0.8"

"@rspack/cli": "^0.3.10"

"webpack": "5.89.0"

webpack5项目

perl 复制代码
使用"vue-loader" 指定版本 15.11.1
"@rspack/cli": "^0.3.10"
"webpack": "5.89.0"

根目录添加 rspack.confg.js

javascript 复制代码
const path = require('node:path')
const rspack = require('@rspack/core')
const { VueLoaderPlugin } = require('vue-loader')

const isProduction = process.env.NODE_ENV === 'production'
const imgPublicPath = 'https://img1.demo.com/path/'
const assetsPublicPath = 'https://s1.demo.com/path/'
const publicPath = isProduction ? assetsPublicPath : '/path/'


function resolve(dir) {
  return path.join(process.cwd(), dir)
}
const rspackPlugins = [
  new VueLoaderPlugin(),
  new rspack.HtmlRspackPlugin({
    template: 'public/index.html',
    filename: isProduction ? 'webserver/index.html' : 'index.html'
  }),
  new rspack.CopyRspackPlugin({
    patterns: [
      {
        from: 'public',
        globOptions: {
          ignore: ['**/index.html']
        }
      }
    ]
  })
]

/**
 * @type {import('@rspack/cli').Configuration}
 */
const baseWebpackConfig = {
  cache: false,
  mode: isProduction ? 'production' : 'development',
  context: __dirname,
  entry: {
    main: './src/main.ts'
  },
  output: {
    clean: true,
    publicPath,
    cssFilename: 'static/css/[name].[contenthash:8].css',
    filename: 'static/js/[name].[contenthash:8].js',
    cssChunkFilename: 'static/css/[name].[contenthash:8].css',
    chunkFilename: 'static/js/[name].[contenthash:8].js'
  },
  target: ['web', 'es5'],
  builtins: {
    PresetEnv: {
      mode: 'entry',
      targets: ['2015']
    },
    pluginImport: [
      {
        libraryName: 'vant',
        style: '{{ kebabCase member }}/style/index.js'
      }
    ]
  },
  devServer: {
    https: true,
    hot: true,
    host: 'local-ip',
    port: 8088,
    allowedHosts: 'all',
    historyApiFallback: true
  },
  module: {
    rules: [
      {
        test: /.vue$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              experimentalInlineMatchResource: true
            }
          }
        ]
      },
      {
        test: /.tsx$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                ['@babel/preset-typescript', { allExtensions: true, isTSX: true }],
                [
                  // 注意 @vue/babel-preset-jsx适配vue2.x @vue/babel-plugin-jsx 适配vue3.x
                  '@vue/babel-preset-jsx',
                  {
                    injectH: false
                  }
                ]
              ]
            }
          }
        ]
      },
      {
        test: /.css$/,
        use: ['postcss-loader'],
        type: 'css'
      },
      {
        test: /.scss$/,
        use: [
          'postcss-loader',
          'sass-loader',
          {
            loader: 'style-resources-loader',
            options: {
              patterns: [
                resolve('src/assets/vars.scss'),
                resolve('src/assets/common.scss')
              ],
              injector: 'prepend'
            }
          }
        ],
        type: 'css'
      },
      {
        test: /.less$/,
        use: ['postcss-loader', 'less-loader'],
        type: 'css'
      },
      {
        resourceQuery: /lang=ts/, // 如果需要在 Vue SFC 里使用 Typescript, 请添加该规则
        type: 'ts'
      },
      {
        test: /.(png|jpe?g|gif|svg)/i,
        type: 'asset',
        generator: {
          publicPath: isProduction ? imgPublicPath : publicPath,
          filename: 'static/img/[name].[hash:8][ext]'
        }
      },
      {
        test: /.(png|jpe?g|gif|svg)/i,
        type: 'asset/inline',
        generator: {
          publicPath: isProduction ? imgPublicPath : publicPath,
          filename: 'static/img/[name].[hash:8][ext]'
        }
      },
      {
        test: /.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'static/font/[name].[hash:8][ext]'
        }
      }
    ]
  },
  experiments: {
    css: true
  },
  resolve: {
    extensions: ['.mjs', '.js', 'jsx', '.ts', '.tsx', '.vue'],
    alias: {
      '@': resolve('src'),
      '@src': resolve('src'),
      'vue-loader': resolve('node_modules/vue-loader')
    }
  },
  optimization: {
    realContentHash: true,
    splitChunks: {
      cacheGroups: {
        someVendor: {
          chunks: 'all',
          minChunks: 2
        }
      }
    }
  },
  plugins: rspackPlugins
  // stats: 'verbose'
}
module.exports = baseWebpackConfig

注意事项

  • 因为rspack对AMD规范没有全面支持。所以遇到打包后页面报

    require is not defined,需要找到相关依赖包,升级到最新的AMD规范的包。相关issue在

    github.com/web-infra-d...

    所以需要升级相关依赖包看能不能解决。

  • 如果项目中采用下图中的方式书写代码,里面包含render jsx,需要在script中添加lang="tsx",让tsx loader进行处理

  • 注意 @vue/babel-preset-jsx适配vue2.x @vue/babel-plugin-jsx 适配vue3.x

  • script配置 build采用rspack build进行编译,开发的话可以采用,dev:rspack或者dev:vuecli,由于rspack对dev支持不是特别好,可以开发采用cli的。当然开发也可以采用vite

js 复制代码
"build:rspack": "rspack build",
"build:vuecli": "vue-cli-service build --no-module",
"dev:rspack": "rspack serve",
"dev:vuecli": "vue-cli-service serve",
"dev": "npm run dev:vuecli",
"build": "npm run build:rspack"

回归测试

  1. 项目部署到测试环境后,对项目中的路由都进行一下回归,看看页面有问题没,console有没有异常。可以小组内分模块进行回归。
  2. 测试一下离线包和预渲染等
  3. 上线后观察sentry有没有异常

接入效果

接入前

接入之后

总结

虽然接入rspack不是一帆风顺的,但结果是好的,并且自己也收获了很多,学习了相关的webpack,vue-loader知识等。rspack对webpack相关的生态支持还是比较好的,比如公司内部的离线包和sentry插件都不用改,直接可以进行使用。接入成本是很低的,最后也可以考虑集成到内部脚手架,方便其他同学使用。

相关推荐
answerball2 小时前
🔥 Vue3响应式源码深度解剖:从Proxy魔法到依赖收集,手把手教你造轮子!🚀
前端·响应式设计·响应式编程
Slow菜鸟2 小时前
ES5 vs ES6:JavaScript 演进之路
前端·javascript·es6
小冯的编程学习之路2 小时前
【前端基础】:HTML
前端·css·前端框架·html·postman
Jiaberrr4 小时前
Vue 3 中搭建菜单权限配置界面的详细指南
前端·javascript·vue.js·elementui
懒大王95274 小时前
uniapp+Vue3 组件之间的传值方法
前端·javascript·uni-app
烛阴5 小时前
秒懂 JSON:JavaScript JSON 方法详解,让你轻松驾驭数据交互!
前端·javascript
拉不动的猪5 小时前
刷刷题31(vue实际项目问题)
前端·javascript·面试
zeijiershuai5 小时前
Ajax-入门、axios请求方式、async、await、Vue生命周期
前端·javascript·ajax
恋猫de小郭5 小时前
Flutter 小技巧之通过 MediaQuery 优化 App 性能
android·前端·flutter
只会写Bug的程序员5 小时前
面试之《webpack从输入到输出经历了什么》
前端·面试·webpack