Next.js开发npm包时如何读取项目根目录的中间件配置.ts文件
报错原因说明
你遇到的Cannot import a module outside a module报错本质是Next.js的模块沙箱限制,以及Node.js的ES Module/CommonJS互操作限制:node_modules下的包默认被禁止导入项目目录内的用户文件,避免打包时出现不可控的依赖。
可行解决方案
方案1:导出初始化函数让用户传入配置(最推荐)
无需主动读取用户配置文件,完全规避跨模块导入问题,对用户无额外配置要求:
- 你的npm包调整导出逻辑,暴露配置注册函数和相关依赖:
// ngn包入口文件 import type { Keyable, Middleware } from './types' // 全局存储运行时中间件配置 let runtimeMiddlewares: Keyable<Array<Middleware>> = {} export function defineNgnConfig(config: { middlewares: Keyable<Array<Middleware>> }) { runtimeMiddlewares = config.middlewares // 内部API处理逻辑直接读取该变量即可 } // 导出所有内置中间件、类型供用户直接调用 export * from './middlewares' export * from './types'
- 用户侧的配置文件写法调整为:
// 用户项目根目录下的ngn.config.ts import { defineNgnConfig, withSetCookie, decryptCookies, withRequest, withValidator, withIp, withThrottle } from 'ngn' // 支持用户导入自定义中间件 import customAuth from './src/middlewares/customAuth' export default defineNgnConfig({ middlewares: { "/": [ withRequest, withIp, withThrottle, decryptCookies, withSetCookie, withValidator, customAuth ] } })
- 仅需提示用户在Next.js的全局入口(如
app/layout.tsx、pages/_app.tsx)或next.config.js中导入一次该配置文件即可,所有模块解析都在用户项目的编译上下文内完成,不会出现导入报错。
方案2:运行时动态编译配置文件
如果确实需要你的包主动读取用户配置,可使用轻量编译工具在运行时编译配置文件,无需webpack:
// 包内部的配置加载逻辑 import { readFileSync } from 'fs' import { transform } from 'esbuild' import path from 'path' import { createRequire } from 'module' async function loadUserConfig() { // 定位用户项目根目录下的配置文件 const configPath = path.resolve(process.cwd(), 'ngn.config.ts') const configContent = readFileSync(configPath, 'utf-8') // 编译TS为可执行的CommonJS代码 const { code } = await transform(configContent, { loader: 'ts', format: 'cjs', tsconfigRaw: readFileSync(path.resolve(process.cwd(), 'tsconfig.json'), 'utf-8') }) // 执行代码获取导出的配置 const module = { exports: {} } const require = createRequire(import.meta.url) eval(code) return module.exports.default }
该方案需要注意将esbuild作为你的包的依赖项,同时兼容用户的TS配置。
webpack打包为单CommonJS文件的思路说明
该方案技术上可行,但需要用户额外配置Next.js的webpack规则,将配置文件设为单独的打包入口输出为CommonJS文件,上手成本更高,不推荐使用。
内容的提问来源于stack exchange,提问作者FaSh
相关产品推荐
相关产品推荐

