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

前端 - 使用动态表达式动态引入文件编译后缺少模块信息?

高博涉
2023-06-17

好像内容有点太多了不方便阅读,总结一下:

  1. 项目信息:

    • RuoYi-Vue2 前后端分离版本
    • Vue 2.6.12
    • VueCLI 4x
    • Webpack 4x
    • Node v16.15.1
    • npm 8.11.0
    • 使用阿里镜像
  2. 项目使用 () => import(@/views/${view}) 的方式动态引入页面组件。
  3. 正常情况下 npm run build 项目可以正确分析并预载入 @/views 目录下所有Vue组件。
  4. 使用 npm run build --mode xxxx 指定非 development/production 的环境变量文件则无法正确分析和预载入 @/views 目录下Vue组件
  5. 无法正确预载入 @/views 目录的问题并不是稳定复现,可能换一台电脑就可以正确编译了。
  6. 没有配置 cache 功能,除了 compression-webpack-plugin 生成的 gzip 文件。

比较疑惑的是为什么没有指定环境变量文件直接使用 npm run build 编译项目(也就是默认使用 .env.production)可以正确编译,但是指定了其他环境变量文件则不会正确编译。

以下是原问题内容


按照 Webpack 文档中的信息 import() 中的表达式,使用以下方式动态引入 /views/ 目录下的所有文件。

// https://github.com/yangzongzhuan/RuoYi-Vue/blob/master/ruoyi-ui/src/store/modules/permission.js#L124
...
export const loadView = (view) => {
  if (process.env.NODE_ENV === 'development') {
    return (resolve) => require([`@/views/${view}`], resolve)
  } else {
    // 使用 import 实现生产环境的路由懒加载
    return () => import(`@/views/${view}`)
  }
}

正常使用 npm run build 是会正确分析预先加载所有的页面文件。

最近需要部署到一个新的生产环境中,所以创建并使用了一个新的 .env.production2 的环境变量文件来区分不同的环境,在编译时使用 npm run build --mode production2 来执行编译。

# .env.production2
VUE_APP_TITLE = 后台管理系统

BABEL_ENV = production

NODE_ENV = production

ENV = production

VUE_APP_BASE_API = /prod-api

但是编译时并不会正确预加载所有的页面文件,只会编译在静态路由表中的页面组件。并且提示:Cannot find module XXX。查看了一下 Jenkins 日志文件,发现有一个相关的警告信息:

warning  in ./src/store/modules/permission.js

Critical dependency: the request of a dependency is an expression

看起来是因为项目使用的是 webpack4 不支持动态 import 的缘故,但重新使用 npm run build 编译项目时又会正确预加载所有页面文件。

我在本地环境使用 npm run build --mode production2 编译项目时又可以成功预加载所有页面文件了,只不过在 Jenkins 中没法正确预加载。

有一些评论是说 node_modules 中的依赖项版本不同导致的,在本地删除 node_modules 目录后再使用 npm clean cache --force 清除缓存,重新 npm install。确实重新安装依赖后第一次编译时没法正确预加载了,但是我修改了一下环境变量,增加上 BABEL_ENV = production 的环境变量之后又可以成功完成编译了。
重新提交代码再使用 Jenkins 重复以上步骤编译项目时,却没办法正常预载加页面文件。但使用 npm run build 仍然可以正确预加载。

但我重新在自己本地就无论如何都没办法复现了。所以我就很迷惑。一下子没有了思绪。希望可以给一些方向。

相关Issues

  • 动态路由按需加载-Cannot find module · Issue #I4PZJF · 若依/RuoYi-Vue - Gitee.com
  • 修复版本差异导致的懒加载报错问题 · 6e14601 · 若依/RuoYi-Vue - Gitee.com
  • #如何实现路由的懒加载 常见问题 | RuoYi
  • import()拼接表达式报错 cannot find module - SegmentFault 思否

共有2个答案

