egoist / tsup

The simplest and fastest way to bundle your TypeScript libraries.
https://tsup.egoist.dev
MIT License
8.99k stars 217 forks source link

Error: Worker terminated due to reaching memory limit: JS heap out of memory #875

Open WINOFFRG opened 1 year ago

WINOFFRG commented 1 year ago

Hi!

While building I am getting this error

DTS Build start
node:events:491
      throw er; // Unhandled 'error' event
      ^

Error [ERR_WORKER_OUT_OF_MEMORY]: Worker terminated due to reaching memory limit: JS heap out of memory
    at new NodeError (node:internal/errors:399:5)
    at [kOnExit] (node:internal/worker:277:26)
    at Worker.<computed>.onexit (node:internal/worker:199:20)
Emitted 'error' event on Worker instance at:
    at [kOnExit] (node:internal/worker:277:12)
    at Worker.<computed>.onexit (node:internal/worker:199:20) {
  code: 'ERR_WORKER_OUT_OF_MEMORY'
}

Node.js v18.14.2

I feel there is some issue with my tsconfig.json Here is the link to the current tsconfig which causes this issue https://github.com/WINOFFRG/limeplay/blob/c7b4342dc74cdbded43c0c39101eb8dd10bd98ac/packages/limeplay-core/tsconfig.json

Please check the root tsconfig.json as well! If I don't extend the root config to package config ./tsconfig.json to packages/limeplay-core/tsconfig.json with the below config

{
    "compilerOptions": {
        "target": "ESNext",
        "useDefineForClassFields": true,
        "lib": ["DOM", "DOM.Iterable", "ESNext"],
        "allowJs": true,
        "checkJs": false,
        "skipLibCheck": true,
        "esModuleInterop": false,
        "allowSyntheticDefaultImports": true,
        "strict": false,
        "forceConsistentCasingInFileNames": true,
        "module": "ESNext",
        "moduleResolution": "Node",
        "resolveJsonModule": true,
        "isolatedModules": false,
        "noEmit": true,
        "noEmitOnError": true,
        "jsx": "react-jsx",
        "declaration": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "noImplicitAny": true,
        "preserveConstEnums": true,
        "typeRoots": ["./src/types"]
    },
    "include": ["src", "../../@types"],
    "exclude": ["node_modules"]
}

The build succeeds but when extended with the config shared above in the URL, It fails. Here is the link to error from Actions

https://github.com/WINOFFRG/limeplay/actions/runs/4589372907/jobs/8104219650#step:4:224

Upvote & Fund

Fund with Polar

juniorwmr commented 1 year ago

Same here.

anhntcv commented 1 year ago

I have the same problem

Achaak commented 1 year ago
{
  "compilerOptions": {
      "target": "ESNext",
      "useDefineForClassFields": true,
      "lib": ["DOM", "DOM.Iterable", "ESNext"],
      "allowJs": true,
      "checkJs": false,
      "skipLibCheck": true,
      "esModuleInterop": false,
      "allowSyntheticDefaultImports": true,
      "strict": false,
      "forceConsistentCasingInFileNames": true,
      "module": "ESNext",
      "moduleResolution": "Node",
      "resolveJsonModule": true,
      "isolatedModules": false,
      "noEmit": true,
      "noEmitOnError": true,
      "jsx": "react-jsx",
      "declaration": true,
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "noImplicitAny": true,
      "preserveConstEnums": true,
      "typeRoots": ["./src/types"]
  },
  "include": ["src", "../../@types"],
  "exclude": ["node_modules"]
}

I have the same probleme but when I tested your tsconfig, it works. And I tested to merge with mine and the problem was "typeRoots": [] which was missing When I add this empty array in my configuration, it works.

anhntcv commented 1 year ago

thank you @Achaak , I tried with "typeRoots": [] and it fixed the error. RAM reaches 4GB threshold when build.

kysley commented 1 year ago

Wow! Thanks @Achaak. This also fixed the problem in our pipeline 🤯

coopbri commented 1 year ago

Unfortunately, I am still encountering this issue despite the workarounds above. I have a React component library with ~40 components and a single entry point (though I tested multiple entry points). The builds (ESM and CJS in my case) are fast, but the *.d.ts generation eventually OOMs after ~10 minutes. I also made sure I don't have any cyclic dependencies.

9vfQbg7z4ajrGQxR commented 11 months ago

same like @coopbri

toteto commented 10 months ago

Have the same issue on TS only library (not React involved), and not even that large. The DTS step in order to be successful has pulled 14GB memory from my machine, this is unacceptable for CI runners.

What I have tried but it didn't work:

Only thing that worked was downgrading to 6.6 as suggested.

