@octanejs/rspack-plugin 0.1.33 → 0.1.35
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.
- package/README.md +9 -1
- package/package.json +3 -3
- package/src/finalize-loader.js +33 -0
- package/src/parallel-loader.js +34 -0
- package/src/plugin.js +19 -1
- package/src/shared.js +26 -1
- package/types/index.d.ts +7 -0
- package/types/options.test-d.ts +10 -0
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ export default {
|
|
|
26
26
|
The plugin:
|
|
27
27
|
|
|
28
28
|
- adds `.tsrx`, `.tsx`, and `.ts` resolution;
|
|
29
|
-
-
|
|
29
|
+
- compiles local and linked/raw dependency sources in parallel Rspack workers;
|
|
30
30
|
- selects client or server codegen from Rspack's `target` (or an explicit
|
|
31
31
|
`environment` option);
|
|
32
32
|
- resolves every exact bare `octane` import to one client runtime, or to
|
|
@@ -47,6 +47,14 @@ Set `transpile: false` when an existing rule already strips TypeScript. Set
|
|
|
47
47
|
Set `profile: true` to produce a client profiling build; server compilations
|
|
48
48
|
always keep profiling disabled.
|
|
49
49
|
|
|
50
|
+
Octane uses up to four Rspack loader workers by default. Set `parallel: false`
|
|
51
|
+
to compile on the main thread, or provide `parallel: { maxWorkers: 2 }` to
|
|
52
|
+
request a different worker-pool limit. Rspack shares one loader worker pool
|
|
53
|
+
per process, so the first parallel loader determines its effective size.
|
|
54
|
+
Source maps, module layers, compiler metadata, and watched package manifests
|
|
55
|
+
are preserved in both modes. Worker startup has a fixed cost, so very small
|
|
56
|
+
builds may be faster with `parallel: false`.
|
|
57
|
+
|
|
50
58
|
Set `strong: true` to reject state updates during rendering, state updates from
|
|
51
59
|
effects, and ref writes during rendering in your application code:
|
|
52
60
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/rspack-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -45,13 +45,13 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@rspack/core": "^2.0.0",
|
|
48
|
-
"octane": "0.1.
|
|
48
|
+
"octane": "0.1.40"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@rspack/core": "^2.1.4",
|
|
52
52
|
"@types/node": "^24.13.3",
|
|
53
53
|
"vitest": "^4.1.10",
|
|
54
|
-
"octane": "0.1.
|
|
54
|
+
"octane": "0.1.40"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"test": "vitest run --config vitest.config.js"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rspack does not copy a module's layer or buildInfo into parallel-loader
|
|
3
|
+
* workers. Pitch data is structured-cloned into the worker before compilation.
|
|
4
|
+
*/
|
|
5
|
+
export function pitch() {
|
|
6
|
+
this.data ??= {};
|
|
7
|
+
this.data.octaneLayer = this._module?.layer ?? null;
|
|
8
|
+
if (this._module?.buildInfo && typeof this._module.buildInfo === 'object') {
|
|
9
|
+
delete this._module.buildInfo.octane;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Restore worker-owned Octane metadata and missing-file watches on the main thread. */
|
|
14
|
+
export default function finalizeOctaneLoader(source, sourceMap, metadata) {
|
|
15
|
+
const result = metadata?.__octaneParallelLoader;
|
|
16
|
+
if (result?.buildInfo) {
|
|
17
|
+
if (!this._module.buildInfo || typeof this._module.buildInfo !== 'object') {
|
|
18
|
+
this._module.buildInfo = {};
|
|
19
|
+
}
|
|
20
|
+
this._module.buildInfo.octane = result.buildInfo;
|
|
21
|
+
}
|
|
22
|
+
for (const dependency of result?.missingDependencies ?? []) {
|
|
23
|
+
this.addMissingDependency(dependency);
|
|
24
|
+
}
|
|
25
|
+
if (metadata && typeof metadata === 'object') {
|
|
26
|
+
const { __octaneParallelLoader, ...remainingMetadata } = metadata;
|
|
27
|
+
if (Object.keys(remainingMetadata).length > 0) {
|
|
28
|
+
this.callback(null, source, sourceMap, remainingMetadata);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
this.callback(null, source, sourceMap);
|
|
33
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import octaneLoader from './loader.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Run the unchanged public Octane loader inside Rspack's worker pool. Rspack
|
|
5
|
+
* proxies resolution, ordinary file dependencies, warnings, and asynchronous
|
|
6
|
+
* callbacks, but omits module layer/buildInfo and addMissingDependency.
|
|
7
|
+
*/
|
|
8
|
+
export default function parallelOctaneLoader(source, sourceMap) {
|
|
9
|
+
const missingDependencies = [];
|
|
10
|
+
const module = this._module;
|
|
11
|
+
const finalizer = this.loaders[this.loaderIndex - 1];
|
|
12
|
+
module.layer = finalizer?.loaderItem?.data?.octaneLayer ?? undefined;
|
|
13
|
+
|
|
14
|
+
const callback = this.callback.bind(this);
|
|
15
|
+
const async = this.async.bind(this);
|
|
16
|
+
const withWorkerMetadata = (finish) => (error, output, outputMap, metadata) => {
|
|
17
|
+
if (error) {
|
|
18
|
+
finish(error);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
finish(null, output, outputMap, {
|
|
22
|
+
...(metadata ?? {}),
|
|
23
|
+
__octaneParallelLoader: {
|
|
24
|
+
buildInfo: module.buildInfo?.octane ?? null,
|
|
25
|
+
missingDependencies,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
this.addMissingDependency = (dependency) => missingDependencies.push(dependency);
|
|
31
|
+
this.callback = withWorkerMetadata(callback);
|
|
32
|
+
this.async = () => withWorkerMetadata(async());
|
|
33
|
+
return octaneLoader.call(this, source, sourceMap);
|
|
34
|
+
}
|
package/src/plugin.js
CHANGED
|
@@ -18,6 +18,9 @@ const PLUGIN_NAME = 'OctaneRspackPlugin';
|
|
|
18
18
|
const PROFILE_DEFINE = '__OCTANE_PROFILE_ENABLED__';
|
|
19
19
|
const PLUGIN_VERSION = createRequire(import.meta.url)('../package.json').version;
|
|
20
20
|
const loaderPath = fileURLToPath(new URL('./loader.js', import.meta.url));
|
|
21
|
+
const finalizeLoaderPath = fileURLToPath(new URL('./finalize-loader.js', import.meta.url));
|
|
22
|
+
const parallelLoaderPath = fileURLToPath(new URL('./parallel-loader.js', import.meta.url));
|
|
23
|
+
const DEFAULT_MAX_WORKERS = 4;
|
|
21
24
|
const OCTANE_RULE = /\.(?:tsrx|tsx|ts|js)$/i;
|
|
22
25
|
const TYPESCRIPT_RULE = /\.(?:tsrx|tsx|ts)$/i;
|
|
23
26
|
|
|
@@ -337,7 +340,22 @@ export class OctaneRspackPlugin {
|
|
|
337
340
|
test: OCTANE_RULE,
|
|
338
341
|
type: 'javascript/auto',
|
|
339
342
|
enforce: 'pre',
|
|
340
|
-
use:
|
|
343
|
+
use:
|
|
344
|
+
this.options.parallel === false
|
|
345
|
+
? [{ loader: loaderPath, options: loaderOptions }]
|
|
346
|
+
: [
|
|
347
|
+
{ loader: finalizeLoaderPath, options: loaderOptions },
|
|
348
|
+
{
|
|
349
|
+
loader: parallelLoaderPath,
|
|
350
|
+
options: loaderOptions,
|
|
351
|
+
parallel: {
|
|
352
|
+
maxWorkers:
|
|
353
|
+
typeof this.options.parallel === 'object'
|
|
354
|
+
? (this.options.parallel.maxWorkers ?? DEFAULT_MAX_WORKERS)
|
|
355
|
+
: DEFAULT_MAX_WORKERS,
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
],
|
|
341
359
|
});
|
|
342
360
|
if (this.options.transpile !== false) {
|
|
343
361
|
compiler.options.module.rules.push({
|
package/src/shared.js
CHANGED
|
@@ -47,7 +47,7 @@ const LOADER_OPTION_KEYS = new Set([
|
|
|
47
47
|
'universalRuntime',
|
|
48
48
|
'layerSpecializations',
|
|
49
49
|
]);
|
|
50
|
-
const PLUGIN_OPTION_KEYS = new Set([...LOADER_OPTION_KEYS, 'runtime', 'transpile']);
|
|
50
|
+
const PLUGIN_OPTION_KEYS = new Set([...LOADER_OPTION_KEYS, 'parallel', 'runtime', 'transpile']);
|
|
51
51
|
const LAYER_SPECIALIZATION_KEYS = new Set(['runtime', 'renderers', 'universalRuntime']);
|
|
52
52
|
|
|
53
53
|
function normalizeRuntimeRequest(value, label = 'runtime') {
|
|
@@ -153,6 +153,29 @@ function assertBooleanOption(options, key) {
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
function normalizeParallelOption(value) {
|
|
157
|
+
if (value === undefined || typeof value === 'boolean') return value;
|
|
158
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
159
|
+
throw new TypeError(
|
|
160
|
+
'@octanejs/rspack-plugin: `parallel` must be a boolean or an options object.',
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
for (const key of Object.keys(value)) {
|
|
164
|
+
if (key !== 'maxWorkers') {
|
|
165
|
+
throw new TypeError(`@octanejs/rspack-plugin: unknown \`parallel.${key}\` option.`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (
|
|
169
|
+
value.maxWorkers !== undefined &&
|
|
170
|
+
(!Number.isSafeInteger(value.maxWorkers) || value.maxWorkers < 1)
|
|
171
|
+
) {
|
|
172
|
+
throw new TypeError(
|
|
173
|
+
'@octanejs/rspack-plugin: `parallel.maxWorkers` must be a positive integer.',
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return Object.freeze(value.maxWorkers === undefined ? {} : { maxWorkers: value.maxWorkers });
|
|
177
|
+
}
|
|
178
|
+
|
|
156
179
|
function normalizeOptions(value, plugin) {
|
|
157
180
|
const options = value ?? {};
|
|
158
181
|
if (typeof options !== 'object' || Array.isArray(options)) {
|
|
@@ -187,6 +210,7 @@ function normalizeOptions(value, plugin) {
|
|
|
187
210
|
throw new TypeError('@octanejs/rspack-plugin: `exclude` must be an array of path strings.');
|
|
188
211
|
}
|
|
189
212
|
if (plugin) assertBooleanOption(options, 'transpile');
|
|
213
|
+
const parallel = plugin ? normalizeParallelOption(options.parallel) : undefined;
|
|
190
214
|
const renderers =
|
|
191
215
|
options.renderers === undefined ? undefined : normalizeRendererConfig(options.renderers);
|
|
192
216
|
const universalRuntime = normalizeUniversalRuntime(options.universalRuntime);
|
|
@@ -206,6 +230,7 @@ function normalizeOptions(value, plugin) {
|
|
|
206
230
|
...(options.requireDirective === undefined
|
|
207
231
|
? null
|
|
208
232
|
: { requireDirective: options.requireDirective }),
|
|
233
|
+
...(plugin && parallel !== undefined ? { parallel } : null),
|
|
209
234
|
...(plugin && options.transpile !== undefined ? { transpile: options.transpile } : null),
|
|
210
235
|
...(plugin && options.runtime !== undefined ? { runtime: options.runtime } : null),
|
|
211
236
|
};
|
package/types/index.d.ts
CHANGED
|
@@ -152,6 +152,13 @@ export interface OctaneRspackLoaderOptions {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
export interface OctaneRspackPluginOptions extends OctaneRspackLoaderOptions {
|
|
155
|
+
/**
|
|
156
|
+
* Compile Octane modules in Rspack worker threads. Enabled by default with
|
|
157
|
+
* at most four workers; set `false` to keep compilation on the main thread.
|
|
158
|
+
* Provide `maxWorkers` to request a different shared worker-pool limit.
|
|
159
|
+
* @default true
|
|
160
|
+
*/
|
|
161
|
+
parallel?: boolean | { maxWorkers?: number };
|
|
155
162
|
/**
|
|
156
163
|
* Compiler and exact-runtime overrides selected by the current module's
|
|
157
164
|
* Rspack layer. Unknown layers retain the top-level plugin options.
|
package/types/options.test-d.ts
CHANGED
|
@@ -21,6 +21,7 @@ const loaderOptions: OctaneRspackLoaderOptions = {
|
|
|
21
21
|
|
|
22
22
|
const pluginOptions: OctaneRspackPluginOptions = {
|
|
23
23
|
strong: false,
|
|
24
|
+
parallel: { maxWorkers: 2 },
|
|
24
25
|
layerSpecializations: {
|
|
25
26
|
'native:main': {
|
|
26
27
|
runtime: '@fixture/native-main-runtime',
|
|
@@ -29,6 +30,8 @@ const pluginOptions: OctaneRspackPluginOptions = {
|
|
|
29
30
|
},
|
|
30
31
|
};
|
|
31
32
|
|
|
33
|
+
const serialPluginOptions: OctaneRspackPluginOptions = { parallel: false };
|
|
34
|
+
|
|
32
35
|
const unsupportedLoaderRuntime: OctaneRspackLoaderOptions = {
|
|
33
36
|
layerSpecializations: {
|
|
34
37
|
'native:main': {
|
|
@@ -38,6 +41,13 @@ const unsupportedLoaderRuntime: OctaneRspackLoaderOptions = {
|
|
|
38
41
|
},
|
|
39
42
|
};
|
|
40
43
|
|
|
44
|
+
const unsupportedLoaderParallel: OctaneRspackLoaderOptions = {
|
|
45
|
+
// @ts-expect-error Worker-pool configuration belongs to the plugin, not the standalone loader.
|
|
46
|
+
parallel: true,
|
|
47
|
+
};
|
|
48
|
+
|
|
41
49
|
void loaderOptions;
|
|
42
50
|
void pluginOptions;
|
|
51
|
+
void serialPluginOptions;
|
|
43
52
|
void unsupportedLoaderRuntime;
|
|
53
|
+
void unsupportedLoaderParallel;
|