Détail du package

synckit

un-ts61mMIT0.11.4

Perform async work synchronously in Node.js using worker_threads with first-class TypeScript support.

deasync, make-synchronized, make-synchronous, sync

readme

synckit

GitHub Actions Workflow Status Codecov type-coverage CodeRabbit Pull Request Reviews npm GitHub Release

Conventional Commits Renovate enabled JavaScript Style Guide Code Style: Prettier changesets

Perform async work synchronously in Node.js/Bun using worker_threads with first-class TypeScript and Yarn P'n'P support.

TOC

Usage

Install

# yarn
yarn add synckit

# npm
npm i synckit

API

// runner.js
import { createSyncFn } from 'synckit'

// the worker path must be absolute
const syncFn = createSyncFn(require.resolve('./worker'), {
  tsRunner: 'tsx', // optional, can be `'node' | 'ts-node' | 'esbuild-register' | 'esbuild-runner' | 'tsx'`
})

// do whatever you want, you will get the result synchronously!
const result = syncFn(...args)
// worker.js
import { runAsWorker } from 'synckit'

runAsWorker(async (...args) => {
  // do expensive work
  return result
})

You must make sure, the result is serializable by Structured Clone Algorithm

Types

export interface GlobalShim {
  moduleName: string
  /** `undefined` means side effect only */
  globalName?: string
  /**
   * 1. `undefined` or empty string means `default`, for example:
   *
   * ```js
   * import globalName from 'module-name'
   * ```
   *
   * 2. `null` means namespaced, for example:
   *
   * ```js
   * import * as globalName from 'module-name'
   * ```
   */
  named?: string | null
  /**
   * If not `false`, the shim will only be applied when the original
   * `globalName` unavailable, for example you may only want polyfill
   * `globalThis.fetch` when it's unavailable natively:
   *
   * ```js
   * import fetch from 'node-fetch'
   *
   * if (!globalThis.fetch) {
   *   globalThis.fetch = fetch
   * }
   * ```
   */
  conditional?: boolean
}

Options

  1. execArgv same as env SYNCKIT_EXEC_ARGV
  2. globalShims: Similar like env SYNCKIT_GLOBAL_SHIMS but much more flexible which can be a GlobalShim Array, see GlobalShim's definition for more details
  3. timeout same as env SYNCKIT_TIMEOUT
  4. transferList: Please refer Node.js worker_threads documentation
  5. tsRunner same as env SYNCKIT_TS_RUNNER

Envs

  1. SYNCKIT_EXEC_ARGV: List of node CLI options passed to the worker, split with comma ,. (default as []), see also node docs
  2. SYNCKIT_GLOBAL_SHIMS: Whether to enable the default DEFAULT_GLOBAL_SHIMS_PRESET as globalShims
  3. SYNCKIT_TIMEOUT: timeout for performing the async job (no default)
  4. SYNCKIT_TS_RUNNER: Which TypeScript runner to be used, it could be very useful for development, could be 'node' | 'ts-node' | 'esbuild-register' | 'esbuild-runner' | 'oxc' | 'swc' | 'tsx', node or ts-node will be used by default accordingly, make sure you have installed them already

TypeScript

node (Default, Node 22.6+)

On recent Node versions, you may select this runner to execute your worker file (a .ts file) in the native runtime.

As of Node v23.6, this feature is supported out of the box. For Node >=22.6 <23.6, this feature is supported via --experimental-strip-types flag. Visit the documentation to learn more.

When synckit detects the process to be running with supported Node versions (>=22.6), it will execute the worker file with the node runner by default, you can disable this behavior by setting --no-experimental-strip-types flag via NODE_OPTIONS env or cli arg.

bun (Default, Bun)

Bun supports TypeScript natively.

When synckit detects the process to be running with Bun, it will execute the worker file with the bun runner by default.

In this case, synckit doesn't do anything to the worker itself, it just passes through the worker directly.

ts-node (Default)

Prior to Node v22.6, you may want to use ts-node to execute your worker file (a .ts file).

If you want to use a custom tsconfig as project instead of default tsconfig.json, use TS_NODE_PROJECT env. Please view ts-node for more details.

If you want to integrate with tsconfig-paths, please view ts-node for more details.

esbuild-register

Please view esbuild-register for its document

esbuild-runner

Please view esbuild-runner for its document

oxc

Please view @oxc-node/core for its document

