如何让NextJS API路由直接输出未打包的原生JavaScript文件?
问题描述
我需要在Next.js构建的网站中创建一个路由,用于输出可在其他网站中使用的JavaScript代码。我在pages/api目录下创建了sendTest.ts文件,同目录下还有一个test.ts文件,希望通过sendTest.ts输出该文件内容。
现有代码
sendTest.ts
import type { NextApiRequest, NextApiResponse } from 'next' import fs from 'fs'; import path from 'path' const filePath = path.join(__dirname, 'test.js'); const file = fs.readFileSync(filePath); export default function handler( req: NextApiRequest, res: NextApiResponse ) { res.setHeader('Content-Type', 'text/javascript'); res.status(200).send(file) }
test.ts
console.log('hello');
问题现象
Next.js构建后,该文件可通过website.com/api/sendTest访问,但打包后的内容包含Webpack相关代码:
"use strict"; (() => { var exports = {}; exports.id = 318; exports.ids = [318]; exports.modules = { /***/ 211: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); console.log("hello there"); /***/ }) }; ; // load runtime var __webpack_require__ = require("../../webpack-api-runtime.js"); __webpack_require__.C(exports); var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = (__webpack_exec__(211)); module.exports = __webpack_exports__; })();
当在其他页面通过<script src="website.com/api/sendTest"></script>引入时,会出现错误:
Uncaught ReferenceError: require is not defined at sendTest:22:27 at sendTest:28:3
我的问题是:如何让NextJS跳过对该文件的Webpack打包,仅将TypeScript转换为JavaScript后原样输出?或者有没有更优的方案来实现从指定NextJS路由输出JavaScript的需求?
解决方案
方案一:静态文件直接访问(最优解)
这是最简单高效的方式,完全绕开Webpack打包:
- 手动编译
test.ts为纯JavaScript:执行tsc test.ts命令,生成test.js文件 - 将编译后的
test.js放到Next.js项目的public目录下 - 其他网站直接通过
<script src="你的域名/test.js"></script>引入即可
这种方式输出的是纯原生JS代码,没有任何额外包装,性能最优。
方案二:API路由动态编译TS为纯JS
如果需要动态生成或实时编译TS文件,可以在API路由中用typescript库直接编译:
- 安装依赖:
npm install typescript @types/typescript --save
- 修改
sendTest.ts代码:
import type { NextApiRequest, NextApiResponse } from 'next' import fs from 'fs'; import path from 'path' import * as ts from 'typescript'; export default function handler(req: NextApiRequest, res: NextApiResponse) { const tsFilePath = path.join(__dirname, 'test.ts'); const tsContent = fs.readFileSync(tsFilePath, 'utf8'); // 配置编译选项,生成无模块包装的纯JS const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.None, // 禁用模块包装 noEmitOnError: true, }; // 编译TS为纯JS const compileResult = ts.transpileModule(tsContent, { compilerOptions }); res.setHeader('Content-Type', 'text/javascript'); res.status(200).send(compileResult.outputText); }
编译后输出的就是纯console.log('hello');代码,没有Webpack的包裹内容。
方案三:配置Webpack跳过特定文件打包
通过修改next.config.js,让Webpack直接读取文件原始内容,不进行打包处理:
- 安装依赖:
npm install raw-loader --save-dev
- 修改
next.config.js:
/** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config) => { // 对test.ts文件使用raw-loader,直接读取原始内容 config.module.rules.push({ test: /test\.ts$/, use: 'raw-loader', }); return config; }, }; module.exports = nextConfig;
- 更新
sendTest.ts:
import type { NextApiRequest, NextApiResponse } from 'next' import testRawContent from './test.ts'; import * as ts from 'typescript'; export default function handler(req: NextApiRequest, res: NextApiResponse) { // 把读取到的TS原始内容编译为纯JS const compileResult = ts.transpileModule(testRawContent, { compilerOptions: { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.None, }, }); res.setHeader('Content-Type', 'text/javascript'); res.status(200).send(compileResult.outputText); }
内容的提问来源于stack exchange,提问作者Neidd
相关产品推荐
相关产品推荐

