farm-fe / farm

Extremely fast Vite-compatible web build tool written in Rust
https://farmfe.org
MIT License
4.32k stars 145 forks source link

[Bug Report]: broken ESM/CJS Interoperability #1509

Open Iced-Sun opened 4 days ago

Iced-Sun commented 4 days ago

Steps to reproduce

  1. mkdir test && cd test
  2. pnpm init
  3. pnpm add @farmfe/cli@0.6.0 @farmfe/core@0.15.3
  4. pnpm add @npmcli/run-script
  5. pnpm add bluebird # workaround for #1252
  6. cat index.ts
    import '@npmcli/run-script';
  7. cat farm.config.ts
    
    import { defineConfig } from '@farmfe/core';

export default defineConfig({ compilation: { input: { index: './index.ts', }, output: { targetEnv: 'node' }, presetEnv: { options: { targets: 'last 2 node major versions' } }, } });

8. `./node_modules/.bin/farm build` succeeds and writes to `./dist/index.js`

### Reproduce link

_No response_

### What is actually happening?

Runnning `node ./dist/index.js` throws `SyntaxError: Cannot use import statement outside a module`.

To fix that, we could either 
1. set `output.entryFilename` to `[entryName].mjs`
    - `./node_modules/.bin/farm build` succeeds
    - `node ./dist/index.mjs` throws `Cannot find module 'node-gyp/bin/node-gyp.js`
    -  after `pnpm add node-gyp`, both compiling and running work fine
2. add `"type": "module"` to `package.json`
    - `./node_modules/.bin/farm build` succeeds
    - `node ./dist/index.js` throws `ReferenceError: __dirname is not defined in ES module scope`
    -  set `output.filename` to `[resourceName].[contentHash].cjs`
    -  `node ./dist/index.js` throws `Cannot find module 'node-gyp/bin/node-gyp.js`
    -  after `pnpm add node-gyp`, both compiling and running work fine
3. set `output.format` to `cjs`
    - `./node_modules/.bin/farm build` succeeds
    - `node ./dist/index.js` throws `Cannot find module 'node-gyp/bin/node-gyp.js`
    -  after `pnpm add node-gyp`, both compiling and running work fine

Either way, we now have a working project. That is the first half of the story.

Let's upgrade `@farmfe/core` to version 0.15.4. Now the workarounds of 1, 2 are broken with `SyntaxError: Cannot use import statement outside a module`, because all required external node builtin modules are `import`ed at the start of bundle files.

Tested with latest `@farmfe/core@1.2.5`, the same behavior can be observed as well. 

As for the workaround 3, it did survive against run-script. But adding a dependency on google-protobuf breaks it tragedically:
1. `pnpm add google-protobuf@3.21.2`
2. `echo "import 'google-protobuf'" >> index.ts`
3. compile, run, boom! `ReferenceError: self is not defined`

Introducing google-protobuf to the workarounds of 1, 2 for 0.15.3 works fine, hence we have to stick with 0.15.3 for now.

Recap:
1. `0.15.3` with `output.format = esm` works with run-script & google-protobuf, with non-ootb-experience
2. `>0.15.3` with `output.format = cjs` works with run-script, fails with google-protobuf

### System Info

```Shell
System:
    OS: Linux 6.8 Exherbo
    CPU: (4) x64 Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz
    Memory: 9.00 GB / 15.52 GB
    Container: Yes
    Shell: 3.7.1 - /bin/fish
  Binaries:
    Node: 20.12.2 - /usr/host/bin/node
    npm: 10.5.0 - /usr/host/bin/npm
    pnpm: 9.4.0 - ~/.local/bin/pnpm
  npmPackages:
    @farmfe/core: ^1.2.5 => 1.2.5
wre232114 commented 4 days ago

i will take a look