olalonde / advisory-lock

advisory-lock
13 stars 1 forks source link

Module not importing correctly in modern setups / native ESM missing #1

Open IlyaSemenov opened 4 months ago

IlyaSemenov commented 4 months ago

With Typescript or native ESM, the module doesn't import correctly:

import advisoryLock from "advisory-lock"

const mutex = advisoryLock("postgres://user:pass@localhost:3475/dbname")(
  "some-lock-name",
)

console.log(mutex)

Run it with tsx (same will happen with vite and probably most other bundlers):

% npx tsx 1.ts
/Users/is/work/ss/1.ts:3
const mutex = advisoryLock("postgres://user:pass@localhost:3475/dbname")(
              ^

TypeError: advisoryLock is not a function
    at <anonymous> (/Users/is/work/ss/1.ts:3:15)
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

or just run as an ESM script in a project with { "type": "module" } in package.json:

% node 1.js
file:///Users/is/work/ss/1.js:3
const mutex = advisoryLock("postgres://user:pass@localhost:3475/dbname")(
              ^

TypeError: advisoryLock is not a function
    at file:///Users/is/work/ss/1.js:3:15
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

This is because the imported module, despite being typed as a function, is in fact an object:

{
  __esModule: true,
  strToKey: [Function: strToKey],
  default: [Function (anonymous)]
}

I see you're using old plain tsc for compile. I suggest to rework the project build setup to use tsup and emit modern CJS and ESM builds (and update package.json accordingly). I can come up with a PR if that's something that you will possibly accept.

jpallen commented 14 hours ago

It's ugly, but I've worked around this in my own code with this wrapper:

import advisoryLock from 'advisory-lock'

type AdvisoryLock = typeof advisoryLock

let _advisoryLock = advisoryLock as any

// See https://github.com/olalonde/advisory-lock/issues/1 for why we need this
if (_advisoryLock.default) {
  _advisoryLock = _advisoryLock.default
}

export default _advisoryLock as AdvisoryLock