解决 pdf.mjs 因 MIME 类型错误导致的模块加载失败问题
Mozilla PDF.js V4 开始,它官方分发确实只提供了 ESM 模块(.mjs),没有以前的 pdf.js、pdf.worker.js UMD 版本了。
这个问题本质上是 浏览器要求以 application/javascript
MIME 类型加载 ES Module,而你引入的 pdf.mjs
文件服务器返回的 Content-Type 不是标准的 JS MIME(通常是 text/html
或者 text/plain
),所以会报:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html"
先介绍一下.mjs文件
什么是 .mjs 文件?
.mjs(Module JavaScript)是 ECMAScript 模块的专用文件扩展名,用于明确标识 JavaScript 模块文件。这是 ES6 模块系统的标准扩展名。
与普通 .js 文件的主要区别
特性 | .mjs 文件 | 传统 .js 文件 |
---|---|---|
模块类型 | ES6 模块 | 传统脚本或 CommonJS 模块 |
严格模式 | 默认启用 | 需要手动启用 |
顶层 this | undefined | 指向全局对象 |
导入/导出 | 支持 import/export | 需要特定环境支持 |
文件识别 | 明确标识为模块 | 需要解析内容判断 |
.mjs 文件的核心特性
1. 明确的模块标识
// math.mjs
export const add = (a, b) => a + b;
export const multiply = (a, b) => a * b;// 默认导出
export default function calculator() {console.log('Calculator module loaded');
}
2. 导入语法
// app.mjs
import calculator, { add, multiply } from './math.mjs';console.log(add(2, 3)); // 输出: 5
console.log(multiply(2, 3)); // 输出: 6
calculator(); // 输出: Calculator module loaded
3. 动态导入
// 动态导入示例
const loadModule = async () => {const module = await import('./dynamic-module.mjs');module.doSomething();
};
为什么使用 .mjs 扩展名?
优势:
- 明确性:一眼就能识别出是 ES6 模块
- 兼容性:避免与 CommonJS 模块混淆
- 工具支持:构建工具和运行时能够正确识别模块类型
- 服务器配置:便于正确设置 MIME 类型
环境支持
支持的运行时:
- Node.js (v12+ 完全支持)
- 现代浏览器 (Chrome、Firefox、Safari、Edge)
- Deno (原生支持)
- Bun (原生支持)
Node.js 中的使用:
// package.json 配置
{"type": "module", // 或者使用 .mjs 扩展名"scripts": {"start": "node src/index.mjs"}
}
回归正题
常见解决方案:
1. 确认服务器返回的 MIME 类型
在服务端配置里,确保 .mjs
文件返回:
Content-Type: application/javascript
- Nginx 配置:
http {types {application/javascript mjs;}
}
- Apache 配置:
AddType application/javascript .mjs
2. 如果你不能改服务器配置
- 把
pdf.mjs
改名为.js
,然后在 HTML 中这样引入:
<script type="module" src="/path/to/pdf.js"></script>
因为大多数服务器对 .js
都会返回正确的 application/javascript
。
3. 使用构建工具打包
如果你项目里有 Webpack / Vite / Rollup,把 pdf.mjs
作为依赖打包进去,这样最终生成的都是标准 JS 文件,不会受 MIME 类型影响。
4. 确认引入方式
要用 ES Module 的方式加载:
<script type="module">import * as pdfjsLib from '/path/to/pdf.mjs';// ...
</script>
- 如果是 uniapp 下使用 npm i pdfjs-dist 安装的 pdfjs,引入方式如下:
import * as pdfjsLib from "pdfjs-dist";
import pdfjsWorker from "pdfjs-dist/build/pdf.worker?url";
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
- 如果是官网下载的zip包,引入方式如下:
import * as pdfjsLib from "@/static/pdf.mjs";const worker = new Worker(new URL("@/static/pdf.worker.mjs", import.meta.url), { type: "module" });
pdfjsLib.GlobalWorkerOptions.workerPort = worker;
由于我使用的是docker,直接用 cat 命令无法编辑mime.types文件(页也可以自行安装 vim 命令)。
这里介绍一下 docker cp 命令。
- 从宿主机复制文件到容器
docker cp ./hello.txt nginx_container:/hello.txt
- 从容器复制文件到宿主机:
docker cp nginx_container:/hello.txt ./hello.txt
- 修改后需要重启nginx
docker exec nginx_container nginx -s reload
验证
curl -I https://your-domain.com/file.mjs
返回
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 26 Aug 2025 10:51:28 GMT
Content-Type: application/javascript; charset=utf-8,gbk
Content-Length: 1887718
Connection: keep-alive
Last-Modified: Tue, 26 Aug 2025 03:14:02 GMT
ETag: "68ad267a-1ccde6"
Accept-Ranges: bytes
至此,访问pdfjs 正常了!😃