当前位置: 首页 > 知识库问答 >
问题:

javascript - Vue3将node_modules内能正常引入的插件包文件拷出来后引用为什么会报错?

席言
2024-07-29

在开发过程发现了一个问题,在vue3+vite+ts的项目中安装好avue插件后,在main.ts中将avue全局import,页面可正常使用无异常。 但是当我把node_modules中avue文件内容拷出来,放到项目其他的文件夹下,目录结构和文件都保持一致。然后在main.ts中import后,在预览页面时浏览器就会报出The requested module '/src/utils/avue/lib/avue.js' does not provide an export named 'default'的错误。

请问这是为什么?如何解决该错误?

main.ts 文件中引入avue:
image.png

node_modules中avue插件的文件结构:
image.png

将avue文件拷贝到其他文件夹下:
image.png

在main.ts引入拷贝后的avue:
image.png

浏览器报错信息:
image.png

共有3个答案

萧波峻
2024-07-29

这个包最后输出的模块用的 UMD,你只能使用 CommonJS 来导入,用 ESM 导入当然会报错了。

https://www.npmjs.com/package/@smallwei/avue?activeTab=code

要是原作者不提供 ESM 版本的输出的话,你就只能按 @陟上晴明 提到的方式引入了。


多展开说一点,你要问为啥在 node_modules 底下的时候你能用 ESM 来导入一个 CommonJS 模块而不会报错,那是因为用 Vite/Rollup/ESBuild/Webpack 这类的构建工具存在,它会把 CommonJS “转换”成 ESM 的形式,最后实际导入的是这个 ESM 的模块。

以 Vite 为例,主要分为两个步骤:

  1. 检测到你导入的是一个形如 import foo from 'foo' 这样的“裸模块”(也就是引用路径开头既不是绝对路径也不是相对路径的),会被视为要从 node_modules 里找。
  2. 依赖预构建,把所有 CommonJS 导出都转换为 ESM 的形式。
https://vitejs.dev/guide/features.html#npm-dependency-resolvi...
https://vitejs.dev/guide/dep-pre-bundling#the-why

这就是为啥你能“混着用”的原因。但注意,这个环节只会针对裸模块(通常来说就是指包管理器里的第三方模块)的代码,不会针对你的项目代码,所以当你把它从 node_modules 拷贝到自己的源码目录下,就不管用了。因为一个正常的项目源代码里,是不可能也不应该同时出现 CommonJS 和 ESM 两种模块方案的


最后,我不知道为啥题主非得要把代码从 node_modules 拷贝出来。如果非要这么整的话,其实除了一开始 @陟上晴明 提到的方式,还有其他思路可以选择。

比如在 package.json 使用本地文件引用路径指向你的拷贝出来后的目录(目录里也需要一个 package.json),然后开发时继续使用裸模块的形式而非具体路径,这样既使用的是本地代码、同时又能触发 Vite 的依赖预构建。

再比如既然 Vite 本身不支持转换源码里的 CommonJS,那就加 vite-plugin-commonjs 之类的插件,然后代码里用 require() 导入。

但我都不推荐,因为坑太多了。我估计题主能在这里提问,本身对这种模块化方案的差异理解就不会是很深刻。如果题主是打工人的话,与其浪费时间在这种 Corner-Case 上、最后还不一定能有结果的问题上,不如尽快把工作做完。

刁茂才
2024-07-29

改用 script:src 引入的方式,引入 avue
�� examples/element-ui/card/index.html · smallwei/Avue - Gitee.com

相关链接

ESM模块打包,cdn方式引入 · Issue #I9SHUP · smallwei/Avue - Gitee.com

凌伟泽
2024-07-29

问题分析

当你在Vue3+Vite+TypeScript项目中遇到这个问题时,主要的原因是模块解析和打包方式的不同。在node_modules中的包通常是按照npm或yarn等包管理器的规则来组织和打包的,这些包可能包含了ES模块、CommonJS模块或其他格式的JavaScript代码,同时它们也可能被设计为支持多种打包工具(如Webpack、Vite等)。

当你将avue包从node_modules中直接拷贝到项目源代码目录中时,你实际上改变了模块的路径和可能的解析方式。Vite(或任何其他现代前端构建工具)会根据其配置和模块系统的规范来解析和打包模块。如果avue包内部使用了特定的打包策略或模块导出方式(如使用默认导出export default,或者命名导出export { ... }),并且这些导出方式在拷贝后没有得到正确的处理或配置,就可能导致导入时出现错误。

解决方案

  1. 不要手动拷贝
    最直接的解决方案是不要手动从node_modules中拷贝包到你的项目中。这样做既容易出错,也难以维护。使用npm或yarn等包管理工具来管理依赖项是更可靠和高效的方式。
  2. 检查导出方式
    如果确实需要修改或访问包内部的某些文件(尽管不推荐),请确保你理解并正确处理了模块的导出方式。检查avue包的源代码,确认其是如何导出模块的,然后在你的项目中以相应的方式导入它们。
  3. 修改Vite配置
    如果avue包在node_modules中正常工作,但在你的自定义目录中出现问题,可能需要检查Vite的配置文件(如vite.config.ts),看看是否有与模块解析相关的设置需要调整。
  4. 使用别名(Alias)
    如果由于某些原因你需要将avue放在自定义目录中,可以在Vite配置中添加别名来指向这个目录,这样你就可以像使用node_modules中的包一样来使用它了。

    // vite.config.ts
    import { defineConfig } from 'vite';
    import vue from '@vitejs/plugin-vue';
    
    export default defineConfig({
      plugins: [vue()],
      resolve: {
        alias: {
          'avue': '/path/to/your/custom/avue/directory'
        }
      }
    });
  5. 考虑使用子模块
    如果avue包提供了子模块或允许按需加载,你可以考虑只引入你需要的部分,而不是整个包。这可以通过npm或yarn的依赖管理功能来实现,而无需手动复制文件。

总之,最好的做法是遵循标准的依赖管理方式,使用npm或yarn来管理你的项目依赖。如果你需要修改或扩展某个库,考虑贡献回原项目或创建一个分支,而不是将库文件直接复制到你的项目中。

 类似资料: