Skip to content

Commit

Permalink
feat: support importing type module dependencies (#18)
Browse files Browse the repository at this point in the history
Closes #17
  • Loading branch information
privatenumber committed Apr 18, 2021
1 parent b14a291 commit a540af7
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 2 deletions.
35 changes: 33 additions & 2 deletions src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { RawSourceMap } from 'source-map'
import sourceMapSupport from 'source-map-support'
import { transformSync, TransformOptions } from 'esbuild'
import { addHook } from 'pirates'
import fs from 'fs';
import module from 'module';
import { getOptions, inferPackageFormat } from './options'

const map: { [file: string]: string | RawSourceMap } = {}
Expand All @@ -23,6 +25,34 @@ function installSourceMapSupport() {
})
}

type COMPILE = (code: string, filename: string, format?: 'cjs' | 'esm') => string

/**
* Patch the Node CJS loader to suppress the ESM error
* https://github.com/nodejs/node/blob/069b5df/lib/internal/modules/cjs/loader.js#L1125
*
* As per https://github.com/standard-things/esm/issues/868#issuecomment-594480715
*/
function patchCommonJsLoader(compile: COMPILE) {
// @ts-expect-error
const extensions = module.Module._extensions;
const jsHandler = extensions['.js'];

extensions['.js'] = function(module: any, filename: string) {
try {
return jsHandler.call(this, module, filename)
} catch (error) {
if (error.code !== 'ERR_REQUIRE_ESM') {
throw error;
}

let content = fs.readFileSync(filename, 'utf8');
content = compile(content, filename, 'cjs');
module._compile(content, filename);
}
};
}

type LOADERS = 'js' | 'jsx' | 'ts' | 'tsx'
const FILE_LOADERS = {
'.js': 'js',
Expand All @@ -44,10 +74,10 @@ export function register(
) {
const { extensions = DEFAULT_EXTENSIONS, ...overrides } = esbuildOptions

function compile(code: string, filename: string) {
const compile: COMPILE = function compile(code, filename, format) {
const dir = dirname(filename)
const options = getOptions(dir)
const format = inferPackageFormat(dir, filename)
format = format ?? inferPackageFormat(dir, filename)

const { code: js, warnings, map: jsSourceMap } = transformSync(code, {
sourcefile: filename,
Expand All @@ -69,6 +99,7 @@ export function register(
return js
}
installSourceMapSupport()
patchCommonJsLoader(compile)
addHook(compile, {
exts: extensions,
})
Expand Down
3 changes: 3 additions & 0 deletions tests/import-type-module/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import foo from 'foo'

console.log(foo)
1 change: 1 addition & 0 deletions tests/import-type-module/node_modules/foo/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions tests/import-type-module/node_modules/foo/package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tests/import-type-module/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"private": true
}
9 changes: 9 additions & 0 deletions tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ test('package type module', async () => {
assert.is(stdout, 'foo')
})

test('import type module', async () => {
const { stdout } = await execa('node', [
'-r',
`${process.cwd()}/register.js`,
`${process.cwd()}/tests/import-type-module/index.js`,
])
assert.is(stdout, 'foo')
})

test.run()

0 comments on commit a540af7

Please sign in to comment.