[Vue Router warn]: Component “default“ in record with path “/xx“ is a function that does not return

2023-05-16

[debug日记]

[Vue Router warn]: Component “default” in record with path “/xxx” is a function that does not return a Promise. If you were passing a functional component, make sure to add a “displayName” to the component. This will break in production if not fixed.

【方案一】

一种可能的解决方法是更改你的导入组件的路径。
当使用vite时,使用了一款插件dynamic-import-vars进行动态导入有只能使用相对路径的要求。

这些限制的中文翻译如下:


限制

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

function importModule(path) {
  // 鬼知道这里会导入什么?
  return import(path);
}

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

导入必须以 ./ 或者 ../开头

所有导入(import)必须使用相对被导入文件的路径。导入**允许以一个变量开头、使用绝对路径**,或者裸导入

// 不允许
import(bar);
import(`${bar}.js`);
import(`/foo/${bar}.js`);
import(`some-library/${bar}.js`);

导入必须带有一个文件扩展名

一个文件夹可能包含了你不想导入的东西。 所以我们要求在静态部分的导入以一个文件扩展名来结尾。

// 不允许
import(`./foo/${bar}`);
// 允许
import(`./foo/${bar}.js`);

导入你自己的目录时必须指定一个文件名字符串模板

当你导入你的目录,你可能最终会得到你不想导入的文件,包括你自己的模块,基于这个原因要求指定一个文件名字符串模板

// 不允许
import(`./${foo}.js`);
// 允许
import(`./module-${foo}.js`);

因此,虽然你在vite配置文件vite.config.ts(或js)中配置了defineConfig中的resolve.alias字段以指定了别名,但是由于插件只允许使用相对路径,因此导致报错。
因此改成以./或者以../开头的相对路径就好。

【方案二】

可以给vue-routercomponent 字段返回一个 Promise将的组件作为value传入resolve。
请返照以下思路:

{path:..., ..., component:() =>  Promise.resolve(your_component)}

实际上遇到这种情况时更可能是在使用一个函数导入一个异步组件,比如这样:

import { defineAsyncComponent } from "vue" 

const AsyncComp = defineAsyncComponent(() =>
  new Promise((resolve, reject) => {
    resolve(...)
  })
)

其中解决函数中可以直接指定一个描述VUE组件的对象。也可以导入,即:

const AsyncComp = defineAsyncComponent(() => import("./components/LoginPopup.vue"))

可以打开vue router源码的类型声明文件相关部分内容:
在这里插入图片描述

这里默认给出的为defineAsyncComponent第一个参数loader,就是VUE文件的路径。更详细的请自行看这部分源码了解。

function defineAsyncComponent(source) {
    if (shared.isFunction(source)) {
        source = { loader: source };
    }
    const { 
      loader, 
      loadingComponent, 
      errorComponent, 
      delay = 200, timeout, // undefined = never times out
      suspensible = true, 
      onError: userOnError 
    } = source;
    
    let pendingRequest = null;
    let resolvedComp;
    let retries = 0;
    const retry = () => {
        retries++;
        pendingRequest = null;
        return load();
    };
    const load = () => {
        let thisRequest;
        return (pendingRequest ||
            (thisRequest = pendingRequest =
                loader()
                    .catch(err => {
                      err = err instanceof Error ? err : new Error(String(err));
                      if (userOnError) {
                        return new Promise((resolve, reject) => {
                          const userRetry = () => resolve(retry());
                          const userFail = () => reject(err);
                          userOnError(err, userRetry, userFail, retries + 1);
                        });
                      }
                      else {
                        throw err;
                      }
                  })
                    // !!! 当 Promise 为resolve 的时候,
                    .then((comp) => { 
                      if (thisRequest !== pendingRequest && pendingRequest) {
                        return pendingRequest;
                      }
                      if (!comp) {
                        warn(`Async component loader resolved to undefined. ` +
                            `If you are using retry(), make sure to return its return value.`);
                      }
                      // interop module default
                      if (comp &&
                        (comp.__esModule || comp[Symbol.toStringTag] === 'Module')) {
                        comp = comp.default;
                      }
                      if (comp && !shared.isObject(comp) && !shared.isFunction(comp)) {
                        throw new Error(`Invalid async component load result: ${comp}`);
                      }
                      resolvedComp = comp; 
                      return comp;
                  })));
    };
    return defineComponent({
        name: 'AsyncComponentWrapper',
        __asyncLoader: load,
        get __asyncResolved() {
            return resolvedComp;
        },
        setup() {
            const instance = currentInstance;
            // already resolved
            if (resolvedComp) {
                return () => createInnerComp(resolvedComp, instance);
            }
            const onError = (err) => {
                pendingRequest = null;
                handleError(err, instance, 13 /* ASYNC_COMPONENT_LOADER */, !errorComponent /* do not throw in dev if user provided error component */);
            };
            // suspense-controlled or SSR.
            if ((suspensible && instance.suspense) ||
                (isInSSRComponentSetup)) {
                return load()
                    .then(comp => {
                    return () => createInnerComp(comp, instance);
                })
                    .catch(err => {
                    onError(err);
                    return () => errorComponent
                        ? createVNode(errorComponent, {
                            error: err
                        })
                        : null;
                });
            }
            const loaded = reactivity.ref(false);
            const error = reactivity.ref();
            const delayed = reactivity.ref(!!delay);
            if (delay) {
                setTimeout(() => {
                    delayed.value = false;
                }, delay);
            }
            if (timeout != null) {
                setTimeout(() => {
                    if (!loaded.value && !error.value) {
                        const err = new Error(`Async component timed out after ${timeout}ms.`);
                        onError(err);
                        error.value = err;
                    }
                }, timeout);
            }
            load()
                .then(() => {
                loaded.value = true;
                if (instance.parent && isKeepAlive(instance.parent.vnode)) {
                    // parent is keep-alive, force update so the loaded component's
                    // name is taken into account
                    queueJob(instance.parent.update);
                }
            })
                .catch(err => {
                onError(err);
                error.value = err;
            });
            return () => {
                if (loaded.value && resolvedComp) {
                    return createInnerComp(resolvedComp, instance);
                }
                else if (error.value && errorComponent) {
                    return createVNode(errorComponent, {
                        error: error.value
                    });
                }
                else if (loadingComponent && !delayed.value) {
                    return createVNode(loadingComponent);
                }
            };
        }
    });
}

附:标准的JavaScript动态导入是不要求相对路径的:

动态导入-摘录自MDN

标准导入语法是静态的,并且总是会在加载时评估导入模块中的所有代码。在您希望有条件地或按需加载模块的情况下,您可以改用动态导入。以下是您可能需要使用动态导入的一些原因:

  • 静态导入会显着减慢代码的加载速度,并且您需要正在导入的代码的可能性很小,或者直到以后才需要它。
  • 静态导入会显着增加程序的内存使用量,并且您需要导入的代码的可能性很小。
  • 当您导入的模块在加载时不存在时
  • 当需要动态构造导入说明符字符串时。(静态导入仅支持静态说明符。)
  • 当导入的模块有副作用时,除非某些条件为真,否则您不想要这些副作用。(建议不要在模块中产生任何副作用,但有时您无法在模块依赖项中控制这一点。)

仅在必要时使用动态导入。静态形式更适合加载初始依赖项,并且可以更容易地从静态分析工具和tree shaking中受益。

要动态导入模块,import可以将关键字作为函数调用。以这种方式使用时,它会返回一个承诺。

import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });

复制到剪贴板

这种形式也支持await关键字。

let module = await import('/modules/my-module.js');
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[Vue Router warn]: Component “default“ in record with path “/xx“ is a function that does not return 的相关文章

  • 为什么枚举上的开关需要默认值?

    通常 switch 语句中不需要 default 但是 在以下情况下 只有当我取消注释默认语句时 代码才能成功编译 有人能解释一下为什么吗 public enum XYZ A B public static String testSwitc
  • 如何将 cmd python 从 anaconda 更改为默认 python?

    windows powershell 或 cmd 使用 anaconda python 而不是默认的 windows 安装如何让他们使用默认的Python安装 我的操作系统是Windows 8 1蟒蛇3 6蟒蛇蟒蛇3 6 在系统属性中设置默
  • 以编程方式更改无线路由器设置 - Netgear 理想的选择

    是否可以使用 C 以编程方式更改 Netgear 无线路由器上的设置 我有经常更改的设置 我想创建自己的界面来进行这些更改 目前 我导航到管理网页 10 0 0 1 它提示我输入用户名和密码 身份验证后 我可以使用 Web 界面更改路由器的
  • 在 C++ 中设置默认浮点打印精度

    我想在比较过程中控制双精度数的精度 然后使用 C 恢复到默认精度 我打算使用setPrecision 设置精度 那么将精度设置回默认值的语法 如果有 是什么 我正在做这样的事情 std setPrecision math log10 m F
  • lumen:全新安装时找不到 App\Http\Controllers\Controller 类

    我正在与一个全新安装Lumen 构建 Web API 的大部分内容都可以工作 但是当我尝试使用路由器指向一个类时 我收到此错误 Fatal error Class App Http Controllers Controller not fo
  • 主干路由器 + RewriteRule 不触发带有“/”的路由

    我将所有链接转换为example com action to example com index html action然后由我的主干路由器解析 然而 我的新页面 signup inviteAuthHash eg signup 9d519a
  • 任意多个节点的贝尔曼-福特距离向量算法

    我正在尝试为模拟路由器的类编写一个程序 到目前为止我已经设置了基础知识 路由器 可以通过模拟服务器向连接到该服务器的其他 路由器 发送和接收数据包 每个数据包仅包含该路由器的距离向量 当路由器接收到数据包时 它应该使用贝尔曼 福特算法相应地
  • React Router - 刷新后保持在同一页面

    我正在学习反应 我有一个包含 4 个子页面的页面 我使用 React Router 来浏览这些页面 除了重新加载页面之外 一切正常 当我从页面 主页 转到 关于 或其他页面时 这是可以的 但是当我刷新页面时 它会再次渲染页面 关于 一秒钟
  • 强制 R 不使用指数表示法(例如 e+10)?

    我可以强制 R 使用常规数字而不是使用e 10 类似符号 我有 1 810032e 09 and 4 在同一向量内并希望看到 1810032000 and 4 我正在为老式程序创建输出 我必须使用编写一个文本文件cat 到目前为止效果很好
  • 覆盖 Spring 表单错误消息

    在 Spring 中如何覆盖默认表单错误消息 我正在使用一个Validator和一个属性文件来添加我自己的错误消息 但是 例如 如何覆盖因转换 编码错误而打印的消息 它们似乎是自动生成的 我认为对用户没有帮助 Failed to conve
  • Android:更改默认家庭应用程序

    对于某些特定要求 我需要更改 Android 默认主页应用程序 使用我的自定义主页应用程序 我的应用程序内的一个设置 将切换默认主页 我的应用程序或以前的主页 我不希望用户进行非常复杂的 Android 设置 任何人都可以帮我解决一下它在哪
  • Objective-C:标量属性默认为原子?

    一位朋友告诉我 标量属性 BOOL NSInteger 等 的 property 默认值是非原子的 IE property BOOL followVenmo 默认为 property nonatomic BOOL followVenmo 但
  • 如何为成员使用非默认构造函数?

    我有两节课 class a public a int i class b public b Gives me an error here because it tries to find constructor a a a aInstanc
  • 更改 Firefox 拼写检查默认语言

    Firefox 开始相信我的默认拼写检查语言应该是西班牙语 我的全球偏好选择了英语 首选项 gt 内容 gt 语言 gt 英语 en 我可以通过以下方式逐页重置拼写检查器语言 右键单击 gt 语言 gt 英语 美国 但是 对于新打开的页面或
  • 如何以编程方式显示“清除默认值”?

    现在我正在开发一个家庭启动器应用程序 我想清除默认家庭启动器的默认设置 例如 三星主页 即 我想展示Settings gt Applications gt Manage Application gt Samsung Home gt clea
  • 如何以编程方式从设置中设置默认启动器?

    我想将我的启动器设置为默认启动器 我的代码对很多人来说都可以正常工作 但在乐视设备上却无法正常工作 因为它提供了从默认应用程序设置中设置默认启动器的功能 运行此代码时 它会在默认启动器上移动 但仅在乐视设备中不显示启动器选择器弹出窗口 如何
  • Angular2 条件路由

    这可能是一个基本问题 但是在 Angular2 中是否有任何方法可以进行条件路由 或者 有人会在路由器之外这样做吗 我知道 ui router 有一定的能力做到这一点 但我在 Angular2s 路由器中没有看到类似的东西 如上所述 角路线
  • 调用过程默认值而不将值绑定到 Jdbc 中的参数

    我正在尝试打电话PL SQL为其某些参数定义了默认值的过程 我正在这样做使用CallableStatement in JDBC 该过程有大量已定义默认值的参数 我不想在 Java 代码中显式设置默认值 这样做会使维护代码变得更加困难 如果
  • 强制 telnet 客户端进入字符模式

    我有一个应用程序 我接受来自 telnet 客户端的套接字连接 并建立一个简单的键盘驱动的字符 GUI telnet 客户端 至少在 Linux 上 默认为一次一行模式 所以我总是必须这样做 mode char手动 浏览相关 RFC 表明
  • 使用 Dragstart PreventDefault 禁用浏览器默认图像拖动,但它也禁用我的拖动事件

    我尝试阻止浏览器默认图像在dragstart中拖动 但不知何故它也禁用了drag和dragend事件 无论如何 我可以禁用浏览器默认图像拖动 但它仍然会运行拖动和拖动结束事件 或者唯一的选择是使用背景图像 我不想这样做 因为我需要因此更改很

随机推荐