diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eaed733..4ed2de9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - node-version: [12.x, 14.x, 16.x] + node-version: [12.x, 14.x, 16.x, 16.11, 16.12] os: [ubuntu-latest, windows-latest, macos-latest] fail-fast: false diff --git a/loader.mjs b/loader.mjs index 605da91..30a7819 100644 --- a/loader.mjs +++ b/loader.mjs @@ -5,14 +5,37 @@ import { transformSync } from 'esbuild' const baseURL = pathToFileURL(`${process.cwd()}/`).href const isWindows = process.platform === 'win32' -const extensionsRegex = /\.(tsx?|json)$/; +const extensionsRegex = /\.(tsx?|json)$/ const excludeRegex = /^\w+:/ +function esbuildTransformSync(rawSource, filename, url, format) { + const { + code: js, + warnings, + map: jsSourceMap, + } = transformSync(rawSource.toString(), { + sourcefile: filename, + sourcemap: 'both', + loader: new URL(url).pathname.match(extensionsRegex)[1], + target: `node${process.versions.node}`, + format: format === 'module' ? 'esm' : 'cjs', + }) + + if (warnings && warnings.length > 0) { + for (const warning of warnings) { + console.warn(warning.location) + console.warn(warning.text) + } + } + + return { js, jsSourceMap } +} + export function resolve(specifier, context, defaultResolve) { const { parentURL = baseURL } = context const url = new URL(specifier, parentURL) if (extensionsRegex.test(url.pathname)) - return { url: url.href } + return { url: url.href, format: 'module' } // ignore `data:` and `node:` prefix etc. if (!excludeRegex.test(specifier)) { @@ -22,7 +45,10 @@ export function resolve(specifier, context, defaultResolve) { url.pathname = `${pathname}.${ext}` const path = fileURLToPath(url.href) if (fs.existsSync(path)) - return { url: url.href } + return { + url: url.href, + format: extensionsRegex.test(url.pathname) && 'module', + } } } @@ -30,6 +56,28 @@ export function resolve(specifier, context, defaultResolve) { return defaultResolve(specifier, context, defaultResolve) } +// New hook starting from Node v16.12.0 +// See: https://github.com/nodejs/node/pull/37468 +export function load(url, context, defaultLoad) { + if (extensionsRegex.test(new URL(url).pathname)) { + const { format } = context + + let filename = url + if (!isWindows) filename = fileURLToPath(url) + + const rawSource = fs.readFileSync(new URL(url), { encoding: 'utf8' }) + const { js } = esbuildTransformSync(rawSource, filename, url, format) + + return { + format: 'module', + source: js, + } + } + + // Let Node.js handle all other format / sources. + return defaultLoad(url, context, defaultLoad) +} + export function getFormat(url, context, defaultGetFormat) { if (extensionsRegex.test(new URL(url).pathname)) { return { @@ -46,23 +94,9 @@ export function transformSource(source, context, defaultTransformSource) { if (extensionsRegex.test(new URL(url).pathname)) { let filename = url - if (!isWindows) - filename = fileURLToPath(url) - - const { code: js, warnings, map: jsSourceMap } = transformSync(source.toString(), { - sourcefile: filename, - sourcemap: 'both', - loader: new URL(url).pathname.match(extensionsRegex)[1], - target: `node${process.versions.node}`, - format: format === 'module' ? 'esm' : 'cjs', - }) - - if (warnings && warnings.length > 0) { - for (const warning of warnings) { - console.warn(warning.location) - console.warn(warning.text) - } - } + if (!isWindows) filename = fileURLToPath(url) + + const { js } = esbuildTransformSync(source, filename, url, format) return { source: js,