@egoist @sxzz Do you have any idea what could be the issue here? Providing minimal reproducing example may be harder since it mostly happens in medium to large codebases.

toteto commented 10 months ago

Downgrading to 6.6 made me remove the top-level async logic from my tsup.config.js. This made my build work, but then I bumped the tsup version to 7.2 and by having no top-level async in the config, the memory requirement went down from 14GB to 4GB, bit more manageable by CI.

Looking more into the issues, found #1018 that is somewhat expected to solve this, but not sure since running the build, it still take around 4GB.

Probably part of my issue is (please confirm if true) that I am being lazy to define actual entry points so I wrote a method that fetches all the .ts files in the source and defines those as entry points. It also uses these entries to generate the package.json#exports. Reducing the set of entries to the actual entries reduces the memory footprint to ~2,5GB.

For reference, the build on tsup 6.6 takes <500MB with 1/10th of the time.

toteto commented 10 months ago

After bit of debugging decided to time the hooks execution times. As suspected the rollup dts plugin is the culprit with the hook for options that in my case took ~30s to execute. Will investigate further to find what exactly is the issue.

millerized commented 9 months ago

As an extra data point (same as @coopbri) I can confirm that something in v6.7.0 has created a performance regression -- both in speed and memory usage (OOM).

I tried v8.0.1 today and the problem still persists and seems worse now that my codebase is a little larger. Seems like this is most likely due to entry point count.

Probably part of my issue is (please confirm if true) that I am being lazy to define actual entry points so I wrote a method that fetches all the .ts files in the source and defines those as entry points.

@toteto I wouldn't say this is your issue because I have mine setup to do tsup src/**/**/index.ts .. etc which essentially creates an entry point for every component in my library (30). I do this intentionally to avoid huge barrel file exports because of perf issues in user land.

nolde commented 3 months ago

I have been using onSuccess hook to just use tsc to compile the types, while tsup takes care of code. This took any memory issues away, and allowed me to build .d.ts files for all internal files, allowing deep lib reference with exports. It fixed my memory issues during build.

// tsup.config.ts
import { copyFile } from 'node:fs/promises'
import { exec } from 'node:child_process'
import { promisify } from 'node:util'

import glob from 'tiny-glob'
import { defineConfig } from 'tsup'

const pexec = promisify(exec)

export default defineConfig({
  cjsInterop: true,
  clean: true,
  entry: ['src/**/*.ts', '!src/**/*.test.ts'],
  format: ['cjs', 'esm'],
  shims: true,
  sourcemap: false,
  splitting: true,
  target: 'node20',
  //
  async onSuccess () {
    try {
      await pexec('tsc --emitDeclarationOnly --declaration')
      const files = await glob('dist/**/*.d.ts')
      await Promise.all(files.map(file => copyFile(file, file.replace('.d.ts', '.d.mts')))) // or to `.d.cjs` for "type": "module" projects
    } catch (err) {
      console.error()
      console.error('Typescript compilation error:')
      console.error()
      console.error(err.stdout)
      throw err
    }
  }
})

Don't forget to add "outDir": "./dist" to your tsconfig.

tysonclugg commented 3 months ago

As per https://github.com/egoist/tsup/issues/920#issuecomment-2159611615 this may have been fixed upstream in Node v21 and above. Can someone please test and confirm if this is the case?

faithfulojebiyi commented 1 day ago

I have been using onSuccess hook to just use tsc to compile the types, while tsup takes care of code. This took any memory issues away, and allowed me to build .d.ts files for all internal files, allowing deep lib reference with exports. It fixed my memory issues during build.

// tsup.config.ts
import { copyFile } from 'node:fs/promises'
import { exec } from 'node:child_process'
import { promisify } from 'node:util'

import glob from 'tiny-glob'
import { defineConfig } from 'tsup'

const pexec = promisify(exec)

export default defineConfig({
  cjsInterop: true,
  clean: true,
  entry: ['src/**/*.ts', '!src/**/*.test.ts'],
  format: ['cjs', 'esm'],
  shims: true,
  sourcemap: false,
  splitting: true,
  target: 'node20',
  //
  async onSuccess () {
    try {
      await pexec('tsc --emitDeclarationOnly --declaration')
      const files = await glob('dist/**/*.d.ts')
      await Promise.all(files.map(file => copyFile(file, file.replace('.d.ts', '.d.mts')))) // or to `.d.cjs` for "type": "module" projects
    } catch (err) {
      console.error()
      console.error('Typescript compilation error:')
      console.error()
      console.error(err.stdout)
      throw err
    }
  }
})

Don't forget to add "outDir": "./dist" to your tsconfig.

Have you had any issues where ot generated wrong types