Skip to content

Commit

Permalink
feat: use native esm (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
JounQin committed Aug 29, 2021
1 parent 0018dbc commit f38de5f
Show file tree
Hide file tree
Showing 29 changed files with 1,958 additions and 2,037 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-mugs-glow.md
@@ -0,0 +1,5 @@
---
"synckit": minor
---

feat: use native esm
1 change: 1 addition & 0 deletions .env
@@ -0,0 +1 @@
SYNCKIT_TS_ESM=1
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Expand Up @@ -46,7 +46,6 @@ jobs:
yarn build
yarn lint
yarn test
yarn test-worker
env:
EFF_NO_LINK_RULES: true
PARSER_NO_WATCH: true
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -91,7 +91,7 @@ It is about 20x faster than [`sync-threads`](https://github.com/lambci/sync-thre

And it's almost same as [`deasync`](https://github.com/abbr/deasync) but requires no native bindings or `node-gyp`.

See [benchmark](./benchmarks/benchmark.txt) for more details.
See [benchmark.cjs](./benchmarks/benchmark.cjs.txt) and [benchmark.esm](./benchmarks/benchmark.esm.txt) for more details.

You can try it with running `yarn benchmark` by yourself. [Here](./benchmarks/benchmark.js) is the benchmark source code.

Expand Down
96 changes: 96 additions & 0 deletions benchmarks/benchmark.cjs
@@ -0,0 +1,96 @@
// @ts-check

const { performance } = require('perf_hooks')

const RUN_TIMES = +process.env.RUN_TIMES || 1000

/**
* @param {string} name
* @typedef {{ loadTime:number,runTime:number, totalTime:number }} PerfResult
* @returns {PerfResult} Perf result
*/
const perfCase = name => {
const loadStartTime = performance.now()

const syncFn = require(`./${name}.cjs`)

const loadTime = performance.now() - loadStartTime

let i = RUN_TIMES

const runStartTime = performance.now()

while (i-- > 0) {
syncFn(__filename)
}

const runTime = performance.now() - runStartTime

return {
loadTime,
runTime,
totalTime: runTime + loadTime,
}
}

/**
* @param {string} text
* @returns {string} Kebab cased text
*/
const kebabCase = text =>
text.replace(/([A-Z]+)/, (_, $1) => '-' + $1.toLowerCase())

class Benchmark {
/**
* @param { Object.<string, PerfResult> } perfResults
*/
constructor(perfResults) {
const keys = Object.keys(perfResults)
const _baseKey = keys[0]
const baseKey = kebabCase(_baseKey)

const perfTypes = /** @type {Array<keyof PerfResult>} */ ([
'loadTime',
'runTime',
'totalTime',
])

for (const perfType of perfTypes) {
const basePerf = perfResults[_baseKey][perfType]
this[perfType] = keys.reduce((acc, key) => {
const perfResult = perfResults[key]
key = kebabCase(key)
return Object.assign(acc, {
[key]: perfResult[perfType].toFixed(2) + 'ms',
...(key === baseKey
? null
: {
[`perf ${key}`]: this.perf(basePerf, perfResult[perfType]),
}),
})
}, {})
}
}

/**
* @param {number} a
* @param {number} b
* @returns {string} perf description
*/
perf(a, b) {
return a === b
? 'same'
: a > b
? (a / b).toFixed(2) + 'x slower'
: (b / a).toFixed(2) + 'x faster'
}
}

console.table(
new Benchmark({
synckit: perfCase('synckit'),
syncThreads: perfCase('sync-threads'),
deasync: perfCase('deasync'),
native: perfCase('native'),
}),
)
8 changes: 8 additions & 0 deletions benchmarks/benchmark.cjs.txt
@@ -0,0 +1,8 @@
$ node benchmarks/benchmark.cjs
┌───────────┬────────────┬──────────────┬───────────────────┬────────────┬────────────────┬───────────┬─────────────────┐
│ (index) │ synckit │ sync-threads │ perf sync-threads │ deasync │ perf deasync │ native │ perf native │
├───────────┼────────────┼──────────────┼───────────────────┼────────────┼────────────────┼───────────┼─────────────────┤
│ loadTime │ '26.45ms' │ '1.61ms' │ '16.47x slower' │ '15.39ms' │ '1.72x slower' │ '0.35ms' │ '76.64x slower' │
│ runTime │ '256.15ms' │ '4884.80ms' │ '19.07x faster' │ '428.31ms' │ '1.67x faster' │ '35.98ms' │ '7.12x slower' │
│ totalTime │ '282.60ms' │ '4886.41ms' │ '17.29x faster' │ '443.70ms' │ '1.57x faster' │ '36.32ms' │ '7.78x slower' │
└───────────┴────────────┴──────────────┴───────────────────┴────────────┴────────────────┴───────────┴─────────────────┘
8 changes: 4 additions & 4 deletions benchmarks/benchmark.txt → benchmarks/benchmark.esm.txt
@@ -1,8 +1,8 @@
$ node benchmarks/benchmark
$ node benchmarks/benchmark.js
┌───────────┬────────────┬──────────────┬───────────────────┬────────────┬────────────────┬───────────┬─────────────────┐
│ (index) │ synckit │ sync-threads │ perf sync-threads │ deasync │ perf deasync │ native │ perf native │
├───────────┼────────────┼──────────────┼───────────────────┼────────────┼────────────────┼───────────┼─────────────────┤
│ loadTime │ '23.78ms' │ '1.34ms' │ '17.73x slower' │ '12.33ms' │ '1.93x slower' │ '0.32ms' │ '74.50x slower' │
│ runTime │ '202.66ms' │ '4184.60ms' │ '20.65x faster' │ '307.03ms' │ '1.51x faster' │ '30.71ms' │ '6.60x slower' │
│ totalTime │ '226.44ms' │ '4185.95ms' │ '18.49x faster' │ '319.36ms' │ '1.41x faster' │ '31.02ms' │ '7.30x slower' │
│ loadTime │ '41.02ms' │ '1.93ms' │ '21.31x slower' │ '14.68ms' │ '2.80x slower' │ '0.78ms' │ '52.48x slower' │
│ runTime │ '278.47ms' │ '4819.02ms' │ '17.31x faster' │ '420.87ms' │ '1.51x faster' │ '38.73ms' │ '7.19x slower' │
│ totalTime │ '319.49ms' │ '4820.94ms' │ '15.09x faster' │ '435.55ms' │ '1.36x faster' │ '39.51ms' │ '8.09x slower' │
└───────────┴────────────┴──────────────┴───────────────────┴────────────┴────────────────┴───────────┴─────────────────┘
34 changes: 22 additions & 12 deletions benchmarks/benchmark.js
@@ -1,18 +1,24 @@
// @ts-check

const { performance } = require('perf_hooks')
import { performance } from 'perf_hooks'
import { fileURLToPath } from 'url'

const RUN_TIMES = +process.env.RUN_TIMES || 1000

// @ts-expect-error -- no idea
const __filename = fileURLToPath(import.meta.url)

/**
* @param {string} name
* @typedef {{ loadTime:number,runTime:number, totalTime:number }} PerfResult
* @returns {PerfResult} Perf result
* @returns {Promise<PerfResult>} Perf result
*/
const perfCase = name => {
const perfCase = async name => {
const loadStartTime = performance.now()

const syncFn = require(`./${name}`)
const syncFn = (
await import(`./${name}.${name === 'synckit' ? 'js' : 'cjs'}`)
).default

const loadTime = performance.now() - loadStartTime

Expand Down Expand Up @@ -86,11 +92,15 @@ class Benchmark {
}
}

console.table(
new Benchmark({
synckit: perfCase('synckit'),
syncThreads: perfCase('sync-threads'),
deasync: perfCase('deasync'),
native: perfCase('native'),
}),
)
const main = async () => {
console.table(
new Benchmark({
synckit: await perfCase('synckit'),
syncThreads: await perfCase('sync-threads'),
deasync: await perfCase('deasync'),
native: await perfCase('native'),
}),
)
}

main()
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion benchmarks/sync-threads.js → benchmarks/sync-threads.cjs
Expand Up @@ -3,6 +3,6 @@ const { createSyncFn } = require('sync-threads')
/**
* @type {() => string}
*/
const syncFn = createSyncFn(require.resolve('./sync-threads.worker'))
const syncFn = createSyncFn(require.resolve('./sync-threads.worker.cjs'))

module.exports = syncFn
File renamed without changes.
8 changes: 8 additions & 0 deletions benchmarks/synckit.cjs
@@ -0,0 +1,8 @@
const { createSyncFn } = require('../lib/index.cjs')

/**
* @type {() => string}
*/
const syncFn = createSyncFn(require.resolve('./synckit.worker.cjs'))

module.exports = syncFn
10 changes: 7 additions & 3 deletions benchmarks/synckit.js
@@ -1,8 +1,12 @@
const { createSyncFn } = require('../lib')
import { createRequire } from 'module'

import { createSyncFn } from '../lib/index.js'

const cjsRequire = createRequire(import.meta.url)

/**
* @type {() => string}
*/
const syncFn = createSyncFn(require.resolve('./synckit.worker'))
const syncFn = createSyncFn(cjsRequire.resolve('./synckit.worker'))

module.exports = syncFn
export default syncFn
5 changes: 5 additions & 0 deletions benchmarks/synckit.worker.cjs
@@ -0,0 +1,5 @@
const fs = require('fs')

const { runAsWorker } = require('../lib/index.cjs')

runAsWorker(filename => fs.promises.readFile(filename, 'utf8'))
4 changes: 2 additions & 2 deletions benchmarks/synckit.worker.js
@@ -1,5 +1,5 @@
const fs = require('fs')
import fs from 'fs'

const { runAsWorker } = require('../lib')
import { runAsWorker } from '../lib/index.js'

runAsWorker(filename => fs.promises.readFile(filename, 'utf8'))
58 changes: 40 additions & 18 deletions package.json
@@ -1,15 +1,18 @@
{
"name": "synckit",
"version": "0.3.4",
"type": "module",
"description": "Perform async work synchronously in Node.js using `worker_threads`, or `child_process` as fallback, with first-class TypeScript support.",
"repository": "git+https://github.com/rx-ts/synckit.git",
"author": "JounQin <admin@1stg.me>",
"license": "MIT",
"engines": {
"node": ">=8.10"
"node": ">=12"
},
"exports": {
"import": "./lib/index.js",
"require": "./lib/index.cjs"
},
"main": "lib",
"module": "lib/es2015",
"types": "lib",
"files": [
"lib",
Expand All @@ -25,44 +28,51 @@
"synckit"
],
"scripts": {
"benchmark": "node benchmarks/benchmark",
"benchmark:export": "yarn benchmark > benchmarks/benchmark.txt",
"benchmark": "run-s benchmark:*",
"benchmark-export": "run-s benchmark-export:*",
"benchmark-export:cjs": "yarn benchmark:cjs > benchmarks/benchmark.cjs.txt",
"benchmark-export:esm": "yarn benchmark:esm> benchmarks/benchmark.esm.txt",
"benchmark:cjs": "node benchmarks/benchmark.cjs",
"benchmark:esm": "node benchmarks/benchmark.js",
"build": "run-p build:*",
"build:r": "r -f es2015",
"build:r": "r -f cjs",
"build:ts": "tsc -p src",
"jest": "node --experimental-vm-modules node_modules/.bin/jest --setupFiles dotenv/config",
"lint": "run-p lint:*",
"lint:es": "eslint . --cache -f friendly --max-warnings 10",
"lint:tsc": "tsc --noEmit",
"prepare": "simple-git-hooks && yarn-deduplicate --strategy fewer || exit 0",
"prerelease": "npm run build",
"pretest": "yarn build:ts",
"release": "clean-publish && changeset publish",
"test": "jest",
"test-worker": "ts-node test/test-worker-ts && node test/test-worker",
"test": "yarn jest",
"typecov": "type-coverage"
},
"dependencies": {
"tslib": "^2.3.0",
"tslib": "^2.3.1",
"uuid": "^8.3.2"
},
"devDependencies": {
"@1stg/lib-config": "^3.0.0",
"@1stg/lib-config": "^4.0.0",
"@changesets/changelog-github": "^0.4.0",
"@changesets/cli": "^2.16.0",
"@types/jest": "^26.0.24",
"@types/node": "^16.3.1",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.5",
"@types/uuid": "^8.3.1",
"clean-publish": "^2.1.1",
"deasync": "^0.1.21",
"deasync": "^0.1.23",
"enhanced-resolve": "^5.8.2",
"postcss": "^8.3.6",
"sync-threads": "^1.0.1",
"ts-expect": "^1.3.0",
"ts-jest": "^27.0.3",
"ts-node": "^10.1.0",
"type-coverage": "^2.17.3",
"typescript": "^4.2.4"
"ts-jest": "^27.0.5",
"ts-node": "^10.2.1",
"type-coverage": "^2.18.1",
"typescript": "^4.4.2"
},
"resolutions": {
"prettier": "^2.3.2"
"prettier": "^2.3.2",
"tslib": "^2.3.1"
},
"commitlint": {
"extends": "@1stg"
Expand All @@ -71,8 +81,20 @@
"preset": "ts-jest",
"testEnvironment": "node",
"collectCoverage": true,
"extensionsToTreatAsEsm": [
".ts"
],
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1",
"^synckit$": "<rootDir>/src"
},
"globals": {
"ts-jest": {
"useESM": true,
"tsconfig": {
"importHelpers": false
}
}
}
},
"prettier": "@1stg/prettier-config",
Expand Down

0 comments on commit f38de5f

Please sign in to comment.