Vue/Nuxt项目webpack require存在的图片报Cannot find module错误如何解决
我在v-img组件中require已知存在的图片文件时遇到了webpack报错,相关代码如下:
imgSrcFancy (imgsize) { try { // 生产环境下除非未指定imgsize,否则使用.imgs目录下的缩略图而非原图 // if (imgsize === '' || process.env.NODE_ENV === 'development') { if (imgsize === '') { // 测试用临时强制始终使用.imgs目录 console.log('回退加载全分辨率图片') return require(`~/content${this.dirp}/${this.src}`) } else { // 生产环境且imgsize非空 const path = require('path') const ext = path.extname(this.src) const name = path.basename(this.src, ext) const loadstring = `~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}` console.log('从' + loadstring + '加载缩略图') return require(`~/content${this.dirp}/.imgs/${name}_${imgsize}${ext}`) } } catch (error) { console.log('查找图片失败:' + this.src) console.log(error) return null }
背景说明
我有一个使用nuxt-content搭建的博客,项目文件结构为:所有文章的图片和对应.md文件都存放在/content/posts目录下每个文章专属的文件夹中。最初版本的v-img组件可以正常require加载这些图片。
已上线的站点加载速度很慢,因此我编写了一个Python程序生成图片的缩小版本,全部存放在每个文章目录下的.imgs子文件夹中,结构如下:
- content/ - posts/ - post-slug-one/ - index.md - my_image1.jpg ... - .imgs/ - my_image1_large.jpg - my_image1_tn.jpg ...
该Python程序在Netlify构建环节执行,构建命令为python3 ./gen_tn.py && nuxt build && nuxt generate,该流程运行正常。
为避免占用本地磁盘空间,我原本通过NODE_ENV判断,开发环境直接加载全尺寸原图,该逻辑也运行正常,不过为了测试我临时禁用了该判断。
我在本地生成了缩略图用于测试,但执行到return require(~/content${this.dirp}/.imgs/${name}_${imgsize}${ext})这一行时抛出异常:
Error: Cannot find module './content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg' at webpackContextResolve (content.*$:752) at webpackContext (content.*$:747) at VueComponent.imgSrcFancy (VImg.vue:59) at Proxy.render (VImg.vue?ad21:7) at VueComponent.Vue._render (vue.runtime.esm.js:3548) at VueComponent.updateComponent (vue.runtime.esm.js:4055) at Watcher.get (vue.runtime.esm.js:4479) at Watcher.run (vue.runtime.esm.js:4554) at flushSchedulerQueue (vue.runtime.esm.js:4310) at Array.<anonymous> (vue.runtime.esm.js:1980)
但该文件实际存在,本地执行ls命令可正常输出路径:
MBPro:bst-blog$ ls content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg content/posts/sept-2021-photos-things/.imgs/pos_DSC01274_large.jpg
我甚至尝试硬编码图片尺寸,还是无法解决问题:
return require(`~/content${this.dirp}/.imgs/${name}_large${ext}`)
请问我哪里操作有误?该如何修复这个问题?
问题原因
这个问题是两个常见的webpack/nuxt配置特性共同导致的:
- Nuxt和webpack默认会忽略名称以
.开头的隐藏目录/文件,你的缩略图存放目录.imgs是隐藏目录,构建阶段webpack扫描静态资源时默认不会把该目录下的文件纳入处理范围,因此动态require时找不到对应模块。 - webpack的动态require机制需要明确的上下文范围来预收集资源,你直接用别名拼接完全动态的路径时,webpack无法提前识别需要加载的文件范围,也会导致加载失败。
修复步骤
方案一(推荐,改动最小)
将缩略图存放目录.imgs改名为不带点开头的名称(比如imgs),同时同步代码中的路径拼接逻辑即可。绝大多数构建工具默认都会过滤隐藏目录,改名可以直接规避这个问题。
方案二(保留.imgs目录)
如果必须保留.imgs的命名,按以下两步调整配置和代码:
- 修改
nuxt.config.js的content配置项,添加忽略规则排除对.imgs目录的过滤:
export default { // 其他配置 content: { // 只忽略名称以.开头且不是.imgs的文件/目录 ignore: [/^\.(?!imgs)/] }, build: { extend(config) { // 让webpack处理content目录下所有图片资源,包括隐藏目录内的 config.module.rules.push({ test: /\.(png|jpe?g|gif|webp)$/i, include: path.resolve(__dirname, 'content'), type: 'asset/resource' }) } } }
- 调整组件内require的写法,用
require.context给webpack明确的资源上下文:
// 在组件script顶部提前创建content目录的资源上下文,匹配所有图片后缀 const contentImgContext = require.context('~/content', true, /\.(png|jpe?g|gif|webp)$/i) // 原有方法内替换require逻辑 return contentImgContext(`./${this.dirp}/.imgs/${name}_${imgsize}${ext}`)
内容的提问来源于stack exchange,提问作者Brians Spare Time

