t3-oss / t3-env

https://env.t3.gg
MIT License
2.74k stars 86 forks source link

[repro]: SyntaxError: Cannot use import statement outside a module #262

Closed luskin closed 1 month ago

luskin commented 2 months ago

Our company is building out a rather large Turborepo and we have recently adopted @t3-oss/env-core. The packages is fantastic, great work! Unfortunately, there appears to be one small but blocking issue with regards to ESM support. The entire monorepo is full ESM with hundreds of different packages, and @t3-oss/env-core is the only dependency which seems to have this issue. The previous issue on this has been closed due to no repro repo, well luckily for you maintainers we created the most minimal repro of the issue we are facing. To be clear, this is only occurring during testing phase, not during any dev/build processes.

The issue:

    SyntaxError: Cannot use import statement outside a module

    > 1 | import { createEnv } from '@t3-oss/env-core'
        | ^
      2 | import { z } from 'zod'
      3 |
      4 | export const env = createEnv({

      at Runtime.createScriptFromCode (node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1505:14)
      at Object.<anonymous> (env.ts:1:1)
      at Object.<anonymous> (index.ts:1:1)
      at Object.<anonymous> (index.unit.test.ts:1:1)

Reproduction Repository: https://github.com/luskin/t3-oss-env-esm-issue

luskin commented 2 months ago

I forgot to mention we are pulling ts-jest ESM setup directly from the documentation here

petevdp commented 1 month ago

@luskin I encountered the same issue, but I was able to get around it as suggested here by running jest under node with an additional like this: node --experimental-vm-modules node_modules/jest/bin/jest.js. I tried using this in your repro and it seems to work fine.

To me this suggests that the problem may just be jest's lack of support for esm, but if you're sure that other packages are actually distributing esm but don't encounter this issue then I'm not sure what the problem could be.

Edit: I see you're following the ts-jest instructions. I didn't try those.

luskin commented 1 month ago

@petevdp Thanks for the reply. Yes, that seems to patch the issue but from my understanding using the ts-jest esm setup should handle this without the need for the experimental flags. This package is the only ESM distributed package in our project that has this issue, unsure what is different with this package than others.

petevdp commented 1 month ago

@luskin I'm probably unable to debug futher, but I did try the following to test if any other common packages are affected by this issue:

I replaced the contents of env.ts with this, which removes all references to @t3-oss/env-core:

// import { z } from "zod";
// import { createEnv } from "@t3-oss/env-core";
import * as _ from "lodash-es";

const obj = {};
console.log(_.cloneDeep(obj));

export const env = {
  TEST_ENV_VAR: "MY_TEST_VALUE",
};
// export const env = createEnv({
//   server: {
//     TEST_ENV_VAR: z.string().optional().default("MY_TEST_VALUE"),
//   },
//   runtimeEnv: process.env,
//   emptyStringAsUndefined: true,
// });

and ran npm i lodash-es @types/lodash-es

what I found after running pnpm run test was the same kind of error as is in your report:

 /home/pete/repros/t3-oss-env-esm-issue/node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/lodash.js:10
    export { default as add } from './add.js';
    ^^^^^^

    SyntaxError: Unexpected token 'export'

      1 | // import { z } from "zod";
      2 | // import { createEnv } from "@t3-oss/env-core";
    > 3 | import * as _ from "lodash-es";
        | ^

The lodash.js file referenced in the error is just a series of exports which is very standard so it seems unlikely to me at least that this would be an issue which only appeard with certain package. I'm not sure what could separate the case of this package from the others you're dealing with, but perhaps there is some hidden difference?

I'm not totally sure what the problem is but based on the above I'm guessing that its origin is with jest being unable to run esmodules by default(perhaps that's a separate process from what is being done in this configuration from ts-jest). But of course I may be wrong. Hope this helps!

luskin commented 1 month ago

Closing as I have confirmed this is a problem with jest's incompatibility with ESM-only projects. ESM is far from ready for primetime, I would highly suggest the maintainers simply bundle a CJS version as well...

elliott-w commented 1 month ago

After 2 hours of debugging, I figured out you can add the following lines to your jest config:

  transform: {
    'node_modules/@t3-oss/.+\\.js$': ['ts-jest'],
  },
  transformIgnorePatterns: ['/node_modules/(?!@t3-oss)'],

Couldn't figure out how to get this to work with next/jest tho, so I'm just using ts-jest preset.