| 96 | } |
| 97 | |
| 98 | export async function load(url, context, nextLoad) { |
| 99 | const [urlWithoutQuery] = url.split('?'); |
| 100 | |
| 101 | if (!urlWithoutQuery.startsWith('file:')) { |
| 102 | return nextLoad(url, context); |
| 103 | } |
| 104 | |
| 105 | const filePath = fileURLToPath(urlWithoutQuery); |
| 106 | if (!TS_EXTENSIONS.has(path.extname(filePath))) { |
| 107 | return nextLoad(url, context); |
| 108 | } |
| 109 | |
| 110 | const stat = await fs.promises.stat(filePath); |
| 111 | const cached = transformCache.get(filePath); |
| 112 | if (cached?.mtimeMs === stat.mtimeMs) { |
| 113 | return { |
| 114 | format: cached.format, |
| 115 | source: cached.source, |
| 116 | shortCircuit: true, |
| 117 | }; |
| 118 | } |
| 119 | |
| 120 | const sourceText = await fs.promises.readFile(filePath, 'utf8'); |
| 121 | const isCommonJs = filePath.endsWith('.cts'); |
| 122 | const moduleType = isCommonJs ? 'commonjs' : 'es6'; |
| 123 | const tsx = filePath.endsWith('.tsx'); |
| 124 | |
| 125 | let output; |
| 126 | try { |
| 127 | output = await transform(sourceText, { |
| 128 | filename: filePath, |
| 129 | sourceMaps: 'inline', |
| 130 | module: { type: moduleType }, |
| 131 | jsc: { |
| 132 | target: 'es2022', |
| 133 | keepClassNames: true, |
| 134 | experimental: { keepImportAttributes: true }, |
| 135 | parser: { |
| 136 | syntax: 'typescript', |
| 137 | tsx, |
| 138 | decorators: true, |
| 139 | dynamicImport: true, |
| 140 | }, |
| 141 | transform: { |
| 142 | legacyDecorator: true, |
| 143 | decoratorMetadata: true, |
| 144 | useDefineForClassFields: false, |
| 145 | react: tsx |
| 146 | ? { runtime: 'automatic', importSource: 'react' } |
| 147 | : undefined, |
| 148 | }, |
| 149 | }, |
| 150 | }); |
| 151 | } catch (error) { |
| 152 | const detail = error instanceof Error ? error.message : String(error); |
| 153 | throw new Error(`[swc-loader] Failed to compile ${filePath}\n${detail}`); |
| 154 | } |
| 155 | |