likes
comments
collection
share

🚀 从 create-react-app 迁移到 vite ⚡️

作者站长头像
站长
· 阅读数 67

要不要迁移❓

一、star 对比

create-react-app 底层用的是 webpack,让我们来对比下 webpack 和 vite 的历史 star 数趋势:

🚀 从 create-react-app 迁移到 vite ⚡️

webpack 从 2012 开始,11 年间到达 63k star,而 vite 从 2020 年,只用了 3 年就达到 56k star,曲线更陡峭,上升更快。

二、时间对比

以我维护的项目(技术栈:webpack5+Ant4+React18+mobx+axios)进行体验

create-react-app vs vite4:

启动开发服务器(dev server)模块热替换(HMR)构建产物(build)
create-react-app15.45s4.09s1min08s
vite0.49s~0.63s<=1s19.57s~23.81s
节省时间14.86s3.09s44.19s
节省时间占比96.8%77%65%

其中,启动开发服务器在 0.49s ~ 0.63s,真是比秒开还快了!

🚀 从 create-react-app 迁移到 vite ⚡️

说明:create-react-app 是手动计时取中间值,vite dev server时间是观察命令行控制台,多次记录取最大值和最小值,HMR 刷新是红轴机械键盘按键一按到底,页面就已经刷新,从控制台上看到的每次的时间差值,都是 1s,那实际应该小于等于 1s。

三、vite 两大特点

正如官网介绍的,它大大提升了本地开发体验:

  1. 更快地启动(对应 create-react-app 的 npm run start 命令)

    关键在于依赖模块的处理,由于 底层使用编译型语言 Go 预构建依赖,比以 JavaScript 编写的打包器(create-react-app 就是基于JavaScript)预构建依赖 快 10-100 倍

  2. 更快热更新(对应 create-react-app 的 动态模块热替换 HMR)

    在源码处理上,Vite 以 ESM 方式返回浏览器源码。 只需在浏览器请求源码时进行转换并按需提供,这样某个文件改变时,可以精确定位,无需打包就返回给浏览器。

    下面官方中文文档的对比图,可以帮助更好理解。

    图一 是基于 JS bundle 的开发服务器(如 webpcak)

    🚀 从 create-react-app 迁移到 vite ⚡️

    图二 是基于 ESM 方式的开发服务器

    🚀 从 create-react-app 迁移到 vite ⚡️

一起迁移吧 💪

零、尝试迁移工具

先尝试下 wp2vite,按操作发现 vite 版本还是 2,npm run start 也没有跑起来,从代码记录上已经两年多没更新了。

package.json 的 vite 版本:

🚀 从 create-react-app 迁移到 vite ⚡️

npm run start 报错了:

🚀 从 create-react-app 迁移到 vite ⚡️

代码记录:

🚀 从 create-react-app 迁移到 vite ⚡️

webpack-to-vite 是在 awesome-vite 列表上出现的。从文档上看,目前支持 vue,还未支持 create-react-app。

坚强的 React 开发者,只能一起手动迁移了!💪

一、常规步骤

新建一个 Vite React 模板代码库:

🚀 从 create-react-app 迁移到 vite ⚡️

对照 vite 项目和旧的 create-react-app 项目,需要更改如下:

  • 更新 package.json

    // package.json
    {
      "version": "x.y.z",
      "private": true,
      "scripts": {
        "dev": "vite",
        "build": "tsc && vite build",
        "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
        "preview": "vite preview"
      },
      "devDependencies": {
        "vite": "^4.3.9",
        "@vitejs/plugin-react": "^4.0.0",
      }
    }
    
  • 在要迁移的create-react-app项目新建 vite.config.ts 文件

    // vite.config.ts
    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [react()],
    })
    
  • index.htmlpublic 文件夹下移到根目录

  • index.html 需要去掉 %PUBLIC_URL%; 同时新增 script <script type="module" src="/src/index.jsx"></script>; 记得把 /src/index.js 更改为 /src/index.jsx

    <-- index.html -->
    <script type="module" src="/src/index.jsx"></script>
    
  • 把带有 JSX 的 js/ts 文件名,更新为 jsx/tsx

    不然会报错:

    🚀 从 create-react-app 迁移到 vite ⚡️

二、路径别名

如果在 config/webpack.config.js 或其他位置配置了路径别名,则需要到 vite/config.ts 也配置

比如我配置的是 '@' 路径别名

// config/webpack.config.js
module.exports = function (webpackEnv) {
    return {
        resolve: {
            alias: {
                // ...
                '@': path.resolve(__dirname, '../src')
            }
        }
    }
}

需要在 vite/config.ts 对应配置如下:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: [{
      find: "@", replacement: path.resolve(__dirname, "src")
    }]
  },
})

三、CSS 预处理器

vite 自动提示了缺少的预处理器,如 sass

🚀 从 create-react-app 迁移到 vite ⚡️

安装 sass: npm i sass --save-dev

如果使用的是 less、stylus,安装下对应的处理器即可,更多可查阅 Vite 官方中文文档 - CSS 预处理器

四、require is not define

