@rspack/core 2.0.0-rc.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,5 +16,199 @@ Tinypool is a fork of piscina. What we try to achieve in this library, is to eli
16
16
 
17
17
  _In case you need more tiny libraries like tinypool or tinyspy, please consider submitting an [RFC](https://github.com/tinylibs/rfcs)_
18
18
 
19
- ## Docs
20
- Read **[full docs](https://github.com/tinylibs/tinypool#readme)** on GitHub.
19
+ ## Example
20
+
21
+ ### Using `node:worker_threads`
22
+
23
+ #### Basic usage
24
+
25
+ ```js
26
+ // main.mjs
27
+ import Tinypool from 'tinypool'
28
+
29
+ const pool = new Tinypool({
30
+ filename: new URL('./worker.mjs', import.meta.url).href,
31
+ })
32
+ const result = await pool.run({ a: 4, b: 6 })
33
+ console.log(result) // Prints 10
34
+
35
+ // Make sure to destroy pool once it's not needed anymore
36
+ // This terminates all pool's idle workers
37
+ await pool.destroy()
38
+ ```
39
+
40
+ ```js
41
+ // worker.mjs
42
+ export default ({ a, b }) => {
43
+ return a + b
44
+ }
45
+ ```
46
+
47
+ #### Main thread <-> worker thread communication
48
+
49
+ <details>
50
+ <summary>See code</summary>
51
+
52
+ ```js
53
+ // main.mjs
54
+ import Tinypool from 'tinypool'
55
+ import { MessageChannel } from 'node:worker_threads'
56
+
57
+ const pool = new Tinypool({
58
+ filename: new URL('./worker.mjs', import.meta.url).href,
59
+ })
60
+ const { port1, port2 } = new MessageChannel()
61
+ const promise = pool.run({ port: port1 }, { transferList: [port1] })
62
+
63
+ port2.on('message', (message) => console.log('Main thread received:', message))
64
+ setTimeout(() => port2.postMessage('Hello from main thread!'), 1000)
65
+
66
+ await promise
67
+
68
+ port1.close()
69
+ port2.close()
70
+ ```
71
+
72
+ ```js
73
+ // worker.mjs
74
+ export default ({ port }) => {
75
+ return new Promise((resolve) => {
76
+ port.on('message', (message) => {
77
+ console.log('Worker received:', message)
78
+
79
+ port.postMessage('Hello from worker thread!')
80
+ resolve()
81
+ })
82
+ })
83
+ }
84
+ ```
85
+
86
+ </details>
87
+
88
+ ### Using `node:child_process`
89
+
90
+ #### Basic usage
91
+
92
+ <details>
93
+ <summary>See code</summary>
94
+
95
+ ```js
96
+ // main.mjs
97
+ import Tinypool from 'tinypool'
98
+
99
+ const pool = new Tinypool({
100
+ runtime: 'child_process',
101
+ filename: new URL('./worker.mjs', import.meta.url).href,
102
+ })
103
+ const result = await pool.run({ a: 4, b: 6 })
104
+ console.log(result) // Prints 10
105
+ ```
106
+
107
+ ```js
108
+ // worker.mjs
109
+ export default ({ a, b }) => {
110
+ return a + b
111
+ }
112
+ ```
113
+
114
+ </details>
115
+
116
+ #### Main process <-> worker process communication
117
+
118
+ <details>
119
+ <summary>See code</summary>
120
+
121
+ ```js
122
+ // main.mjs
123
+ import Tinypool from 'tinypool'
124
+
125
+ const pool = new Tinypool({
126
+ runtime: 'child_process',
127
+ filename: new URL('./worker.mjs', import.meta.url).href,
128
+ })
129
+
130
+ const messages = []
131
+ const listeners = []
132
+ const channel = {
133
+ onMessage: (listener) => listeners.push(listener),
134
+ postMessage: (message) => messages.push(message),
135
+ }
136
+
137
+ const promise = pool.run({}, { channel })
138
+
139
+ // Send message to worker
140
+ setTimeout(
141
+ () => listeners.forEach((listener) => listener('Hello from main process')),
142
+ 1000
143
+ )
144
+
145
+ // Wait for task to finish
146
+ await promise
147
+
148
+ console.log(messages)
149
+ // [{ received: 'Hello from main process', response: 'Hello from worker' }]
150
+ ```
151
+
152
+ ```js
153
+ // worker.mjs
154
+ export default async function run() {
155
+ return new Promise((resolve) => {
156
+ process.on('message', (message) => {
157
+ // Ignore Tinypool's internal messages
158
+ if (message?.__tinypool_worker_message__) return
159
+
160
+ process.send({ received: message, response: 'Hello from worker' })
161
+ resolve()
162
+ })
163
+ })
164
+ }
165
+ ```
166
+
167
+ </details>
168
+
169
+ ## API
170
+
171
+ We have a similar API to Piscina, so for more information, you can read Piscina's detailed [documentation](https://github.com/piscinajs/piscina#piscina---the-nodejs-worker-pool) and apply the same techniques here.
172
+
173
+ ### Tinypool specific APIs
174
+
175
+ #### Pool constructor options
176
+
177
+ - `isolateWorkers`: Disabled by default. Always starts with a fresh worker when running tasks to isolate the environment.
178
+ - `terminateTimeout`: Disabled by default. If terminating a worker takes `terminateTimeout` amount of milliseconds to execute, an error is raised.
179
+ - `maxMemoryLimitBeforeRecycle`: Disabled by default. When defined, the worker's heap memory usage is compared against this value after task has been finished. If the current memory usage exceeds this limit, worker is terminated and a new one is started to take its place. This option is useful when your tasks leak memory and you don't want to enable `isolateWorkers` option.
180
+ - `runtime`: Used to pick worker runtime. Default value is `worker_threads`.
181
+ - `worker_threads`: Runs workers in [`node:worker_threads`](https://nodejs.org/api/worker_threads.html). For `main thread <-> worker thread` communication you can use [`MessagePort`](https://nodejs.org/api/worker_threads.html#class-messageport) in the `pool.run()` method's [`transferList` option](https://nodejs.org/api/worker_threads.html#portpostmessagevalue-transferlist). See [example](#main-thread---worker-thread-communication).
182
+ - `child_process`: Runs workers in [`node:child_process`](https://nodejs.org/api/child_process.html). For `main thread <-> worker process` communication you can use `TinypoolChannel` in the `pool.run()` method's `channel` option. For filtering out the Tinypool's internal messages see `TinypoolWorkerMessage`. See [example](#main-process---worker-process-communication).
183
+ - `teardown`: name of the function in file that should be called before worker is terminated. Must be named exported.
184
+ - `serialization`: Specify the kind of serialization used for the `child_process` runtime. Possible values are `'json'` and `'advanced'`. See Node.js [Advanced serialization](https://nodejs.org/docs/latest/api/child_process.html#advanced-serialization) for more details.
185
+
186
+ #### Pool methods
187
+
188
+ - `cancelPendingTasks()`: Gracefully cancels all pending tasks without stopping or interfering with on-going tasks. This method is useful when your tasks may have side effects and should not be terminated forcefully during task execution. If your tasks don't have any side effects you may want to use [`{ signal }`](https://github.com/piscinajs/piscina#cancelable-tasks) option for forcefully terminating all tasks, including the on-going ones, instead.
189
+ - `recycleWorkers(options)`: Waits for all current tasks to finish and re-creates all workers. Can be used to force isolation imperatively even when `isolateWorkers` is disabled. Accepts `{ runtime }` option as argument.
190
+
191
+ #### Exports
192
+
193
+ - `workerId`: Each worker now has an id ( <= `maxThreads`) that can be imported from `tinypool` in the worker itself (or `process.__tinypool_state__.workerId`).
194
+
195
+ ## Authors
196
+
197
+ | <a href="https://github.com/Aslemammad"> <img width='150' src="https://avatars.githubusercontent.com/u/37929992?v=4" /><br> Mohammad Bagher </a> |
198
+ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
199
+
200
+ ## Sponsors
201
+
202
+ Your sponsorship can make a huge difference in continuing our work in open source!
203
+
204
+ <p align="center">
205
+ <a href="https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg">
206
+ <img src='https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg'/>
207
+ </a>
208
+ </p>
209
+
210
+ ## Credits
211
+
212
+ [The Vitest team](https://vitest.dev/) for giving me the chance of creating and maintaing this project for vitest.
213
+
214
+ [Piscina](https://github.com/piscinajs/piscina), because Tinypool is not more than a friendly fork of piscina.
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { MessagePort, TransferListItem } from "node:worker_threads";
3
3
  import { EventEmitterAsyncResource } from "node:events";
4
+ import { SerializationType } from "node:child_process";
4
5
 
5
6
  //#region src/common.d.ts
6
7
  /** Channel for communicating between main thread and workers */
@@ -22,6 +23,7 @@ interface TinypoolWorker {
22
23
  resourceLimits?: any;
23
24
  workerData: TinypoolData;
24
25
  trackUnmanagedFds?: boolean;
26
+ serialization?: SerializationType;
25
27
  }): void;
26
28
  terminate(): Promise<any>;
27
29
  postMessage(message: any, transferListItem?: TransferListItem[]): void;
@@ -144,6 +146,7 @@ interface Options {
144
146
  trackUnmanagedFds?: boolean;
145
147
  isolateWorkers?: boolean;
146
148
  teardown?: string;
149
+ serialization?: SerializationType;
147
150
  }
148
151
  interface FilledOptions extends Options {
149
152
  filename: string | null;
@@ -8,48 +8,9 @@ import { inspect, types } from "node:util";
8
8
  import assert from "node:assert";
9
9
  import { performance } from "node:perf_hooks";
10
10
  import { readFileSync } from "node:fs";
11
- import os from "node:os";
12
- import childProcess, { fork } from "node:child_process";
11
+ import { availableParallelism } from "node:os";
12
+ import { fork } from "node:child_process";
13
13
 
14
- //#region src/physicalCpuCount.ts
15
- function exec(command) {
16
- const output = childProcess.execSync(command, {
17
- encoding: "utf8",
18
- stdio: [
19
- null,
20
- null,
21
- null
22
- ]
23
- });
24
- return output;
25
- }
26
- let amount;
27
- try {
28
- const platform = os.platform();
29
- if (platform === "linux") {
30
- const output1 = exec("cat /proc/cpuinfo | grep \"physical id\" | sort |uniq | wc -l");
31
- const output2 = exec("cat /proc/cpuinfo | grep \"core id\" | sort | uniq | wc -l");
32
- const physicalCpuAmount = parseInt(output1.trim(), 10);
33
- const physicalCoreAmount = parseInt(output2.trim(), 10);
34
- amount = physicalCpuAmount * physicalCoreAmount;
35
- } else if (platform === "darwin") {
36
- const output = exec("sysctl -n hw.physicalcpu_max");
37
- amount = parseInt(output.trim(), 10);
38
- } else if (platform === "win32") throw new Error();
39
- else {
40
- const cores = os.cpus().filter(function(cpu, index) {
41
- const hasHyperthreading = cpu.model.includes("Intel");
42
- const isOdd = index % 2 === 1;
43
- return !hasHyperthreading || isOdd;
44
- });
45
- amount = cores.length;
46
- }
47
- } catch {
48
- amount = os.cpus().length;
49
- }
50
- if (amount === 0) amount = os.cpus().length;
51
-
52
- //#endregion
53
14
  //#region src/runtime/thread-worker.ts
54
15
  var ThreadWorker = class {
55
16
  name = "ThreadWorker";
@@ -188,7 +149,7 @@ function hasUnref(stream) {
188
149
 
189
150
  //#endregion
190
151
  //#region src/index.ts
191
- const cpuCount = amount;
152
+ const cpuCount = availableParallelism();
192
153
  function onabort(abortSignal, listener) {
193
154
  if ("addEventListener" in abortSignal) abortSignal.addEventListener("abort", listener, { once: true });
194
155
  else abortSignal.once("abort", listener);
@@ -549,7 +510,8 @@ var ThreadPool = class {
549
510
  execArgv: this.options.execArgv,
550
511
  resourceLimits: this.options.resourceLimits,
551
512
  workerData: [tinypoolPrivateData, this.options.workerData],
552
- trackUnmanagedFds: this.options.trackUnmanagedFds
513
+ trackUnmanagedFds: this.options.trackUnmanagedFds,
514
+ serialization: this.options.serialization
553
515
  });
554
516
  const onMessage = (message$1) => {
555
517
  const { taskId, result } = message$1;
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "tinypool",
3
3
  "type": "module",
4
- "version": "1.1.1",
5
- "packageManager": "pnpm@9.0.6",
4
+ "version": "2.1.0",
6
5
  "description": "A minimal and tiny Node.js Worker Thread Pool implementation, a fork of piscina, but with fewer features",
7
6
  "license": "MIT",
8
7
  "homepage": "https://github.com/tinylibs/tinypool#readme",
@@ -31,9 +30,26 @@
31
30
  "files": [
32
31
  "dist"
33
32
  ],
34
- "pnpm": {
35
- "overrides": {
36
- "vitest>tinypool": "link:./"
37
- }
33
+ "devDependencies": {
34
+ "@types/node": "^20.12.8",
35
+ "clean-publish": "^3.4.4",
36
+ "eslint": "^9.4.0",
37
+ "eslint-config-prettier": "^9.1.0",
38
+ "eslint-plugin-prettier": "^5.1.3",
39
+ "eslint-plugin-unicorn": "^53.0.0",
40
+ "prettier": "^3.3.2",
41
+ "tsdown": "^0.11.3",
42
+ "typescript": "^5.4.5",
43
+ "typescript-eslint": "^7.13.0",
44
+ "vite": "^5.2.11",
45
+ "vitest": "^4.0.1"
46
+ },
47
+ "scripts": {
48
+ "test": "vitest",
49
+ "bench": "vitest bench",
50
+ "dev": "tsdown --watch ./src",
51
+ "build": "tsdown",
52
+ "lint": "eslint --max-warnings=0",
53
+ "typecheck": "tsc --noEmit"
38
54
  }
39
55
  }
@@ -7,6 +7,7 @@ export interface RscManifestExport {
7
7
  id: string;
8
8
  name: string;
9
9
  chunks: string[];
10
+ cssFiles?: string[];
10
11
  async?: boolean;
11
12
  }
12
13
  /** Map of export name to manifest export. */
package/dist/index.js CHANGED
@@ -6865,7 +6865,7 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis
6865
6865
  return output.wasmLoading && enabledWasmLoadingTypes.add(output.wasmLoading), output.workerWasmLoading && enabledWasmLoadingTypes.add(output.workerWasmLoading), forEachEntry((desc)=>{
6866
6866
  desc.wasmLoading && enabledWasmLoadingTypes.add(desc.wasmLoading);
6867
6867
  }), Array.from(enabledWasmLoadingTypes);
6868
- }), D(output, 'bundlerInfo', {}), 'object' == typeof output.bundlerInfo && (D(output.bundlerInfo, 'version', "2.0.0-rc.3"), D(output.bundlerInfo, 'bundler', 'rspack'), D(output.bundlerInfo, 'force', !1));
6868
+ }), D(output, 'bundlerInfo', {}), 'object' == typeof output.bundlerInfo && (D(output.bundlerInfo, 'version', "2.0.0"), D(output.bundlerInfo, 'bundler', 'rspack'), D(output.bundlerInfo, 'force', !1));
6869
6869
  }, applyExternalsPresetsDefaults = (externalsPresets, { targetProperties, buildHttp, outputModule })=>{
6870
6870
  let isUniversal = (key)=>!!(outputModule && targetProperties && null === targetProperties[key]);
6871
6871
  D(externalsPresets, 'web', !buildHttp && targetProperties && (targetProperties.web || isUniversal('node'))), D(externalsPresets, 'node', targetProperties && (targetProperties.node || isUniversal('node'))), D(externalsPresets, 'electron', targetProperties && targetProperties.electron || isUniversal('electron')), D(externalsPresets, 'electronMain', targetProperties && !!targetProperties.electron && (targetProperties.electronMain || isUniversal('electronMain'))), D(externalsPresets, 'electronPreload', targetProperties && !!targetProperties.electron && (targetProperties.electronPreload || isUniversal('electronPreload'))), D(externalsPresets, 'electronRenderer', targetProperties && !!targetProperties.electron && (targetProperties.electronRenderer || isUniversal('electronRenderer'))), D(externalsPresets, 'nwjs', targetProperties && (targetProperties.nwjs || isUniversal('nwjs')));
@@ -8119,7 +8119,7 @@ class MultiStats {
8119
8119
  obj.children = this.stats.map((stat, idx)=>{
8120
8120
  let obj = stat.toJson(childOptions.children[idx]), compilationName = stat.compilation.name;
8121
8121
  return obj.name = compilationName && makePathsRelative(childOptions.context, compilationName, stat.compilation.compiler.root), obj;
8122
- }), childOptions.version && (obj.rspackVersion = "2.0.0-rc.3", obj.version = "5.75.0"), childOptions.hash && (obj.hash = obj.children.map((j)=>j.hash).join(''));
8122
+ }), childOptions.version && (obj.rspackVersion = "2.0.0", obj.version = "5.75.0"), childOptions.hash && (obj.hash = obj.children.map((j)=>j.hash).join(''));
8123
8123
  let mapError = (j, obj)=>({
8124
8124
  ...obj,
8125
8125
  compilerPath: obj.compilerPath ? `${j.name}.${obj.compilerPath}` : j.name
@@ -9390,7 +9390,7 @@ let iterateConfig = (config, options, fn)=>{
9390
9390
  object.hash = context.getStatsCompilation(compilation).hash;
9391
9391
  },
9392
9392
  version: (object)=>{
9393
- object.version = "5.75.0", object.rspackVersion = "2.0.0-rc.3";
9393
+ object.version = "5.75.0", object.rspackVersion = "2.0.0";
9394
9394
  },
9395
9395
  env: (object, _compilation, _context, { _env })=>{
9396
9396
  object.env = _env;
@@ -11048,7 +11048,7 @@ class TraceHookPlugin {
11048
11048
  });
11049
11049
  }
11050
11050
  }
11051
- let CORE_VERSION = "2.0.0-rc.3", VFILES_BY_COMPILER = new WeakMap();
11051
+ let CORE_VERSION = "2.0.0", VFILES_BY_COMPILER = new WeakMap();
11052
11052
  class VirtualModulesPlugin {
11053
11053
  #staticModules;
11054
11054
  #compiler;
@@ -13351,7 +13351,7 @@ async function transform(source, options) {
13351
13351
  let _options = JSON.stringify(options || {});
13352
13352
  return binding_default().transform(source, _options);
13353
13353
  }
13354
- let exports_rspackVersion = "2.0.0-rc.3", exports_version = "5.75.0", exports_WebpackError = Error, exports_config = {
13354
+ let exports_rspackVersion = "2.0.0", exports_version = "5.75.0", exports_WebpackError = Error, exports_config = {
13355
13355
  getNormalizedRspackOptions: getNormalizedRspackOptions,
13356
13356
  applyRspackOptionsDefaults: applyRspackOptionsDefaults,
13357
13357
  getNormalizedWebpackOptions: getNormalizedRspackOptions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rspack/core",
3
- "version": "2.0.0-rc.3",
3
+ "version": "2.0.0",
4
4
  "webpackVersion": "5.75.0",
5
5
  "license": "MIT",
6
6
  "description": "Fast Rust-based bundler for the web with a modernized webpack API",
@@ -38,9 +38,9 @@
38
38
  },
39
39
  "devDependencies": {
40
40
  "@ast-grep/napi": "^0.42.1",
41
- "@napi-rs/wasm-runtime": "1.1.3",
41
+ "@napi-rs/wasm-runtime": "1.1.4",
42
42
  "@rsbuild/plugin-node-polyfill": "^1.4.4",
43
- "@rslib/core": "0.21.0",
43
+ "@rslib/core": "0.21.2",
44
44
  "@rspack/lite-tapable": "1.1.0",
45
45
  "@swc/types": "0.1.26",
46
46
  "@types/node": "^20.19.39",
@@ -53,13 +53,13 @@
53
53
  "memfs": "4.53.0",
54
54
  "open": "^11.0.0",
55
55
  "prebundle": "^1.6.4",
56
- "tinypool": "^1.1.1",
57
- "typescript": "^6.0.2",
56
+ "tinypool": "^2.1.0",
57
+ "typescript": "^6.0.3",
58
58
  "watchpack": "2.4.4",
59
59
  "webpack-sources": "3.3.4"
60
60
  },
61
61
  "dependencies": {
62
- "@rspack/binding": "2.0.0-rc.3"
62
+ "@rspack/binding": "2.0.0"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0",