我们从 UmiJS 迁移到了 Vite

发表于 3年以前  | 总阅读数:496 次

我们从 UmiJS 迁移到 Vite 已经上线半年多了。迁移过程中也遇到了不少问题,好在 Vite 足够优秀,继承自 Rollup 的插件系统,使我们有了自由发挥空间。目前很多人对 Vite 跃跃欲试,Vite 开发体验到底怎么样,今天来叙叙迁移到 Vite 的亲身经历。先说结论,Vite 已经很成熟,强烈建议有条件的可以从 webpack 迁移过来。

为什么要放弃 UmiJS

2019 年底,在 Webpack 横行霸道,各种脚手架琳琅满目的时代选择了 UmiJS。它配置少、功能多、文档齐全、持续更新。一整套的解决方案,非常适合一个大部分非 React 技术栈的团队。经过不断地磨合,团队很快适应了这种 React 开发模式,开发效率也是水涨船高。

凡事总有个原因,为什么要迁移。2021 年初,为适应公司的发展,前端架构也需要做调整与升级。在项目日益增长的情况下,一次项目启动需要耗费一分多钟,热更新也慢得基本无法使用。差点的机器配置启动项目要么好几分钟、要么内存溢出。这种模式极大地降低了开发效率。无论是自定义修改内部 webpack 插件、从各种角度如多核编译、缓存等方式优化,依然是杯水车薪。虽然 UmiJS 提供了 webpack5 插件,不过在当时处于不可用的状态。

我们主要的矛盾是:

  1. 启动时间长
  2. 热更新慢
  3. 太臃肿
  4. 框架 BUG 修复不及时
  5. 过度封装,自定义插件难度大
  6. 约定式功能太单一

适应业务的要求,我们也需要上微前端。UmiJS 也提供了微前端插件 “乾坤”。但依然解决不了根本开发体验问题。因此,在基础脚手架上,我们寻求更多的是可控性及透明性。(尽管UmiJS 现在已经支持Module Federation 的打包提速方案)

为什么是 Vite

市面上的脚手架很多,阵营却很少,大部分是基于 webpack 的上层封装。webpack 的缺点很明显,当冷启动开发服务器时,基于打包器的方式启动必须优先抓取并构建你的整个应用,然后才能提供服务。

在浏览器 ESM 支持得很普遍得今天,Vite 这种可以称得上是下一代前端开发与构建工具。在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,无论应用大小如何,HMR 始终能保持快速更新。

Vite 这种方式在我们习惯 webpack 的阴影下显得尤为惊艳,可以说 Vite 完美地解决了我们所有的痛点。不过 Vite 也是刚发布 2.0 不久,踩过坑的人也是相当少。我们便试试 Vite

前期调研

迁移的必要条件是在原有的功能下找到替代方案,我们便统计用到了 UmiJS 中的 API 及特性

UmiJS 配置

  • alias - 配置别名(对应 resolve.alias)
  • base - 设置路由前缀(对应 base)
  • define - 用于提供给代码中可用的变量(对应 define)
  • outputPath - 指定输出路径(对应 build.outDir)
  • hash - 配置是否让生成的文件包含 hash 后缀 (Vite 自带)
  • antd - 整合 antd 组件库 (无需框架提供,Vite 中可自己引用)
  • dva - 整合 dva 数据流(此库已经很久没有更新了,在 hooks 时代使用显得格格不入。我们没有大量使用,重写一个文件很轻松)
  • locale - 国际化插件,用于解决 i18n 问题(需要自己实现国际化逻辑,都是基于 react-intl 封装,在 Vite 中实现无压力)
  • fastRefresh - 快速刷新(对应 @vitejs/plugin-react-refresh 插件)
  • dynamicImport - 是否启用按需加载(路由级的按需加载,在 Vite 中用 React.lazy 封装)
  • targets - 配置需要兼容的浏览器最低版本(对应 @vitejs/plugin-legacy 插件)
  • theme - 配置 less 变量(对应 css.preprocessorOptions.less.modifyVars 配置)
  • lessLoader - 设置 less-loader 配置项(与 theme 配置相同)
  • ignoreMomentLocale - 忽略 moment 的 locale 文件(可以通过 alias 设置别名方式解决)
  • proxy - 配置代理能力(对应 server.proxy)
  • externals - 设置哪些模块可以不被打包(对应 build.rollupOptions.external)
  • copy - 设置要复制到输出目录的文件或文件夹(对应 rollup-plugin-copy)
  • mock - 配置 mock 属性(对应 vite-plugin-mock)
  • extraBabelPlugins - 配置额外的 babel 插件(对应 @rollup/plugin-babel)