运行 npm run dev 时,浏览器报错 require is not define

🚀 从 create-react-app 迁移到 vite ⚡️

通过添加 @originjs/vite-plugin-commonjs 插件解决了

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs'
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    viteCommonjs(),
  ],
  // ...
  optimizeDeps: {
    esbuildOptions: {
      plugins:[
        // 我用到了 react-resizable,添加了 viteCommonjs 仍报错,单独在这里配置解决了
        esbuildCommonjs(['react-resizable'])
      ]
    }
  }
})

参考链接: github.com/vitejs/vite…

五、代理开发服务器请求

在 webpack 中如果对开发服务器的 localhost api 路径代理到自己的后端服务器

// src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
        changeOrigin: true,
        target: 'https://dev.mysite.com',
    })
  )
};

则对应到 vite 的配置如下:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs'
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
    // ...
    server: {
        // create-react-app 默认端口是 3000,可以在这改
        port: 3000,
        proxy: {    // 开发服务器代理规则
        '/api': {   // 使用 proxy 实例
            target: 'https://dev.mysite.com',
            changeOrigin: true,
        },
    },
  },
})

更多配置可以查看 Vite 官方中文文档 - server.proxy

六、Antd 样式问题与按需导入

Antd 样式 less 报错:

🚀 从 create-react-app 迁移到 vite ⚡️

通过配置 preprocessorOptions.less.javascriptEnabled = true 解决

// https://vitejs.dev/config/
export default defineConfig({
  css: {
    preprocessorOptions: {
      less: { javascriptEnabled: true },
    },
  },
})

支持 antd 样式按需导入

npm i vite-plugin-imp --save-dev

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteCommonjs } from '@originjs/vite-plugin-commonjs'
import vitePluginImp from 'vite-plugin-imp'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    viteCommonjs(),
    // antd 样式按需导入
    vitePluginImp({
      optimize: true,
      libList: [
        {
          libName: 'antd',
          libDirectory: 'es',
          style: (name) => `antd/es/${name}/style`
        }
      ]
    })
  ],
})

七、svg 图片转换为 svg 元素

引入 svg 图片给 img src 是 vite 默认就支持的。这样 svg 会作为一张图片传给浏览器。使用如下:

import logo from "./icons/logo.svg";
<img src={logo} alt={"logo"}

如果 webpack 配置了将 svg 图片作为组件使用,最后转换为 svg 元素传给浏览器,可能会用到了 webpack svg loader react-svg-loader@svgr/webpack

对应到 vite,需要安装依赖 npm i vite-plugin-svgr --save-dev

vite 新增配置如下:

import svgr from 'vite-plugin-svgr'
export default defineConfig({
    // ...
    plugins: [
        react(),
        svgr(),
        // ...
    ],
})

在代码上使用:

import logo, { ReactComponent as Logo } from "./icons/logo.svg";

<img src={logo} alt={"logo"}/>
<Logo />

浏览器效果:

🚀 从 create-react-app 迁移到 vite ⚡️

八、生产版本 require is not defined

运行 npm run build, 再运行 npm run preview 时浏览器报错:

-> err bound ReferenceError: require is not defined

🚀 从 create-react-app 迁移到 vite ⚡️

定位报错位置:

🚀 从 create-react-app 迁移到 vite ⚡️

在 vite 使用行内 require 图片会报错,可以修改如下:

{
    titleIcon: new URL('../icons/info-icon.png', import.meta.url).href
}

上面这种方式更适合动态 URL

我们也可以直接改为 import 引入图片即可

import infoIcon from '../icons/info-icon.png';
{
    titleIcon: infoIcon
}

更多资料可查询 Vite中文网 - 静态资源处理

另一个 require is not defined 报错是 uuid 引入方式问题,需要把 require 改为 import

🚀 从 create-react-app 迁移到 vite ⚡️

🚀 从 create-react-app 迁移到 vite ⚡️

修改如下:

🚀 从 create-react-app 迁移到 vite ⚡️

九、产物太大,如何优化

一起看下 npm run build 后得到文件:

🚀 从 create-react-app 迁移到 vite ⚡️

只有一个 JS 文件 和 CSS 文件,其他都是图片等资源。

也就是全部 JS 源码都打包到一起了,有 2004kB,即使 gzip 了也有 639kB,算是挺大了。

回想下以前 webpack 一般如何进行打包优化的,分为几个部分:

  1. 对于单页面,拆分JS,减小体积(代码分割)
  2. 对于多页面之间,提取公共资源,减少加载次数(代码合并)
  3. 几乎不变动的第三方库也提取出来(node_modules/* 打包后叫 vendor.js) 比如 Antd、lodash、react 这些第三方库,升级版本了,才会更新
  4. manifest.js,记录了 JS 文件映射表

Vite 4 里有什么可选的打包优化方案呢?

参考资料

到这里本文就结束了,您的点赞、关注与收藏,是我持续学习和写作的动力!

本文未涉及的或写得不清楚的,热烈欢迎您的评论和留言! Thanks♪(・ω・)ノ

转载自:https://juejin.cn/post/7240487843223142458
评论
请登录