lukeed / tsm

TypeScript Module Loader
MIT License
1.18k stars 19 forks source link

Force to run as ESM #19

Closed faustbrian closed 2 years ago

faustbrian commented 2 years ago

Hey, I'm using a build setup like https://www.sensedeep.com/blog/posts/2021/how-to-create-single-source-npm-module.html to support both ESM and CJS but that seems to cause an issue with https://github.com/lukeed/uvu which seems to come from tsm when looking at the stack trace.

The TLDR of the above article is that instead of your package.json having a type property you defer it into the distribution folder. So you have dist/cjs/package.json and dist/esm/package.json files which indicate how to treat the loading. I assume that tsm decides if it should use require or import based on the type property in the package.json file.

Is there any way to force tsm to run as if the package.json file had a type property that is set to module?

> @payvo/sdk-ada@3.2.2 test /Users/brianfaust/Work/sdk/packages/ada
> uvu -r tsm source .test.js

/Users/brianfaust/Work/sdk/packages/ada/source/address-list.service.test.js:1
import { assert, test } from "@payvo/sdk-test";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1031:15)
    at Module._compile (node:internal/modules/cjs/loader:1065:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Object.loader (/Users/brianfaust/Work/sdk/common/temp/node_modules/.pnpm/tsm@2.1.4/node_modules/tsm/require.js:1:1052)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at /Users/brianfaust/Work/sdk/common/temp/node_modules/.pnpm/uvu@0.5.2/node_modules/uvu/run/index.js:9:3
 ELIFECYCLE  Test failed. See above for more details.
lukeed commented 2 years ago

You can use a config file to force/configure behavior for a specific extension. So, if you want all .js files to be loaded as ESM, you can do this:

// tsm.js
import { define } from 'tsm/config';

export default define({
  '.js': {
    format: 'esm'
  }
});

However, if you're doing something like uvu -r tsm or node --require tsm then you'll still run into issues. This is because you're using a require hook to load a file. That file cannot contain ESM since it was required. It'd be like trying to do require('./file.mjs')

If you invoke tsm directly as a CLI (or via node --loader tsm) then that Node process will be expecting/able to handle ESM. It will also be able to handle any CommonJS module exports.

Hopefully that helps! I believe the docs touch on this too