如何在Next.js项目中编译public目录下的TypeScript文件
问题:Next.js项目中public目录下TypeScript文件编译后浏览器报错
exports is not defined 场景与报错
现有正常运行的Next.js TypeScript项目,计划在public目录下开发小型游戏,目录结构如下:
- rootfolder/pages/game.tsx
- rootfolder/public/game/app.ts
执行tsc public/game/app.ts完成编译后,浏览器加载页面时出现报错:
Unhandled Runtime Error
ReferenceError: exports is not defined
现有代码如下:
game.tsx
import Head from 'next/head'; import Script from 'next/script'; export default function Game() { return ( <> <Head> <title>My Game</title> </Head> <Script type='module' src='game/app.js' /> <div className='h-[100vh] bg-gray-600 flex justify-center items-center'> <div className='game-container scale-125'> <canvas className='game-canvas border-2 border-gray-300' width='700px' height='400px' /> </div> </div> </> ); }
app.ts
console.log('hi'); export default {};
编译后的app.js
"use strict"; exports.__esModule = true; console.log('hi'); exports["default"] = {};
全局tsconfig.json
{ "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": false, "esModuleInterop": true, "noUnusedLocals": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "baseUrl": ".", "paths": { "@/*": ["./*"] } }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", "public/game/app.js", "public/game/app.ts" ], "exclude": ["node_modules"] }
原因分析
报错核心在于:浏览器通过type='module'加载脚本时仅支持ES模块语法,但直接用全局tsconfig编译public/game/app.ts时,生成的JS代码采用了CommonJS的exports语法,导致浏览器无法识别。
全局tsconfig中配置的module: "esnext"因Next.js自身构建逻辑,单独执行tsc命令时并未生效,最终编译产物仍为CommonJS格式。
解决方案
1. 为游戏代码创建独立TypeScript配置
在项目根目录新建tsconfig.game.json,专门针对public下的游戏TS文件配置ES模块编译规则:
{ "compilerOptions": { "target": "ES6", "module": "ESNext", "lib": ["dom", "esnext"], "strict": true, "esModuleInterop": true, "outDir": "./public/game", "rootDir": "./public/game" }, "include": ["public/game/**/*.ts"], "exclude": ["node_modules"] }
2. 修改编译命令
使用新配置文件编译游戏代码,替换原有的tsc public/game/app.ts:
tsc --project tsconfig.game.json
编译后生成的app.js会采用ES模块语法,不再出现exports:
console.log('hi'); export default {};
3. (可选)简化编译流程
在package.json的scripts中添加游戏编译命令,方便后续使用:
{ "scripts": { "build:game": "tsc --project tsconfig.game.json" } }
之后执行npm run build:game即可快速完成游戏代码编译。
4. 验证
重新编译后,浏览器加载页面时不再报错,控制台可正常输出hi。
内容的提问来源于stack exchange,提问作者Michael Schulz
相关产品推荐
相关产品推荐

