vite使用引入cdn遇到的坑!

1.前言

        最近在公司做对项目优化,优化项目体积大小,其中之一就是使用cdn外链的方式来减小打包的体积。本文章不做打包优化的具体配置以及项目是如何优化的,只总结遇到让我十分困扰的问题。

2.如何进行cdn?

        我在此之前也没有接触过vite项目,一直使用的是webpack,对vite不是很熟悉,配置vite的cdn我也是从网上找到的插件 vite-plugin-cdn-import,使用方式也很简单,用法就不过多赘述,官方文档上有使用介绍,下面是我的配置步骤:

  1. 配置cdn地址链接
  2. 配置打包忽略react,react-dom打包到最终的产物
// npm install vite-plugin-cdn-import --save-dev

import importToCDN from 'vite-plugin-cdn-import'

export default ({ mode }: any) => {
  return defineConfig({
    // ...
     plugins: [
        // 配置cdn地址
       importToCDN({
          modules: [
            {
              name: 'react', // 包名
              var: 'React',  // 为环境提供的全局变量
              path: 'https://unpkg.com/react@18.3.1/umd/react.production.min.js',
            },
            {
              name: 'react-dom',
              var: 'ReactDOM',
              path: 'https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js',
             },
          ],
       }),
     ],
     build: {
        // 配置打包
        rollupOptions: {
            // 忽略react,react-dom打包到最终的产物
           external: ['react', 'react-dom'],
           // ...
        }
     }
    //...
  })
}

本以为很完美,配置结束了,但是真实情况并非如此!遇到了三个让人头疼的问题。

3.问题

 1.Uncaught TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".

        这个问题的意思是:未捕获的类型错误:未能解析模块说明符“react”。相对引用必须以“/”、“./”或“../”开头。什么鬼?!根本不知道什么意思,只能借助谷歌寻找答案,最后弄明白了问题的原因!

        首先这是一个常见的问题,它通常表示在模块解析过程中有些问题。这个错误通常出现的原因是:尽管你已经通过 CDN 配置了 React,但 Vite 在构建或开发过程中仍在尝试从本地 node_modules 解析这些库,而不是使用 CDN 提供的全局变量。查阅vite-plugin-cdn-import 找到一条Issues:

引入react的cdn会报如下错误 · Issue #17 · MMF-FE/vite-plugin-cdn-import · GitHub

既然有人遇到了相同的问题,顺着这条线索我尝试了Issues中的解决办法!

  1. 使用 vite-plugin-externals ,这个插件是用于外部资源,比如cdn资源,它可以在不配置rollup的选项,就可以使用在生产环境。
  2. 配置使用 @vitejs/plugin-react 这个插件是React 项目的默认 Vite 插件有几个有点。
    1. 在开发中启用快速刷新
    2. 使用自动 JSX 运行时
    3. 使用自定义 Babel 插件/预设
    4. 安装尺寸小

我最初使用的是 @vitejs/plugin-react-swc,替换成 @vitejs/plugin-react 是因为他可以配置 jsx runtime

// npm install vite-plugin-externals --save-dev
// npm install @vitejs/plugin-react --save-dev

import react from '@vitejs/plugin-react';
import importToCDN from 'vite-plugin-cdn-import';
import { viteExternalsPlugin } from 'vite-plugin-externals';

export default ({ mode }: any) => {
  return defineConfig({
    // ...
     plugins: [
       // 配置react 线上的兼容模式,使用经典模式
       react({ jsxRuntime: mode === 'production' ? 'classic' : 'automatic' }),
       // 配置cdn地址
       importToCDN({
          modules: [
            {
              name: 'react', // 包名
              var: 'React',  // 为环境提供的全局变量
              path: 'https://unpkg.com/react@18.3.1/umd/react.production.min.js',
            },
            {
              name: 'react-dom',
              var: 'ReactDOM',
              path: 'https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js',
             },
          ],
        }),
        // 这个插件也是帮助vite忽略react,react-dom打包到最终的产物
        mode === 'production' &&
        viteExternalsPlugin({
          react: 'React',
          'react-dom': 'ReactDOM',
        }),
     ].filter(Boolean),
     build: {
        // 配置打包
        rollupOptions: {
           // 忽略react,react-dom打包到最终的产物
           // external: ['react', 'react-dom'],
           // ...
        }
     }
    //...
  })
}