程举
2023-06-17
  1. 从描述来看,我猜测是你走的太远,超过了 webpack 通常测试的覆盖范围,遇到了不能稳定重现的 bug。bug 是什么与该怎么解决,我暂时也没有头绪。
  2. 不过我记得动态加载需要配合 /* webpack-** */ 表达式,以便 weebpack 正确打包未明确引用的包,但是你的代码里我没看到。
  3. 因为有 dead code 的存在,其实环境变量可能影响到编译结果,但是看你的描述,更可能是有些代码被错误标记了。不确定该怎么解决,只能一步一步打断点调试,我觉得非常不经济。
  4. 我能想到的解决方案是升级 webpack 到 5,先试一下。
  5. 如果 Jenkins 升不了那就没办法。我其实一直很好奇,为啥非得上 Jenkins?小门小户的我,用 GitHub Actions、Vercel、OpenResty 自建系统从来没被限制过。
欧阳永宁
2023-06-17

依旧只是在环境变量文件中增加了 BABEL_ENV=production,指定为生产环境。


反反复复想找出稳定复现的场景。最后可以稳定复现场景为:

  • 环境变量文件配置的 VUE_APP_TITLE 为中文时就可以正确分析并打包页面文件。使用英文就没办法正确分析。

但显然问题并不是这里导致的,所以只能怀疑是缓存的缘故。但是反复删除 node_modules 并且使用 npm cache clean --force 清理缓存,仍可以稳定复现(搞得我有点怀疑人生)。

花了太久时间复现问题了,开发工期太紧张已经不适合在投入时间在这个上面了。中间也尝试过升级到 VueCLI 5 来快速升级到 Webpack 5,但是高版本的 npm 在使用 VueCLI 更新的时候会引发依赖树分析的版本冲突问题,如果不想改变 npm 版本的话暂时没办法解决。手动升级 Webpack5 或者迁移到 Vite 的成本显然会更高。

如果其他大佬有想法可以指导本菜��解决问题的大概方向。

 类似资料:
  • 问题内容: 我正在使用Browserify将大型Node.js应用程序编译为一个文件(使用选项和[以避免Express中的问题])。我有一些代码可根据目录中的可用内容动态加载模块: 我的应用程序中出现奇怪的错误,即从已编译文件的加载目录中加载了框架文字文件。我认为这是因为路径设置不正确,并且因为Browserify无法正确处理像这样动态加载。 除了制作静态文件之外,还有没有一种首选的方法可以动态地

  • 问题内容: 我正在尝试从其他目录动态导入模块。我正在从这个问题中得到答案。我在名为foo的目录中有一个名为bar的模块。主脚本将在foo的父目录中运行。 这是我到目前为止在测试脚本中拥有的代码(正在foo的父目录中运行) 和bar.py的代码 但是当我运行test.py时,出现此错误: 问题答案: 需要导入模块的路径名+文件名,您应该将源代码更改为以下代码之一:

  • 在传统桌面操作系统中,用户空间和内核空间是分开的,应用程序运行在用户空间,内核以及内核模块则运行于内核空间,其中内核模块可以动态加载与删除以扩展内核功能。dlmodule 则是 RT-Thread 下,在内核空间对外提供的动态模块加载机制的软件组件。在 RT-Thread v3.1.0 以前的版本中,这也称之为应用模块(Application Module),在 RT-Thread v3.1.0

  • 动态模块接口 结构体 struct   rt_dlmodule   动态模块控制块 更多...   类型定义 typedef void(*  rt_dlmodule_init_func_t) (struct rt_dlmodule *module)   动态模块初始化函数指针类型定义   typedef void(*  rt_dlmodule_cleanup_func_t) (struct rt_

  • 问题内容: 我有一台受信任的远程服务器,其中存储了许多自定义Python模块。我可以通过HTTP(例如,使用)作为文本/纯文本来获取它们,但是我无法将获取的模块代码保存到本地硬盘上。如何将代码作为完全可操作的Python模块(包括其全局变量和导入)导入? 我想我必须使用和模块功能的某种组合,但是我还无法使其工作。 问题答案: 看起来这应该可以解决问题:导入动态生成的模块 另外,按照ActiveSt

  • 16.6. 动态导入模块 好了,大道理谈够了。让我们谈谈动态倒入数据吧。 首先,让我们看一看正常的导入模块。 import module 语法查看搜索路径寻找已命名模块并以名字导入它们。你甚至于可以以这种方法,以逗号分割同时导入多个模块,本章代码前几行就是这样做的。 例 16.13. 同时导入多个模块 import sys, os, re, unittest 这里同时导入四个模块:sys (