您的位置:首页 > 文旅 > 美景 > The above dynamic import cannot be analyzed by Vite.

The above dynamic import cannot be analyzed by Vite.

2024/7/3 17:25:06 来源:https://blog.csdn.net/weixin_45687201/article/details/140058588  浏览:    关键词:The above dynamic import cannot be analyzed by Vite.

The above dynamic import cannot be analyzed by Vite.

🙋🏼‍♂️ 问题现象

今天写一个项目菜单管理,遇到一个警告信息:

# vscode 终端输出:
10:00:36 [vite] warning:
D:/my-project/src/router/dynamicRouter.ts
10 |      const routeRecord = {
11 |        ...rest,
12 |        component: () => import(`${component}`),|                                ^^^^^^^^^^^^^^
13 |        children: []
14 |        // Initialize children here
The above dynamic import cannot be analyzed by Vite.
See https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations for supported dynamic import formats. If this is intended to be left as-is, you can use the /* @vite-ignore */ comment inside the import() call to suppress this warning.Plugin: vite:import-analysisFile: D:/my-project/src/router/dynamicRouter.ts

🔎 寻找解决方案

🧩 @rollup/plugin-dynamic-import-vars

根据错误信息,查阅了https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations资料。

他是一个rollup插件,支持动态导入中的变量。

🛠️ 安装

npm install @rollup/plugin-dynamic-import-vars --save-dev

✍️ 使用

// vite.config.ts
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars'
export default {plugins: [dynamicImportVars({// options})]
}

📓 选项

include
// 要包含在此插件中的文件(默认全部)。
Type: String | Array[...String]
Default: []
exclude
// 要在此插件中排除的文件(默认为无)。
Type: String | Array[...String]
Default: []
errorWhenNoFilesFound
// 默认情况下,当没有找到目标文件时,插件不会抛出错误。将此选项设置为true将导致在遇到不存在的文件时抛出错误。
Type: Boolean
Default: false
warnOnError

⚠️ 重要:当设置为启用时,此选项将会生产出警告而不是错误
warnOnError true

// 默认情况下,插件在遇到错误退出构建过程时。如果将此选项设置为 true,它将引发警告,并使代码保持不变。
Type: Default: Booleanfalse

🕹️ 使用方式

当动态导入包含串联字符串时,字符串的变量将替换为 glob 模式。在构建过程中评估此 glob 模式,找到的任何文件都将添加到汇总包中。在运行时,将为完整的串联字符串返回正确的导入。

一些示例模式及其生成的 glob:

`./locales/${locale}.js` -> './locales/*.js'
`./${folder}/${name}.js` -> './*/*.js'
`./module-${name}.js` -> './module-*.js'
`./modules-${name}/index.js` -> './modules-*/index.js'
'./locales/' + locale + '.js' -> './locales/*.js'
'./locales/' + locale + foo + bar + '.js' -> './locales/*.js'
'./locales/' + `${locale}.js` -> './locales/*.js'
'./locales/' + `${foo + bar}.js` -> './locales/*.js'
'./locales/'.concat(locale, '.js') -> './locales/*.js'
'./'.concat(folder, '/').concat(name, '.js') -> './*/*.js'

代码如下所示:

function importLocale(locale) {return import(`./locales/${locale}.js`)
}

变成:

function __variableDynamicImportRuntime__(path) {switch (path) {case './locales/en-GB.js':return import('./locales/en-GB.js')case './locales/en-US.js':return import('./locales/en-US.js')case './locales/nl-NL.js':return import('./locales/nl-NL.js')default:return new Promise(function (resolve, reject) {queueMicrotask(reject.bind(null, new Error('Unknown variable dynamic import: ' + path)))})}
}function importLocale(locale) {return __variableDynamicImportRuntime__(`./locales/${locale}.js`)
}

🔰 导入断言

此插件将保持动态导入语句中的导入断言完好无损。

// Refer to rollup-plugin-import-css https://github.com/jleeson/rollup-plugin-import-css
function importLocale(sheet) {return import(`./styles/${sheet}.css`, { assert: { type: 'css' } })
}

这很重要,例如在处理 CSS 导入的 rollup-plugin-import-css 上下文中, 由于仍然有一个断言,它将把 CSS 导入解析为 CSSStyleSheet,类似于本机浏览器行为。

🙅‍♂️ 局限性

要知道要在 rollup bundle 中注入什么,我们必须能够对代码进行一些静态分析,并对可能的导入做出一些假设。例如,如果您只使用一个变量,理论上可以从整个文件系统中导入任何内容。

function importModule(path) {// who knows what will be imported here?return import(path)
}

为了帮助静态分析,并避免可能的乱用,我们仅限于以下几条规则:

➡️ 导入必须以 ./ 开头。

所有导入都必须相对于导入文件开始。导入不应以变量、绝对路径或裸导入开头:

// Not allowed
import(bar)
import(`${bar}.js`)
import(`/foo/${bar}.js`)
import(`some-library/${bar}.js`)

📁 必须指定文件名

如果你导入自己的目录,你最终可能会得到你不打算导入的文件,包括你自己的模块。因此,需要给出更具体的文件名模式:

// not allowed
import(`./${foo}.js`)
// allowed
import(`./module-${foo}.js`)

🌎 glob 只深入一层

生成 glob 时,字符串中的每个变量都会转换为每个目录深度最多一个星号的 glob。这样可以避免无意中将许多目录中的文件添加到导入中。*

在下面的示例中,这将生成而不是 。./foo//.js./foo/*/.js

import(`./foo/${x}${y}/${z}.js`)

🤔 方案是否可行?

结合上面的@rollup/plugin-dynamic-import-vars方案以及自身项目

🎲 处理问题评估

目录结构:

/my-project/
├── node_modules/
├── public/
├── src/
│   ├── router/
│   │   ├── dynamicData.json
│   │   └── dynamicRouter.ts
│   ├── layouts/
│   └── views/
├── ...
├── package.json
└── vite.config.ts

静态菜单数据:

[{"id": 1,"path": "/","component": "../layouts/default.vue","children": [{"id": 2,"path": "/","name": "home","mate": { "name": "首页", "icon": "Menu" },"component": "../views/Home/HomeIndex.vue"},{"id": 3,"path": "/photo","name": "photo","mate": { "name": "图片信息", "icon": "document" },"component": "../views/Photo/PhotoIndex.vue"},{"id": 4,"path": "/personal","name": "personal","inside": true,"mate": { "name": "用户中心", "icon": "user" },"component": "../views/PersonalCenter/IndexPage.vue"}]}
]

dynamicRouter.ts 主要代码段

const routeRecord: RouteRecordRaw = {...rest,component: () => import(`${component}`),children: [] // Initialize children here
};

根据以上代码,执行后会产生vite编译警告:

10:00:36 [vite] warning:
D:/my-project/src/router/dynamicRouter.ts
10 |      const routeRecord = {
11 |        ...rest,
12 |        component: () => import(`${component}`),|                                ^^^^^^^^^^^^^^
13 |        children: []
14 |        // Initialize children here
The above dynamic import cannot be analyzed by Vite.

经过实际验证:

  1. json../剔除,将.vue剔除后,大致代码:

    [{"id": 1,"path": "/","component": "layouts/default","children": [{"id": 2,"path": "/","name": "home","mate": { "name": "首页", "icon": "Menu" },"component": "views/Home/HomeIndex"}]}
    ]
    
  2. 修改引用方式

    // dynamicRouter.ts
    const routeRecord: RouteRecordRaw = {...rest,component: () => import(`./${component}.vue`),
    };
    

    这明显不行的,跟实际页面路径不匹配。

    在这里插入图片描述

📚️ 总结

  • 可以看到我们想要实现的是../**/*.vue文件引入,但是@rollup/plugin-dynamic-import-vars方案并不友好,他只允许使用./,即相对于导入文件来使用。

  • @rollup/plugin-dynamic-import-vars插件不支持动态计算的路径或其他形式的动态导入。

🧱 另辟蹊径

通过一开始的错误提示,或许不应该使用rollup插件,应该直接从vite插件入手。

正好vite有一款插件vite-plugin-dynamic-import

🧩 vite-plugin-dynamic-import

或许你会疑问,既然已经有了解决方案,为什么一开头还要讲@rollup/plugin-dynamic-import-vars呢?

其实vite-plugin-dynamic-import是兼容@rollup/plugin-dynamic-import-vars的限制./–>相对于导入文件使用。

📢 介绍

直击要害,vite插件能够为我们解决的问题:

  • 用不了别名

    // router.jsimport(`@/views/${variable}.js`)
    
  • 必须相对路径

    // router.jsimport(`/User/project-root/src/views/${variable}.js`)
    
  • 必须含文件尾缀

    // router.jsimport(`./views/${variable}`)
    

🛠️ 安装

npm i vite-plugin-dynamic-import -D

✍️ 使用

import dynamicImport from 'vite-plugin-dynamic-import'export default {plugins: [dynamicImport(/* options */)]
}

📓 选项

export interface Options {filter?: (id: string) => boolean | void/*** ```* 1. `true` - 尽量匹配所有可能场景, 功能更像 `webpack`* 链接 https://webpack.js.org/guides/dependency-management/#require-with-expression** 2. `false` - 功能更像rollup的 `@rollup/plugin-dynamic-import-vars`插件* 链接 https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#how-it-works** default true* ```*/loose?: boolean/*** 如果你想排除一些文件* 举俩🌰 `type.d.ts`, `interface.ts`*/onFiles?: (files: string[], id: string) => typeof files | void/*** 自定义 importee** e.g. - 在 importee 前面插入 `\/*@vite-ignore*\/` 绕过 Vite*/onResolve?: (rawImportee: string, id: string) => typeof rawImportee | void
}

🕹️ 实际操作

通过上面的介绍,业务代码可以调整为:

component: () => import(`../${component}.vue`)

当然,如果设置了别名

// vite.config.ts
resolve: {alias: {"@": resolve(__dirname, "./src")}
}

可以这么使用

component: () => import(`@/${component}.vue`)

以上就是实现动态加载路由的方案,如果你有更好的主意可以在评论区留言~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com