这个办法引出了我遇到的第二个问题。

2.TypeError: Cannot read properties of null (reading 'useEffect')

        这个错误通常指向 React 运行时环境或库的问题,这可能是由于构建过程中的配置问题或者 React 自身未能正确加载或初始化。

        这个问题我查找了很多资料,但是都没有找到相关的解决方案,但是我知道还是我的配置问题。

3.Uncaught TypeError: React.jsx is not a function

        在我配置cdn的时候我具体忘记我是哪一步的操作导致了报这个错误,这个错误的原因是:虽然你使用 CDN 引入了 React,但 CDN 提供的 UMD 版本可能并不包含 React.jsx 这个函数。这个函数是在 React 的新的 JSX 转换机制中使用的,可能并不在所有构建版本中都可用。

        在第一个错误的时候我提到了@vitejs/plugin-react-swc 这个插件,它的官方介绍 jsxRuntime 总是 automatic,所以我替换了 @vitejs/plugin-react 插件,这个插件可以更改 jsxRuntime 为 classic,对打包后的产物使用经典模式(classic),(automatic 为React的新版本模式),在官方文档也有介绍:引入新的 JSX 转换。虽然我解决的我本地代码的 React.jsx is not a function,但是在@antd-Dsign/pro-component 中依然使用的 React.jsx 的方法,所以问题依然未解决。配置在上面的代码中!

4.最终的解决方案:

        在vite的官方文档查找到了这个插件 vite-plugin-external(不是 vite-plugiin-externals,这是两个插件), 这个插件的做用我引用官方的解释:

        当 command 的值为 'serve' 时,插件将 externals 转换成 alias 配置,这样可以直接使用 Vite 的文件加载能力;当 command 的值为 'build' 时,插件将 externals 转换成 rollupOptions 配置, 包含 external 和 output.globals但是可以通过配置 interop 为 'auto',统一将 externals 转换成 alias 配置,打包后的代码中会使用兼容代码导入外部依赖。

配置如下:

// npm install vite-plugin-external --save-dev

import react from '@vitejs/plugin-react-swc';
import importToCDN from 'vite-plugin-cdn-import';
import createExternal from 'vite-plugin-external';

export default ({ mode }: any) => {
  return defineConfig({
    // ...
     plugins: [
       // 配置react 线上的兼容模式,使用经典模式
       react(),
       // 配置cdn地址
       importToCDN({
          modules: [
            {
              name: 'react', // 包名
              var: 'React',  // 为环境提供的全局变量
              path: 'https://unpkg.com/react@18.3.1/umd/react.production.min.js',
            },
            {
              name: 'react-dom',
              var: 'ReactDOM',
              path: 'https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js',
             },
          ],
        }),
        // 这个插件也是帮助vite忽略react,react-dom打包到最终的产物
        mode === 'production' &&
        createExternal({
          interop: 'auto', // 这个声明很重要
          externals: {
            react: 'React',
            'react-dom': 'ReactDOM',
          }
        }),
     ].filter(Boolean),
     build: {
       // ... 删除掉 externals 的配置 vite-plugin-external 会帮助做
     }
    //...
  })
}

我将 @vitejs/plugin-react 插件又替换回了@vitejs/plugin-react-swc也没有出现 React.jsx is not a function 问题 ,最后以上的问题都迎刃而解了,这个问题困扰我很久,特此记录一下。大佬们如果遇到以上问题,希望我这个文章能有所帮助,最后总结一下问题:

  1. 使用 vite-plugin-cdn-import 引入cdn外链
  2. 使用 vite-plugin-external 忽略cdn外链,内部自动配置rollup配置。

兜兜转转最后就用了一个插件就解决了以上所有问题,😭!

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值