如何为Create React App创建的React TypeScript项目配置本地可运行脚本
我用Create React App创建了一个React TypeScript项目,想给项目加一个仅在本地运行的可执行脚本,这个脚本和React应用共用algorithm.ts这个TypeScript模块,期望实现:
npm start→ 运行React应用npm run myscript→ 运行脚本
我试了多种方案,最近的尝试是把脚本做成Node.js脚本,每次运行前先将algorithm.ts编译为JS,但运行时报错:
$ npm run myscript
tsc src/algorithm.ts && node src/myscript.js
file:///
/src/algorithm.js:2
exports.__esModule = true;
^ReferenceError: exports is not defined
at file:////src/algorithm.js:2:1
at ModuleJob.run (internal/modules/esm/module_job.js:146:23)
at async Loader.import (internal/modules/esm/loader.js:165:24)
at async Object.loadESM (internal/process/esm_loader.js:68:5)
这种方案还得让脚本用JS而非TS,虽非首选但可接受。相关文件内容如下:
algorithm.ts:
import { blabla } from "blabla"; ... export const function1 = ... export const function2 = ... ...
ReactComponent.tsx:
import { function1, function2 } from "./algorithm"; ...
myscript.js:
import * as algorithm from "algorithm.js" ...
package.json:
... "type": "module", "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "myscript": "tsc src/algorithm.ts && node src/myscript.js" }, ...
tsconfig.json:
{ "compilerOptions": { "target": "es5", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": [ "src" ] }
核心问题
报错原因是单独用tsc编译单个文件时,直接套用了React项目的TS配置:module: esnext加上package.json的"type": "module",但编译输出的代码混用了CommonJS(exports)和ESM语法,导致Node.js加载时冲突。另外单独编译单个文件也会忽略模块依赖的完整处理逻辑。
方案1:用ts-node直接运行TS脚本(推荐,无需写JS)
- 安装开发依赖:
npm install --save-dev ts-node @types/node
- 在
src目录下创建myscript.ts(用TS编写脚本逻辑):
import { function1, function2 } from "./algorithm"; // 这里写你的脚本逻辑 console.log("运行脚本:", function1());
- 修改
package.json中的脚本配置:
"scripts": { // 保留原有start、build等脚本 "myscript": "ts-node --esm src/myscript.ts" }
- 直接运行
npm run myscript即可,无需手动编译,ts-node会直接处理TS模块的加载。
方案2:修复原有编译方案(兼容JS脚本)
如果坚持使用JS脚本,需要调整编译配置避免语法冲突:
- 在项目根目录创建单独的脚本编译配置文件
tsconfig.script.json:
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "esnext", "target": "es2020", "noEmit": false, "outDir": "./dist/script" }, "include": ["src/algorithm.ts", "src/myscript.ts"] }
- 修改
package.json的脚本:
"scripts": { // 保留原有脚本 "myscript": "tsc --project tsconfig.script.json && node dist/script/myscript.js" }
- 修正
myscript.js的导入路径(如果改成TS脚本也适用):
import * as algorithm from "./algorithm";
编译后的文件会统一输出到dist/script目录,模块语法保持一致,不会出现exports未定义的问题。
注意事项
- 不要单独编译单个TS文件(
tsc src/algorithm.ts),这种方式会忽略TS配置的完整模块处理逻辑,导致语法冲突。 - 如果
algorithm.ts中使用了浏览器专属API(如DOM相关),需要在脚本中添加polyfill或调整逻辑,因为Node.js不支持这类API。
内容的提问来源于stack exchange,提问作者Vilius Kazakauskas

