.
This commit is contained in:
+4
@@ -0,0 +1,4 @@
|
||||
import type { Options as SWCOptions } from '@swc/core';
|
||||
export declare function registerHook(swcOptions: SWCOptions): void;
|
||||
export declare function deregisterHook(): void;
|
||||
export declare function requireFromString(code: string, filename: string): any;
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
0 && (module.exports = {
|
||||
deregisterHook: null,
|
||||
registerHook: null,
|
||||
requireFromString: null
|
||||
});
|
||||
function _export(target, all) {
|
||||
for(var name in all)Object.defineProperty(target, name, {
|
||||
enumerable: true,
|
||||
get: all[name]
|
||||
});
|
||||
}
|
||||
_export(exports, {
|
||||
deregisterHook: function() {
|
||||
return deregisterHook;
|
||||
},
|
||||
registerHook: function() {
|
||||
return registerHook;
|
||||
},
|
||||
requireFromString: function() {
|
||||
return requireFromString;
|
||||
}
|
||||
});
|
||||
const _nodemodule = /*#__PURE__*/ _interop_require_default(require("node:module"));
|
||||
const _nodefs = require("node:fs");
|
||||
const _nodepath = require("node:path");
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
const oldJSHook = require.extensions['.js'];
|
||||
const extensions = [
|
||||
'.ts',
|
||||
'.cts',
|
||||
'.mts',
|
||||
'.cjs',
|
||||
'.mjs'
|
||||
];
|
||||
function registerHook(swcOptions) {
|
||||
// lazy require swc since it loads React before even setting NODE_ENV
|
||||
// resulting loading Development React on Production
|
||||
const { transformSync } = require('../swc');
|
||||
require.extensions['.js'] = function(mod, oldFilename) {
|
||||
try {
|
||||
return oldJSHook(mod, oldFilename);
|
||||
} catch (error) {
|
||||
if (error.code !== 'ERR_REQUIRE_ESM') {
|
||||
throw error;
|
||||
}
|
||||
// calling oldJSHook throws ERR_REQUIRE_ESM, so run _compile manually
|
||||
// TODO: investigate if we can remove readFileSync
|
||||
const content = (0, _nodefs.readFileSync)(oldFilename, 'utf8');
|
||||
const { code } = transformSync(content, swcOptions);
|
||||
mod._compile(code, oldFilename);
|
||||
}
|
||||
};
|
||||
for (const ext of extensions){
|
||||
const oldHook = require.extensions[ext] ?? oldJSHook;
|
||||
require.extensions[ext] = function(mod, oldFilename) {
|
||||
const _compile = mod._compile;
|
||||
mod._compile = function(code, filename) {
|
||||
const swc = transformSync(code, swcOptions);
|
||||
return _compile.call(this, swc.code, filename);
|
||||
};
|
||||
return oldHook(mod, oldFilename);
|
||||
};
|
||||
}
|
||||
}
|
||||
function deregisterHook() {
|
||||
require.extensions['.js'] = oldJSHook;
|
||||
extensions.forEach((ext)=>delete require.extensions[ext]);
|
||||
}
|
||||
function requireFromString(code, filename) {
|
||||
const paths = _nodemodule.default._nodeModulePaths((0, _nodepath.dirname)(filename));
|
||||
const m = new _nodemodule.default(filename, module.parent);
|
||||
m.paths = paths;
|
||||
m._compile(code, filename);
|
||||
return m.exports;
|
||||
}
|
||||
|
||||
//# sourceMappingURL=require-hook.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../src/build/next-config-ts/require-hook.ts"],"sourcesContent":["import type { Options as SWCOptions } from '@swc/core'\nimport Module from 'node:module'\nimport { readFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\nconst oldJSHook = require.extensions['.js']\nconst extensions = ['.ts', '.cts', '.mts', '.cjs', '.mjs']\n\nexport function registerHook(swcOptions: SWCOptions) {\n // lazy require swc since it loads React before even setting NODE_ENV\n // resulting loading Development React on Production\n const { transformSync } = require('../swc') as typeof import('../swc')\n\n require.extensions['.js'] = function (mod: any, oldFilename) {\n try {\n return oldJSHook(mod, oldFilename)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ERR_REQUIRE_ESM') {\n throw error\n }\n\n // calling oldJSHook throws ERR_REQUIRE_ESM, so run _compile manually\n // TODO: investigate if we can remove readFileSync\n const content = readFileSync(oldFilename, 'utf8')\n const { code } = transformSync(content, swcOptions)\n mod._compile(code, oldFilename)\n }\n }\n\n for (const ext of extensions) {\n const oldHook = require.extensions[ext] ?? oldJSHook\n require.extensions[ext] = function (mod: any, oldFilename) {\n const _compile = mod._compile\n\n mod._compile = function (code: string, filename: string) {\n const swc = transformSync(code, swcOptions)\n return _compile.call(this, swc.code, filename)\n }\n\n return oldHook(mod, oldFilename)\n }\n }\n}\n\nexport function deregisterHook() {\n require.extensions['.js'] = oldJSHook\n extensions.forEach((ext) => delete require.extensions[ext])\n}\n\nexport function requireFromString(code: string, filename: string) {\n const paths = (Module as any)._nodeModulePaths(dirname(filename))\n const m = new Module(filename, module.parent!) as any\n m.paths = paths\n m._compile(code, filename)\n return m.exports\n}\n"],"names":["deregisterHook","registerHook","requireFromString","oldJSHook","require","extensions","swcOptions","transformSync","mod","oldFilename","error","code","content","readFileSync","_compile","ext","oldHook","filename","swc","call","forEach","paths","Module","_nodeModulePaths","dirname","m","module","parent","exports"],"mappings":";;;;;;;;;;;;;;;;IA4CgBA,cAAc;eAAdA;;IApCAC,YAAY;eAAZA;;IAyCAC,iBAAiB;eAAjBA;;;mEAhDG;wBACU;0BACL;;;;;;AAExB,MAAMC,YAAYC,QAAQC,UAAU,CAAC,MAAM;AAC3C,MAAMA,aAAa;IAAC;IAAO;IAAQ;IAAQ;IAAQ;CAAO;AAEnD,SAASJ,aAAaK,UAAsB;IACjD,qEAAqE;IACrE,oDAAoD;IACpD,MAAM,EAAEC,aAAa,EAAE,GAAGH,QAAQ;IAElCA,QAAQC,UAAU,CAAC,MAAM,GAAG,SAAUG,GAAQ,EAAEC,WAAW;QACzD,IAAI;YACF,OAAON,UAAUK,KAAKC;QACxB,EAAE,OAAOC,OAAO;YACd,IAAI,AAACA,MAAgCC,IAAI,KAAK,mBAAmB;gBAC/D,MAAMD;YACR;YAEA,qEAAqE;YACrE,kDAAkD;YAClD,MAAME,UAAUC,IAAAA,oBAAY,EAACJ,aAAa;YAC1C,MAAM,EAAEE,IAAI,EAAE,GAAGJ,cAAcK,SAASN;YACxCE,IAAIM,QAAQ,CAACH,MAAMF;QACrB;IACF;IAEA,KAAK,MAAMM,OAAOV,WAAY;QAC5B,MAAMW,UAAUZ,QAAQC,UAAU,CAACU,IAAI,IAAIZ;QAC3CC,QAAQC,UAAU,CAACU,IAAI,GAAG,SAAUP,GAAQ,EAAEC,WAAW;YACvD,MAAMK,WAAWN,IAAIM,QAAQ;YAE7BN,IAAIM,QAAQ,GAAG,SAAUH,IAAY,EAAEM,QAAgB;gBACrD,MAAMC,MAAMX,cAAcI,MAAML;gBAChC,OAAOQ,SAASK,IAAI,CAAC,IAAI,EAAED,IAAIP,IAAI,EAAEM;YACvC;YAEA,OAAOD,QAAQR,KAAKC;QACtB;IACF;AACF;AAEO,SAAST;IACdI,QAAQC,UAAU,CAAC,MAAM,GAAGF;IAC5BE,WAAWe,OAAO,CAAC,CAACL,MAAQ,OAAOX,QAAQC,UAAU,CAACU,IAAI;AAC5D;AAEO,SAASb,kBAAkBS,IAAY,EAAEM,QAAgB;IAC9D,MAAMI,QAAQ,AAACC,mBAAM,CAASC,gBAAgB,CAACC,IAAAA,iBAAO,EAACP;IACvD,MAAMQ,IAAI,IAAIH,mBAAM,CAACL,UAAUS,OAAOC,MAAM;IAC5CF,EAAEJ,KAAK,GAAGA;IACVI,EAAEX,QAAQ,CAACH,MAAMM;IACjB,OAAOQ,EAAEG,OAAO;AAClB","ignoreList":[0]}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export declare function transpileConfig({ nextConfigPath, dir, }: {
|
||||
nextConfigPath: string;
|
||||
dir: string;
|
||||
}): Promise<any>;
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "transpileConfig", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return transpileConfig;
|
||||
}
|
||||
});
|
||||
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
||||
const _nodefs = require("node:fs");
|
||||
const _nodeurl = require("node:url");
|
||||
const _commentjson = /*#__PURE__*/ _interop_require_wildcard(require("next/dist/compiled/comment-json"));
|
||||
const _requirehook = require("./require-hook");
|
||||
const _log = require("../output/log");
|
||||
const _utils = require("../../server/lib/utils");
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
function _getRequireWildcardCache(nodeInterop) {
|
||||
if (typeof WeakMap !== "function") return null;
|
||||
var cacheBabelInterop = new WeakMap();
|
||||
var cacheNodeInterop = new WeakMap();
|
||||
return (_getRequireWildcardCache = function(nodeInterop) {
|
||||
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
||||
})(nodeInterop);
|
||||
}
|
||||
function _interop_require_wildcard(obj, nodeInterop) {
|
||||
if (!nodeInterop && obj && obj.__esModule) {
|
||||
return obj;
|
||||
}
|
||||
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
||||
return {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
var cache = _getRequireWildcardCache(nodeInterop);
|
||||
if (cache && cache.has(obj)) {
|
||||
return cache.get(obj);
|
||||
}
|
||||
var newObj = {
|
||||
__proto__: null
|
||||
};
|
||||
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
||||
for(var key in obj){
|
||||
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
||||
if (desc && (desc.get || desc.set)) {
|
||||
Object.defineProperty(newObj, key, desc);
|
||||
} else {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
newObj.default = obj;
|
||||
if (cache) {
|
||||
cache.set(obj, newObj);
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
function resolveSWCOptions(cwd, compilerOptions) {
|
||||
var _process_versions, _process;
|
||||
return {
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: 'typescript'
|
||||
},
|
||||
...compilerOptions.paths ? {
|
||||
paths: compilerOptions.paths
|
||||
} : {},
|
||||
...compilerOptions.baseUrl ? {
|
||||
baseUrl: _nodepath.default.resolve(cwd, compilerOptions.baseUrl)
|
||||
} : compilerOptions.paths ? {
|
||||
baseUrl: cwd
|
||||
} : {}
|
||||
},
|
||||
module: {
|
||||
type: 'commonjs'
|
||||
},
|
||||
isModule: 'unknown',
|
||||
env: {
|
||||
targets: {
|
||||
// Setting the Node.js version can reduce unnecessary code generation.
|
||||
node: ((_process = process) == null ? void 0 : (_process_versions = _process.versions) == null ? void 0 : _process_versions.node) ?? '20.19.0'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function resolveExtends(extendsPath, currentConfigDir) {
|
||||
// Relative paths are resolved relative to the current config's directory
|
||||
if (extendsPath.startsWith('./') || extendsPath.startsWith('../') || _nodepath.default.isAbsolute(extendsPath)) {
|
||||
const resolved = _nodepath.default.resolve(currentConfigDir, extendsPath);
|
||||
// TypeScript allows omitting .json extension
|
||||
if ((0, _nodefs.existsSync)(resolved)) {
|
||||
return resolved;
|
||||
}
|
||||
if (!resolved.endsWith('.json') && (0, _nodefs.existsSync)(resolved + '.json')) {
|
||||
return resolved + '.json';
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
// Package paths - use require.resolve to find the package
|
||||
try {
|
||||
// Try resolving as a direct path within the package
|
||||
return require.resolve(extendsPath, {
|
||||
paths: [
|
||||
currentConfigDir
|
||||
]
|
||||
});
|
||||
} catch {
|
||||
// If that fails, try appending tsconfig.json for package names like "@tsconfig/node18"
|
||||
try {
|
||||
return require.resolve(extendsPath + '/tsconfig.json', {
|
||||
paths: [
|
||||
currentConfigDir
|
||||
]
|
||||
});
|
||||
} catch {
|
||||
// Return the original path and let it fail later with a clear error
|
||||
return _nodepath.default.resolve(currentConfigDir, extendsPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
function loadTsConfigFile(configPath, visited) {
|
||||
const resolvedPath = _nodepath.default.resolve(configPath);
|
||||
if (visited.has(resolvedPath)) {
|
||||
return {};
|
||||
}
|
||||
visited.add(resolvedPath);
|
||||
if (!(0, _nodefs.existsSync)(resolvedPath)) {
|
||||
return {};
|
||||
}
|
||||
const configContent = (0, _nodefs.readFileSync)(resolvedPath, 'utf8');
|
||||
const config = _commentjson.parse(configContent);
|
||||
const configDir = _nodepath.default.dirname(resolvedPath);
|
||||
let mergedOptions = {};
|
||||
// Note that config options from `extends` should get overwritten, not merged
|
||||
if (config.extends) {
|
||||
const extendsList = Array.isArray(config.extends) ? config.extends : [
|
||||
config.extends
|
||||
];
|
||||
for (const extendsPath of extendsList){
|
||||
const parentConfigPath = resolveExtends(extendsPath, configDir);
|
||||
const parentOptions = loadTsConfigFile(parentConfigPath, visited);
|
||||
mergedOptions = {
|
||||
...mergedOptions,
|
||||
...parentOptions
|
||||
};
|
||||
}
|
||||
}
|
||||
const currentOptions = config.compilerOptions ?? {};
|
||||
mergedOptions = {
|
||||
...mergedOptions,
|
||||
paths: currentOptions.paths ?? mergedOptions.paths,
|
||||
baseUrl: currentOptions.baseUrl ?? mergedOptions.baseUrl
|
||||
};
|
||||
return mergedOptions;
|
||||
}
|
||||
async function loadTsConfig(dir) {
|
||||
// NOTE: This doesn't fully cover the edge case for setting
|
||||
// "typescript.tsconfigPath" in next config which is currently
|
||||
// a restriction.
|
||||
// It's a chicken-and-egg problem since we need to transpile
|
||||
// the next config to get that value.
|
||||
const resolvedTsConfigPath = _nodepath.default.join(dir, 'tsconfig.json');
|
||||
if (!(0, _nodefs.existsSync)(resolvedTsConfigPath)) {
|
||||
return {};
|
||||
}
|
||||
return loadTsConfigFile(resolvedTsConfigPath, new Set());
|
||||
}
|
||||
async function transpileConfig({ nextConfigPath, dir }) {
|
||||
try {
|
||||
// envs are passed to the workers and preserve the flag
|
||||
if (process.env.__NEXT_NODE_NATIVE_TS_LOADER_ENABLED === 'true') {
|
||||
try {
|
||||
// Node.js v22.10.0+
|
||||
// Value is 'strip' or 'transform' based on how the feature is enabled.
|
||||
// https://nodejs.org/api/process.html#processfeaturestypescript
|
||||
// TODO: Remove `as any` once we bump @types/node to v22.10.0+
|
||||
if (process.features.typescript) {
|
||||
// Run import() here to catch errors and fallback to legacy resolution.
|
||||
return (await import((0, _nodeurl.pathToFileURL)(nextConfigPath).href)).default;
|
||||
}
|
||||
if ((0, _utils.getNodeOptionsArgs)().includes('--no-experimental-strip-types') || process.execArgv.includes('--no-experimental-strip-types')) {
|
||||
(0, _log.warnOnce)(`Skipped resolving "${_nodepath.default.basename(nextConfigPath)}" using Node.js native TypeScript resolution because it was disabled by the "--no-experimental-strip-types" flag.` + ' Falling back to legacy resolution.' + ' Learn more: https://nextjs.org/docs/app/api-reference/config/typescript#using-nodejs-native-typescript-resolver-for-nextconfigts');
|
||||
}
|
||||
// Feature is not enabled, fallback to legacy resolution for current session.
|
||||
process.env.__NEXT_NODE_NATIVE_TS_LOADER_ENABLED = 'false';
|
||||
} catch (cause) {
|
||||
(0, _log.warnOnce)(`Failed to import "${_nodepath.default.basename(nextConfigPath)}" using Node.js native TypeScript resolution.` + ' Falling back to legacy resolution.' + ' Learn more: https://nextjs.org/docs/app/api-reference/config/typescript#using-nodejs-native-typescript-resolver-for-nextconfigts', {
|
||||
cause
|
||||
});
|
||||
// Once failed, fallback to legacy resolution for current session.
|
||||
process.env.__NEXT_NODE_NATIVE_TS_LOADER_ENABLED = 'false';
|
||||
}
|
||||
}
|
||||
const compilerOptions = await loadTsConfig(dir);
|
||||
return handleCJS({
|
||||
dir,
|
||||
nextConfigPath,
|
||||
compilerOptions
|
||||
});
|
||||
} catch (cause) {
|
||||
throw Object.defineProperty(new Error(`Failed to transpile "${_nodepath.default.basename(nextConfigPath)}".`, {
|
||||
cause
|
||||
}), "__NEXT_ERROR_CODE", {
|
||||
value: "E797",
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
async function handleCJS({ dir, nextConfigPath, compilerOptions }) {
|
||||
const swcOptions = resolveSWCOptions(dir, compilerOptions);
|
||||
let hasRequire = false;
|
||||
try {
|
||||
var _config_experimental;
|
||||
const nextConfigString = (0, _nodefs.readFileSync)(nextConfigPath, 'utf8');
|
||||
// lazy require swc since it loads React before even setting NODE_ENV
|
||||
// resulting loading Development React on Production
|
||||
const { loadBindings } = require('../swc');
|
||||
const bindings = await loadBindings();
|
||||
const { code } = await bindings.transform(nextConfigString, swcOptions);
|
||||
// register require hook only if require exists
|
||||
if (code.includes('require(')) {
|
||||
(0, _requirehook.registerHook)(swcOptions);
|
||||
hasRequire = true;
|
||||
}
|
||||
// filename & extension don't matter here
|
||||
const config = (0, _requirehook.requireFromString)(code, _nodepath.default.resolve(dir, 'next.config.compiled.js'));
|
||||
// At this point we have already loaded the bindings without this configuration setting due to the `transform` call above.
|
||||
// Possibly we fell back to wasm in which case, it all works out but if not we need to warn
|
||||
// that the configuration was ignored.
|
||||
if ((config == null ? void 0 : (_config_experimental = config.experimental) == null ? void 0 : _config_experimental.useWasmBinary) && !bindings.isWasm) {
|
||||
(0, _log.warn)('Using a next.config.ts file is incompatible with `experimental.useWasmBinary` unless ' + '`--experimental-next-config-strip-types` is also passed.\nSetting `useWasmBinary` to `false');
|
||||
config.experimental.useWasmBinary = false;
|
||||
}
|
||||
return config;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
} finally{
|
||||
if (hasRequire) {
|
||||
(0, _requirehook.deregisterHook)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//# sourceMappingURL=transpile-config.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user