Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Jiti not fully importing esm module when default export is a Promise #400

@kevinmarrec

Description

@kevinmarrec

Environment

Node v22.17.0
ESLint v9.35.0
Jiti v2.5.1

Reproduction

Import with jiti

Create two files :

// withoutPromise.js
export const foo = () => 'foo'
export const bar = 'bar'

export default foo()
// withPromise.js
export const foo = async () => 'foo'
export const bar = 'bar'

export default foo()

Import and debug them with jiti :

// reproduction.js
import { createJiti } from 'jiti'

const jiti = createJiti(import.meta.url, {
  moduleCache: false,
})

const configA = await jiti.import('./withoutPromise.js')

console.log(configA)

const configB = await jiti.import('./withPromise.js')

console.log(configB)

Result :

# node reproduction.js
[Module: null prototype] {
  bar: 'bar',
  default: 'foo',
  foo: [Function: foo]
}
foo

Expected :

[Module: null prototype] {
  bar: 'bar',
  default: 'foo',
  foo: [Function: foo]
}
[Module: null prototype] {
  bar: 'bar',
  default: Promise { 'foo' },
  foo: [AsyncFunction: foo]
}

Classic import with Node

// works.js
import { default as _default, foo, bar } from './withPromise.js'

console.log(bar)
console.log(_default)
console.log(foo)

Result :

# node works.js
bar
Promise { 'foo' }
[AsyncFunction: foo]

Describe the bug

jiti is failing to fully import a module when the default exported value is a promise.

I figured out this when trying to export something else in my module aside @antfu ESLint config (which main function antfu results in a promise) :

// config.js
import { antfu } from '@antfu/eslint-config'

export const foo = 'foo'

export default antfu(/* options */)
// reproduction.js
import { createJiti } from 'jiti'

const jiti = createJiti(import.meta.url, {
  moduleCache: false,
})

const config = await jiti.import('./config.js')

console.log(config.foo)
# Result
undefined

Additional context

Maybe #388 is related

I tried to hack ESLint config loader to force interopDefault to false, it make named export working but break default.

So my guess is that is has to do with jiti interopDefault implementation.

I inspected

jiti/src/utils.ts

Lines 116 to 119 in cdb86cb

if (defIsNil && mod instanceof Promise) {
// Hotfix for #388
return mod;
}
and I think I'm not falling into this fix because my module does an export default therefore def = mod.default is defined, so defIsNil if falsy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions