@decohere/flux 0.0.1-dev.130 → 0.0.1-dev.131
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 +1 -1
- package/commonjs/src/flux.module.js +2 -2
- package/commonjs/src/source-module-loader.js +6 -6
- package/commonjs/src/transpile-disk-cache.js +3 -3
- package/es6/src/flux.module.js +1 -1
- package/es6/src/source-module-loader.js +1 -1
- package/es6/src/transpile-disk-cache.js +1 -1
- package/package.json +8 -9
package/README.md
CHANGED
|
@@ -240,7 +240,7 @@ Only source files (`.ts`) that a served entry imports trigger a reboot.
|
|
|
240
240
|
|
|
241
241
|
**Memory grows over a long session.** Each reboot imports changed modules under a new `?version=` URL, and Node's ES module cache never releases the old versions. That's fine for a working day; if a session runs for days with thousands of reboots, restart it.
|
|
242
242
|
|
|
243
|
-
Flux uses **Forge’s compiler
|
|
243
|
+
Flux uses **Forge’s compiler** (`@decohere/forge/transpile`), with one SWC config per project built once per run. It never loads the TypeScript compiler: SWC strips types without checking them, so type errors are `forge typecheck`'s job. SWC leaves imports as written; Flux's resolve hook maps each one to its TypeScript source: `@scope/pkg` and `@scope/pkg/sub` through the the workspace package aliases (and tsconfig `paths`), `./file.js` and `./file` to `file.ts` or `file.tsx`, `./file.mjs` to `file.mts`, `./file.cjs` to `file.cts` (which runs as CommonJS), and `./dir` to `dir/index.ts`. Doing it in one place, instead of in SWC (`jsc.paths`, `resolveFully`) and again in the hook, made loading about 20% faster once Node and SWC are warm (`pnpm bench flux-load`). Before Node imports an entry, Flux compiles it and the files it imports, following their imports out from the entry, in parallel on SWC's thread pool. The load hook is synchronous and would otherwise compile one file at a time; files the app never imports, such as tests, are not compiled. A file that fails to compile there is compiled again when Node loads it, and that load fails with the file's name, as before. That is a debug rule so you can edit a library and hit HMR without a pre-build or `node_modules` workspace symlink. Release still resolves through real `node_modules` (published `exports` / `main`).
|
|
244
244
|
|
|
245
245
|
Why aliases, and a tree of where a symlink misses `src/index.ts`: [Forge — debug path aliases](../forge/README.md#debug-path-aliases-not-node_modules-links).
|
|
246
246
|
|
|
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "FluxModule", {
|
|
|
8
8
|
return FluxModule;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const
|
|
11
|
+
const _transpile = require("@decohere/forge/transpile");
|
|
12
12
|
const _cli = require("@decohere/devkit/cli");
|
|
13
13
|
const _deferredscriptrunner = require("./deferred-script-runner.js");
|
|
14
14
|
const _fluxcommand = require("./flux.command.js");
|
|
@@ -28,6 +28,6 @@ class FluxModule extends _cli.ModuleManifest {
|
|
|
28
28
|
}
|
|
29
29
|
createWorkspace(options) {
|
|
30
30
|
// Same workspace as `flux.run` / `flux.serve` and forge.
|
|
31
|
-
return (0,
|
|
31
|
+
return (0, _transpile.createWorkspace)(options);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -13,7 +13,7 @@ const _nodemodule = require("node:module");
|
|
|
13
13
|
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
14
14
|
const _nodeurl = require("node:url");
|
|
15
15
|
const _decorators = require("@decohere/crucible/decorators");
|
|
16
|
-
const
|
|
16
|
+
const _transpile = require("@decohere/forge/transpile");
|
|
17
17
|
const _workspace = require("@decohere/workspace");
|
|
18
18
|
const _io = require("@decohere/core/io");
|
|
19
19
|
const _scribe = require("@decohere/scribe");
|
|
@@ -74,7 +74,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
74
74
|
}
|
|
75
75
|
class SourceModuleLoader {
|
|
76
76
|
logger = _scribe.scribe.logger(SourceModuleLoader.name);
|
|
77
|
-
transpiler = new
|
|
77
|
+
transpiler = new _transpile.SwcTranspiler();
|
|
78
78
|
disposed = false;
|
|
79
79
|
hooksRegistered = false;
|
|
80
80
|
workspace;
|
|
@@ -113,7 +113,7 @@ class SourceModuleLoader {
|
|
|
113
113
|
this.swcConfigs.clear();
|
|
114
114
|
this.commonJsConfigs.clear();
|
|
115
115
|
this.buildConfig = options.buildConfig;
|
|
116
|
-
this.workspace = options.workspace ?? await (0,
|
|
116
|
+
this.workspace = options.workspace ?? await (0, _transpile.createWorkspace)();
|
|
117
117
|
this.versionFileUrl = options.versionFileUrl ?? ((fileUrl)=>fileUrl);
|
|
118
118
|
this.onResolved = options.onResolved;
|
|
119
119
|
this.fileInfoMap = await this.buildFileInfoMap(this.buildConfig);
|
|
@@ -306,7 +306,7 @@ class SourceModuleLoader {
|
|
|
306
306
|
const key = this.diskCache?.keyFor(fullPath, source, baseConfig);
|
|
307
307
|
const hit = key == null ? undefined : this.diskCache?.readSync(key);
|
|
308
308
|
if (hit != null) return hit;
|
|
309
|
-
const response = this.transpiler.transformCodeSync(source, file,
|
|
309
|
+
const response = this.transpiler.transformCodeSync(source, file, _transpile.BuildTargets.es6, baseConfig);
|
|
310
310
|
if (response.outcome !== "success") {
|
|
311
311
|
this.logger.error(`Failed to transpile ${fullPath}`, response);
|
|
312
312
|
throw new Error(`Failed to transpile ${fullPath}`);
|
|
@@ -335,7 +335,7 @@ class SourceModuleLoader {
|
|
|
335
335
|
const key = this.diskCache?.keyFor(fullPath, source, baseConfig);
|
|
336
336
|
const hit = key == null ? undefined : this.diskCache?.readSync(key);
|
|
337
337
|
if (hit != null) return hit;
|
|
338
|
-
const response = await this.transpiler.transformCode(source, file,
|
|
338
|
+
const response = await this.transpiler.transformCode(source, file, _transpile.BuildTargets.es6, baseConfig);
|
|
339
339
|
if (response.outcome !== "success") return undefined;
|
|
340
340
|
if (key != null) await this.diskCache?.write(key, response.code);
|
|
341
341
|
return response.code;
|
|
@@ -364,7 +364,7 @@ class SourceModuleLoader {
|
|
|
364
364
|
/** Forge's defaults when there is no project: decorators and their metadata on. */ esModuleConfigFor(project) {
|
|
365
365
|
const cached = this.swcConfigs.get(project);
|
|
366
366
|
if (cached != null) return cached;
|
|
367
|
-
const base = this.transpiler.createBaseConfig(
|
|
367
|
+
const base = this.transpiler.createBaseConfig(_transpile.BuildTargets.es6, {
|
|
368
368
|
tsConfig: project?.getTsConfigSync(),
|
|
369
369
|
userConfig: project?.getSwcConfigSync(),
|
|
370
370
|
aliasPaths: false,
|
|
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "TranspileDiskCache", {
|
|
|
11
11
|
const _nodecrypto = require("node:crypto");
|
|
12
12
|
const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
|
|
13
13
|
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
14
|
-
const
|
|
14
|
+
const _transpile = require("@decohere/forge/transpile");
|
|
15
15
|
const _scribe = require("@decohere/scribe");
|
|
16
16
|
function _interop_require_default(obj) {
|
|
17
17
|
return obj && obj.__esModule ? obj : {
|
|
@@ -30,7 +30,7 @@ class TranspileDiskCache {
|
|
|
30
30
|
this.dir = dir;
|
|
31
31
|
}
|
|
32
32
|
/** The cache for a workspace, or null when caching is off (`DECOHERE_CACHE=0`). */ static forWorkspace(rootDir) {
|
|
33
|
-
const base =
|
|
33
|
+
const base = _transpile.transpileCache.directory(rootDir);
|
|
34
34
|
return base == null ? null : new TranspileDiskCache(_nodepath.default.join(base, "flux"));
|
|
35
35
|
}
|
|
36
36
|
get directory() {
|
|
@@ -41,7 +41,7 @@ class TranspileDiskCache {
|
|
|
41
41
|
* file's path (forge's `createFileConfig`), so hashing the base once per project and adding
|
|
42
42
|
* the path covers them without serialising options for every file.
|
|
43
43
|
*/ keyFor(fullPath, source, baseOptions) {
|
|
44
|
-
return (0, _nodecrypto.createHash)("sha256").update(`${FORMAT}\0${
|
|
44
|
+
return (0, _nodecrypto.createHash)("sha256").update(`${FORMAT}\0${_transpile.transpileCache.swcVersion}\0${this.optionsHash(baseOptions)}\0`).update(`${fullPath}\0`).update(source).digest("hex");
|
|
45
45
|
}
|
|
46
46
|
optionsHashes = new WeakMap();
|
|
47
47
|
optionsHash(options) {
|
package/es6/src/flux.module.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createWorkspace } from "@decohere/forge";
|
|
1
|
+
import { createWorkspace } from "@decohere/forge/transpile";
|
|
2
2
|
import { ModuleManifest } from "@decohere/devkit/cli";
|
|
3
3
|
import { DeferredScriptRunner } from "./deferred-script-runner.js";
|
|
4
4
|
import { FluxCommand } from "./flux.command.js";
|
|
@@ -9,7 +9,7 @@ import { registerHooks } from "node:module";
|
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
11
11
|
import { injectable } from "@decohere/crucible/decorators";
|
|
12
|
-
import { BuildTargets, createWorkspace, SwcTranspiler } from "@decohere/forge";
|
|
12
|
+
import { BuildTargets, createWorkspace, SwcTranspiler } from "@decohere/forge/transpile";
|
|
13
13
|
import { packageAliases, sourceExtensions } from "@decohere/workspace";
|
|
14
14
|
import { FileEx, io } from "@decohere/core/io";
|
|
15
15
|
import { scribe } from "@decohere/scribe";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { transpileCache } from "@decohere/forge";
|
|
4
|
+
import { transpileCache } from "@decohere/forge/transpile";
|
|
5
5
|
import { scribe } from "@decohere/scribe";
|
|
6
6
|
/** Bump when what flux stores changes, so older entries stop matching. */ const FORMAT = 1;
|
|
7
7
|
/** Entries untouched for this long are pruned. */ const MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decohere/flux",
|
|
3
|
-
"version": "0.0.1-dev.
|
|
3
|
+
"version": "0.0.1-dev.131",
|
|
4
4
|
"description": "Hot module reload server for Node.js ESM applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -34,14 +34,13 @@
|
|
|
34
34
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@decohere/core": "0.0.1-dev.
|
|
38
|
-
"@decohere/crucible": "0.0.1-dev.
|
|
39
|
-
"@decohere/devkit": "0.0.1-dev.
|
|
40
|
-
"@decohere/forge": "0.0.1-dev.
|
|
41
|
-
"@decohere/scribe": "0.0.1-dev.
|
|
42
|
-
"@decohere/workspace": "0.0.1-dev.
|
|
43
|
-
"commander": "^13.1.0"
|
|
44
|
-
"rxjs": "^7.8.2"
|
|
37
|
+
"@decohere/core": "0.0.1-dev.131",
|
|
38
|
+
"@decohere/crucible": "0.0.1-dev.131",
|
|
39
|
+
"@decohere/devkit": "0.0.1-dev.131",
|
|
40
|
+
"@decohere/forge": "0.0.1-dev.131",
|
|
41
|
+
"@decohere/scribe": "0.0.1-dev.131",
|
|
42
|
+
"@decohere/workspace": "0.0.1-dev.131",
|
|
43
|
+
"commander": "^13.1.0"
|
|
45
44
|
},
|
|
46
45
|
"devDependencies": {}
|
|
47
46
|
}
|