swc

Please view @swc-node/register for its document

tsx

Please view tsx for its document

Benchmark

The following are the benchmark results of synckit against other libraries with Node.js v20.19.0 on my personal MacBook Pro with 64G M1 Max:

# cjs
┌───────────┬────────────┬──────────────┬───────────────────┬─────────────┬────────────────┬───────────────────┬────────────────────────┬───────────┬─────────────────┐
│ (index)   │ synckit    │ sync-threads │ perf sync-threads │ deasync     │ perf deasync   │ make-synchronized │ perf make-synchronized │ native    │ perf native     │
├───────────┼────────────┼──────────────┼───────────────────┼─────────────┼────────────────┼───────────────────┼────────────────────────┼───────────┼─────────────────┤
│ loadTime  │ '17.26ms'  │ '1.49ms'     │ '11.57x slower'   │ '146.55ms'  │ '8.49x faster' │ '1025.77ms'       │ '59.42x faster'        │ '0.29ms'  │ '59.71x slower' │
│ runTime   │ '143.12ms' │ '3689.15ms'  │ '25.78x faster'   │ '1221.11ms' │ '8.53x faster' │ '2842.50ms'       │ '19.86x faster'        │ '12.64ms' │ '11.33x slower' │
│ totalTime │ '160.38ms' │ '3690.64ms'  │ '23.01x faster'   │ '1367.66ms' │ '8.53x faster' │ '3868.27ms'       │ '24.12x faster'        │ '12.93ms' │ '12.41x slower' │
└───────────┴────────────┴──────────────┴───────────────────┴─────────────┴────────────────┴───────────────────┴────────────────────────┴───────────┴─────────────────┘
# esm
┌───────────┬────────────┬──────────────┬───────────────────┬─────────────┬────────────────┬───────────────────┬────────────────────────┬───────────┬─────────────────┐
│ (index)   │ synckit    │ sync-threads │ perf sync-threads │ deasync     │ perf deasync   │ make-synchronized │ perf make-synchronized │ native    │ perf native     │
├───────────┼────────────┼──────────────┼───────────────────┼─────────────┼────────────────┼───────────────────┼────────────────────────┼───────────┼─────────────────┤
│ loadTime  │ '23.88ms'  │ '2.03ms'     │ '11.75x slower'   │ '70.95ms'   │ '2.97x faster' │ '400.24ms'        │ '16.76x faster'        │ '0.44ms'  │ '54.70x slower' │
│ runTime   │ '139.56ms' │ '3570.12ms'  │ '25.58x faster'   │ '1150.99ms' │ '8.25x faster' │ '3484.04ms'       │ '24.96x faster'        │ '12.98ms' │ '10.75x slower' │
│ totalTime │ '163.44ms' │ '3572.15ms'  │ '21.86x faster'   │ '1221.93ms' │ '7.48x faster' │ '3884.28ms'       │ '23.77x faster'        │ '13.42ms' │ '12.18x slower' │
└───────────┴────────────┴──────────────┴───────────────────┴─────────────┴────────────────┴───────────────────┴────────────────────────┴───────────┴─────────────────┘

See benchmark.cjs and benchmark.esm for more details.

You can try it with running yarn benchmark by yourself. Here is the benchmark source code.

Sponsors and Backers

Sponsors and Backers

Sponsors

1stG RxTS UnTS
1stG Open Collective sponsors RxTS Open Collective sponsors UnTS Open Collective sponsors

Backers

1stG RxTS UnTS
1stG Open Collective backers RxTS Open Collective backers UnTS Open Collective backers

Who are using synckit

Acknowledgements

This package is original inspired by esbuild and sync-threads.

Changelog

Detailed changes for each release are documented in CHANGELOG.md.

License

MIT © JounQin@1stG.me

changelog

synckit

0.11.4

Patch Changes

0.11.3

Patch Changes

0.11.2

Patch Changes

0.11.1

Patch Changes

  • #224 0966d2a Thanks @JounQin! - fix: add missing MessageChannel from node:worker_threads for Node 14 compatibility

0.11.0

Minor Changes

  • #222 59f7432 Thanks @JounQin! - feat: add oxc ts runner support, correct swc ts runner with --import flag support

