
vite使用引入cdn遇到的坑!
vite使用插件vite-plugin-cdn-import报错Uncaught TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".
1.前言
最近在公司做对项目优化,优化项目体积大小,其中之一就是使用cdn外链的方式来减小打包的体积。本文章不做打包优化的具体配置以及项目是如何优化的,只总结遇到让我十分困扰的问题。
2.如何进行cdn?
我在此之前也没有接触过vite项目,一直使用的是webpack,对vite不是很熟悉,配置vite的cdn我也是从网上找到的插件 vite-plugin-cdn-import,使用方式也很简单,用法就不过多赘述,官方文档上有使用介绍,下面是我的配置步骤:
- 配置cdn地址链接
- 配置打包忽略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中的解决办法!
- 使用 vite-plugin-externals ,这个插件是用于外部资源,比如cdn资源,它可以在不配置rollup的选项,就可以使用在生产环境。
- 配置使用 @vitejs/plugin-react 这个插件是React 项目的默认 Vite 插件有几个有点。
- 在开发中启用快速刷新
- 使用自动 JSX 运行时
- 使用自定义 Babel 插件/预设
- 安装尺寸小
我最初使用的是 @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 的问题 ,最后以上的问题都迎刃而解了,这个问题困扰我很久,特此记录一下。大佬们如果遇到以上问题,希望我这个文章能有所帮助,最后总结一下问题:
- 使用 vite-plugin-cdn-import 引入cdn外链
- 使用 vite-plugin-external 忽略cdn外链,内部自动配置rollup配置。
兜兜转转最后就用了一个插件就解决了以上所有问题,😭!
更多推荐
所有评论(0)