Perform async work synchronously in Node.js/Bun using worker_threads
with first-class TypeScript and Yarn P'n'P support.
# yarn
yarn add synckit
# npm
npm i synckit
// 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
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
}
execArgv
same as envSYNCKIT_EXEC_ARGV
globalShims
: Similar like envSYNCKIT_GLOBAL_SHIMS
but much more flexible which can be aGlobalShim
Array
, seeGlobalShim
's definition for more detailstimeout
same as envSYNCKIT_TIMEOUT
transferList
: Please refer Node.jsworker_threads
documentationtsRunner
same as envSYNCKIT_TS_RUNNER
SYNCKIT_EXEC_ARGV
: List of node CLI options passed to the worker, split with comma,
. (default as[]
), see alsonode
docsSYNCKIT_GLOBAL_SHIMS
: Whether to enable the defaultDEFAULT_GLOBAL_SHIMS_PRESET
asglobalShims
SYNCKIT_TIMEOUT
:timeout
for performing the async job (no default)SYNCKIT_TS_RUNNER
: Which TypeScript runner to be used, it could be very useful for development, could be'ts-node' | 'esbuild-register' | 'esbuild-runner' | 'swc' | 'tsx'
,'ts-node'
is used by default, make sure you have installed them already
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
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.
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.
Please view esbuild-register
for its document
Please view esbuild-runner
for its document
Please view @swc-node/register
for its document
Please view tsx
for its document
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.
1stG | RxTS | UnTS |
---|---|---|
1stG | RxTS | UnTS |
---|---|---|
@cspell/eslint-plugin
astrojs-compiler-sync
eslint-plugin-prettier
eslint-plugin-prettier-vue
eslint-mdx
prettier-plugin-packagejson
jest-snapshot
This package is original inspired by esbuild
and sync-threads
.
Detailed changes for each release are documented in CHANGELOG.md.