Next.js中使用Pino Transport报错:无法找到worker.js模块
问题背景
用create-next-app创建了TypeScript的Next.js项目,选用Pino作为日志库。不启用transport时运行正常,代码如下:
import pino from 'pino'; const logger = pino({ level: process.env.NEXT_PUBLIC_LOG_LEVEL, formatters: { level: (label) => { return { level: label.toUpperCase() }; }, bindings: (bindings) => { return { host: bindings.hostname }; }, }, }); export default logger;
但启用transport(已安装pino-pretty作为开发依赖)后,使用以下代码报错:
import pino from 'pino'; const logger1 = pino({ transport: { target: 'pino-pretty', }, }); logger1.info('hi'); export default logger1;
报错信息:
- error uncaughtException: Error: Cannot find module 'C:\starttwo-productionlot-frontend\.next\server\app\home\lib\worker.js' at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15) at Module._load (node:internal/modules/cjs/loader:920:27) at Function.executeUserEntryPoint [as runMain] (node:internal/main/worker_thread:164:24) at MessagePort.<anonymous> (node:internal/main/worker_thread:164:24) at [nodejs.internal.kHybridDispatch] (node:internal/event_target:737:20) at exports.emitMessage (node:internal/per_context/messageport:23:28) { digest: undefined } - error node_modules\thread-stream\index.js (195:31) @ Worker.onWorkerExit - error uncaughtException: Error: the worker thread exited at Worker.onWorkerExit (webpack-internal:///(sc_server)/./node_modules/thread-stream/index.js:163:34) at Worker.emit (node:events:513:28) at [kOnExit] (node:internal/worker:289:10) at Worker.<computed>.onexit (node:internal/worker:209:20) at Worker.callbackTrampoline (node:internal/async_hooks:130:17) { digest: undefined }
使用pino/file也出现相同错误(疑问:是否需要安装pino/file?):
import pino from 'pino'; const transport = pino.transport({ target: 'pino/file', options: { destination: '/path/to/file' } }) pino(transport)
仅在服务端page.tsx(无"use client"指令)中使用日志器,尝试Pino官方示例代码仍报错:my-transport.tsx代码:
import { createWriteStream } from 'fs' export default () => { return createWriteStream('../app/app.log')// /app/app.log -- 日志文件位置 }
logger.tsx代码:
const pino = require('pino') const transport = pino.transport({ target: '/absolute/path/to/my-transport.mjs' }) export default pino(transport)
核心疑问:
- Next.js中使用pino.transport有何限制?
- 能否在客户端和服务端使用?
- 如何解决该错误并正常使用transport功能?
解答
1. Next.js中Pino Transport的核心限制
Pino Transport依赖Node.js的Worker Threads和动态模块加载,但Next.js的服务端打包机制(Webpack)会修改模块路径、重构打包后的文件结构,导致Pino无法正确定位到transport依赖的worker脚本,这就是你遇到Cannot find module 'worker.js'错误的根本原因。
另外,pino/file是Pino内置的transport,不需要额外安装,报错同样是Webpack打包破坏了其路径解析逻辑导致的。
2. 客户端与服务端的使用限制
- 服务端:可以使用,但需要规避Webpack打包对Pino Transport的影响;
- 客户端:完全不建议使用Pino Transport。Pino在客户端运行时会自动降级为极简模式,而Transport依赖Node.js专属API(如
fs文件系统、Worker Threads),浏览器环境根本不支持,强行使用会直接报错。
3. 解决方法
方法一:用Next.js实验性配置排除Pino相关包打包
在next.config.js中添加以下配置,将Pino相关包排除在服务端打包流程外,让Node.js直接加载原始模块,避免路径解析混乱:
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { serverComponentsExternalPackages: ['pino', 'pino-pretty', 'thread-stream'], }, } module.exports = nextConfig
之后你的transport代码就可以正常使用了:
import pino from 'pino'; const logger = pino({ transport: { target: 'pino-pretty', options: { colorize: true, }, }, }); export default logger;
方法二:手动传入transport实例(绕过Worker Threads)
如果不想用实验性配置,可以直接将transport实例作为参数传入Pino,避免自动创建Worker Threads:
import pino from 'pino'; import pinoPretty from 'pino-pretty'; const logger = pino( { level: process.env.NEXT_PUBLIC_LOG_LEVEL }, pinoPretty({ colorize: true }) ); export default logger;
这种方式直接把pino-pretty作为写入流传入,不依赖Worker Threads,彻底规避了路径解析问题。
方法三:生产环境文件输出配置
如果要写入日志文件,推荐先用方法一的外部包配置,再使用pino/file:
import pino from 'pino'; const logger = pino({ transport: { target: 'pino/file', options: { destination: './logs/app.log', mkdir: true, // 自动创建日志目录 }, }, }); export default logger;
额外注意事项
- 确保只在服务端代码中使用上述配置,客户端代码直接导入Pino即可(无需transport,客户端会自动降级处理);
- 开发环境用
pino-pretty美化输出,生产环境建议用pino/file或其他高效transport; - 使用TypeScript时,确保
pino和pino-pretty的类型定义已正确安装(通常安装包时会自动包含)。
内容的提问来源于stack exchange,提问作者user22177053