通过配置分析,基本上所有的 UmiJS 配置都可以在 Vite 中找到替代方案。除了配置还有一些约定

UmiJS 中 @/* 路径,代替方式

defineConfig({
  resolve: {
    alias: {
      '@/': `${path.resolve(process.cwd(), 'src')}/`,
    },
  },
});

迁移

Review 现有的代码,找出可能出问题的点并统计。做前期准备。跑起来优先:

从头 Vite 官方模板中创建一个项目,安装所需依赖包。UmiJS 内置封装了 react-routerantd``react-intl,这里我们需要手动加上 BrowserRouterConfigProviderLocaleProvider

// App.tsx
exportdefaultfunction App() {
  return (
    <AppProvider>
      <BrowserRouter>
        <ConfigProvider locale={currentLocale}>
          <LocaleProvider>
            <BasicLayout>
              <Routes />
            </BasicLayout>
          </LocaleProvider>
        </ConfigProvider>
      </BrowserRouter>
    </AppProvider>
  );
}

根据之前约定式路由,添加相应的路由配置

exportconst basicRoutes = [
  {
    path: '/',
    exact: true,
    trunk: () =>import('@/pages/index'),
  },
  {
    path: '/login',
    exact: true,
    trunk: () =>import('@/pages/login'),
  },
  {
    path: '/my-app',
    trunk: () =>import('@/pages/my-app'),
  },
  // ...
];

路由渲染组件,通过 React.lazy 实现 UmiJS 中的 dynamicImport

const routes = basicRoutes.map(({ trunk, ...config }) => {
  const Trunk = React.lazy(() => trunk());
  return {
    ...config,
    component: (
      <React.Suspense fallback={<Spinner />}>
        <Trunk />
      </React.Suspense>
    ),
  };
});

exportdefaultfunction Routes() {
  return (
    <Switch>
      {routes.map((route) => (
        <Route key={route.key || route.path} path={route.path} exact={route.exact} render={() => route.component} />
      ))}
    </Switch>
  );
}

从原先的约定式路由迁移完成,项目中主要不兼容的地方就是从 umi 导入的成员

import { useIntl, history, useLocation, useSelector } from'umi';

我们需要将所有 umi 中导入的变量,通过编辑器的正则替换批量修改替换。

  • 国际化的 useIntl 通过将语言文件和 react-intl 封装,导出一个全局的 formatMessage 方法
  • 路由相关的 API 用 react-router-dom 导出替换
  • Redux 相关的,用 react-redux 导出替换
  • 查找项目中使用 require 的地方,替换为动态 import
  • 查找项目中使用 process.env.NODE_ENV,替换为 import.meta.env.DEV,因为再 Vite 中不再有 node.js 相关的 API

antd 添加进项目后,发现 babel-plugin-import 对应的 Vite 插件似乎有问题,某些样式在 dev 模式下缺失,打包后正常。排查发现是组件包里面引用了 antd,在 dev 模式下包名被“依赖预构建” 混淆,导致插件无法正确插入 antd 的样式。为此,我们自己写了个插件,在 dev 模式下全量引入样式,prod 才走插件。

很轻松,第一个页面成功运行。

由于迁移之后需要使用微前端,因此我们将公共配置通过外置插件统一管理。

exportdefault defineConfig({
  server: {
    // 每个项目配置不同的端口号
    port: 3001,
  },
  plugins: [
    reactRefresh(),
    // 公共配置插件
    baseConfigPlugin(),
    // AntD 插件
    antdPlugin(),
  ],
});

迁移后发现 Vite 需要配置的其实很少,抽取的公共配置,封装成 Vite 插件。

import path from'path';
import LessPluginImportNodeModules from'less-plugin-import-node-modules';

exportdefaultfunction vitePluginBaseConfig(config: CustomConfig): Plugin {
  return {
    enforce: 'post',
    name: 'base-config',
    config() {
      return {
        cacheDir: '.vite',
        resolve: {
          alias: {
            '@/': `${path.resolve(process.cwd(), 'src')}/`,
            lodash: 'lodash-es',
            'lodash.debounce': 'lodash-es/debounce',
            'lodash.throttle': 'lodash-es/throttle',
          },
        },
        server: {
          host: '0.0.0.0',
        },
        css: {
          preprocessorOptions: {
            less: {
              modifyVars: {
                '@primary-color': '#f99b0b',
                ...config.theme,
                // 自定义 ant 前缀
                '@ant-prefix': config.antPrefix || 'ant',
              },
              plugins: [new LessPluginImportNodeModules()],
              javascriptEnabled: true,
            },
          },
        },
      };
    },
  };
}

迁移的整个过程没有想象中那么繁杂,反而相对容易。几乎常用的功能 Vite 都有方案支持,这也许是 Vite 的厉害之处吧。其实本质上的复杂度在于业务,项目的复杂度就是代码量的体现,通过 IDE 的搜索替换,很快便完成了迁移并成功的运行。

现在,我们所有的项目都基于 Vite,完全没有了等待而摸鱼的烦恼。

问题/解决

转换 less 文件 @import '~antd/es/style/themes/default.less' 中的 ~ 别名报错

配置 less 插件less-plugin-import-node-modules

SyntaxError: The requested module 'xxx' does not provide an export named 'default'

我们将公共组件作为独立的 npm 包之后使用时遇到的错误。本想着公共组件包自己不编译,统一交给使用方编译。所以导出了 TS 源文件。而这种情况常规下没有问题,Vite 一旦遇到 CommonJSUMD 的包才导致无法解析。虽然可以将无法解析的包放入 optimizeDeps.include 。但是架不住包的数量多啊,还是将它 tsc 转译为 JS 文件再发布。

打包提速

首次打包发现需要 70 多秒,我们来优化打包结构

  • 通过 build.minify 改为 esbuild(最新版 Vite 已经默认 esbuild) 。Esbuildterser 快 20-40 倍,压缩率只差 1%-2%。开启后降低到 30 多秒
  • babel-plugin-import 的类似 babel 插件严重拖后腿,总共不到 40 秒的时间,它就要占 10 秒。我们通过正则的方式做了个插件,完美解决
  • 通过分析 rollup@ant-design/iconslodash 包的 transform 数量非常多。我们将这些包也加入到刚刚做的插件中

通过一顿操作下来,提速到 16 秒,先这样吧。

为什么将 cacheDir 放在根目录

cacheDir 作为存储缓存文件的目录。此目录下会存储预打包的依赖项或 vite 生成的某些缓存文件,使用缓存可以提高性能。在某些情况下需要联调 node_modules 里包,从而导致修改后未生效。这时需要使用 --force 命令行选项或手动删除目录,放在根目录便于删除。

兼容性问题

Vite 的兼容性可以通过官方的插件 @vitejs/plugin-legacy 解决。我们已经放弃支持 IE 11,无限制在生产使用 ESM,羡慕吗?

结语

如果你是新的项目,完全不必考虑 Webpack 了,Viterollup 的完全生态足够支撑上生产。如果你是 Webpack 生态老项目,不忍体验上的折磨,满足迁移条件的话,不妨试试 Vite,肯定会带给你惊喜。

后面我会分享 Vite 和自己实现的微前端搭配组合,以及Vite 相关的插件,请持续关注。

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/8LF7HbQEL0dnuNs_IkH1gw

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237229次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录