Patch Changes

  • #222 59f7432 Thanks @JounQin! - fix: .cjs should never be treated as ESM

  • #219 79fa3a2 Thanks @JounQin! - refactor: split into chunk files, add module-sync entry

  • #222 59f7432 Thanks @JounQin! - fix: only consider process.features.typescript when --no-experimental-strip-types flag enabled

0.10.3

Patch Changes

0.10.2

Minor Changes

Patch Changes

0.10.1

Patch Changes

  • #204 e13a68a Thanks @nwidynski! - fix: add support for type transformations to node runner, clarify correct Node versions support

0.10.0

Minor Changes

  • #199 7a5f1bd Thanks @nwidynski! - feat: add support for --experimental-strip-types

    Introducing the node runner, which will replace ts-node as the new default:

    • when running on Node 22 with the --experimental-strip-types flag enabled via NODE_OPTIONS env or cli args
    • or when running on Node 23+ without --no-experimental-strip-types flag enabled via NODE_OPTIONS env or cli args

    An error will be thrown when attempting to run with node on unsupported versions (<22). On these versions, the default runner remains ts-node when available.

0.9.2

Patch Changes

0.9.1

Patch Changes

0.9.0

Minor Changes

  • #154 2541a1e Thanks @onigoetz! - feat!: use a single SharedArrayBuffer, remove useless bufferSize option

Patch Changes

0.8.8

Patch Changes

  • #148 7b6a0eb Thanks @JounQin! - feat: migrate @pkgr/utils to lite @pkgr/core - This will make the whole package much more smaller

0.8.7

Patch Changes

  • #145 b2affa0 Thanks @JounQin! - feat: add new globalShims option, what means you can env SYNCKIT_GLOBAL_SHIMS=1 to enable auto polyfilling for some modules, for example: fetch from node-fetch, performance from node:perf_hooks.

    You can also pass a custom globalShims option as GlobalShim Array to custom your own shims:

    export interface GlobalShim {
      moduleName: string
      /** `undefined` means side effect only */
      globalName?: string
      /**
       * 1. `undefined` or empty string means `default`, for example:
       *
       * ```js
       * import globalName from 'module-name'
       * ```
       *
       * 2. `null` means namespaced, for example:
       *
       * ```js
       * import * as globalName from 'module-name'
       * ```
       */
      named?: string | null
      /**
       * If not `false`, the shim will only be applied when the original
       * `globalName` unavailable, for example you may only want polyfill
       * `globalThis.fetch` when it's unavailable natively:
       *
       * ```js
       * import fetch from 'node-fetch'
       *
       * if (!globalThis.fetch) {
       *   globalThis.fetch = fetch
       * }
       * ```
       */
      conditional?: boolean
    }
    

    You can aslo reuse the exported DEFAULT_GLOBAL_SHIMS_PRESET for extanding:

    import { DEFAULT_GLOBAL_SHIMS_PRESET, createSyncFn } from 'synckit'
    
    const syncFn = createSyncFn(require.resolve('./worker'), {
      globalShims: [
        ...DEFAULT_GLOBAL_SHIMS_PRESET,
        // your own shim here
      ],
    })
    

0.8.6

Patch Changes

0.8.5

Patch Changes

0.8.4

Patch Changes

0.8.3

Patch Changes

0.8.2

Patch Changes

0.8.1

Patch Changes

0.8.0

Minor Changes

0.7.3

Patch Changes

0.7.2

Patch Changes

  • 1101ede Thanks @JounQin! - chore: add donate and funding fields, update node engine field

0.7.1

Patch Changes

  • f098d29 Thanks @JounQin! - fix: known Windows issues

  • c53d9dc Thanks @JounQin! - feat: use workerPath as URL for Windows

    related mdx-js/eslint-mdx#389

0.7.0

Minor Changes

0.6.2

Patch Changes

0.6.1

Patch Changes

0.6.0

Minor Changes

0.5.0

Minor Changes

0.4.0

Minor Changes

0.3.4

Patch Changes

  • #39 0698572 Thanks @JounQin! - fix: test whether receiveMessageOnPort available for --experimental-worker

0.3.3

Patch Changes

0.3.2

Patch Changes

0.3.1

Patch Changes

0.3.0

Minor Changes

0.2.0

Minor Changes

0.1.6

Patch Changes

0.1.4

Patch Changes

  • #9 cad2e05 Thanks @JounQin! - fix: try to fix clean-publish + changeset publish again

0.1.2

Patch Changes

0.1.1

Patch Changes

0.1.0

Minor Changes