@swissjs/swite 0.3.0 → 0.3.2
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/CHANGELOG.md +15 -0
- package/dist/adapters/proxy/SwiteProxyError.d.ts.map +1 -0
- package/dist/{proxy → adapters/proxy}/proxyToPython.d.ts +1 -1
- package/dist/adapters/proxy/proxyToPython.d.ts.map +1 -0
- package/dist/build-engine/builder.d.ts.map +1 -0
- package/dist/{builder.js → build-engine/builder.js} +8 -14
- package/dist/cli.js +5 -5
- package/dist/config/config-loader.d.ts.map +1 -0
- package/dist/{config.d.ts → config/config.d.ts} +11 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/env.d.ts +25 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +84 -0
- package/dist/{handlers → dev-engine/handlers}/base-handler.d.ts +5 -1
- package/dist/dev-engine/handlers/base-handler.d.ts.map +1 -0
- package/dist/dev-engine/handlers/base-handler.js +58 -0
- package/dist/dev-engine/handlers/js-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/js-handler.js +1 -1
- package/dist/dev-engine/handlers/mjs-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/mjs-handler.js +1 -1
- package/dist/dev-engine/handlers/node-module-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/node-module-handler.js +33 -44
- package/dist/{handlers → dev-engine/handlers}/ts-handler.d.ts +0 -4
- package/dist/dev-engine/handlers/ts-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/ts-handler.js +5 -28
- package/dist/{handlers → dev-engine/handlers}/ui-handler.d.ts +0 -4
- package/dist/dev-engine/handlers/ui-handler.d.ts.map +1 -0
- package/dist/dev-engine/handlers/ui-handler.js +84 -0
- package/dist/{handlers → dev-engine/handlers}/uix-handler.d.ts +0 -4
- package/dist/dev-engine/handlers/uix-handler.d.ts.map +1 -0
- package/dist/dev-engine/handlers/uix-handler.js +70 -0
- package/dist/dev-engine/hmr/hmr-client-template.d.ts +10 -0
- package/dist/dev-engine/hmr/hmr-client-template.d.ts.map +1 -0
- package/dist/dev-engine/hmr/hmr-client-template.js +122 -0
- package/dist/dev-engine/hmr/hmr.d.ts.map +1 -0
- package/dist/{hmr.js → dev-engine/hmr/hmr.js} +2 -134
- package/dist/{middleware → dev-engine/middleware}/hmr-routes.d.ts +2 -2
- package/dist/dev-engine/middleware/hmr-routes.d.ts.map +1 -0
- package/dist/{middleware → dev-engine/middleware}/hmr-routes.js +1 -1
- package/dist/dev-engine/middleware/middleware-setup.d.ts +35 -0
- package/dist/dev-engine/middleware/middleware-setup.d.ts.map +1 -0
- package/dist/dev-engine/middleware/middleware-setup.js +327 -0
- package/dist/dev-engine/middleware/static-files.d.ts.map +1 -0
- package/dist/{middleware → dev-engine/middleware}/static-files.js +2 -2
- package/dist/{dev → dev-engine}/pythonDevManager.d.ts +1 -1
- package/dist/dev-engine/pythonDevManager.d.ts.map +1 -0
- package/dist/{dev → dev-engine}/pythonDevManager.js +1 -1
- package/dist/{router → dev-engine/router}/file-router.d.ts +4 -4
- package/dist/dev-engine/router/file-router.d.ts.map +1 -0
- package/dist/{router → dev-engine/router}/file-router.js +4 -4
- package/dist/dev-engine/server.d.ts.map +1 -0
- package/dist/{server.js → dev-engine/server.js} +10 -6
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/internal/cache/compilation-cache.d.ts.map +1 -0
- package/dist/{cache → internal/cache}/compilation-cache.js +3 -2
- package/dist/internal/generate-import-map-cli.d.ts.map +1 -0
- package/dist/{utils → internal}/generate-import-map-cli.js +1 -1
- package/dist/internal/generate-import-map.d.ts.map +1 -0
- package/dist/{utils → internal}/generate-import-map.js +3 -3
- package/dist/{utils → kernel}/package-finder.d.ts +7 -5
- package/dist/kernel/package-finder.d.ts.map +1 -0
- package/dist/kernel/package-finder.js +154 -0
- package/dist/kernel/package-registry.d.ts.map +1 -0
- package/dist/kernel/workspace.d.ts.map +1 -0
- package/dist/{resolver → resolution}/bare-import-resolver.d.ts +1 -1
- package/dist/resolution/bare-import-resolver.d.ts.map +1 -0
- package/dist/{resolver → resolution}/bare-import-resolver.js +25 -53
- package/dist/resolution/cdn/cdn-fallback.d.ts.map +1 -0
- package/dist/{utils → resolution/path}/file-path-resolver.d.ts +2 -1
- package/dist/resolution/path/file-path-resolver.d.ts.map +1 -0
- package/dist/{utils → resolution/path}/file-path-resolver.js +46 -28
- package/dist/resolution/path/path-fixup.d.ts +13 -0
- package/dist/resolution/path/path-fixup.d.ts.map +1 -0
- package/dist/resolution/path/path-fixup.js +20 -0
- package/dist/{resolver.d.ts → resolution/resolver.d.ts} +1 -1
- package/dist/resolution/resolver.d.ts.map +1 -0
- package/dist/{resolver.js → resolution/resolver.js} +8 -37
- package/dist/{import-rewriter.d.ts → resolution/rewriting/import-rewriter.d.ts} +1 -1
- package/dist/resolution/rewriting/import-rewriter.d.ts.map +1 -0
- package/dist/resolution/rewriting/import-rewriter.js +199 -0
- package/dist/{resolver → resolution}/symlink-registry.d.ts +1 -1
- package/dist/resolution/symlink-registry.d.ts.map +1 -0
- package/dist/{resolver → resolution}/symlink-registry.js +1 -1
- package/dist/resolution/url-resolver.d.ts.map +1 -0
- package/dist/{resolver → resolution}/url-resolver.js +38 -109
- package/dist/resolution/workspace-package-resolver.d.ts.map +1 -0
- package/dist/resolution/workspace-package-resolver.js +77 -0
- package/docs/architecture/build-pipeline.md +97 -0
- package/docs/architecture/dev-server.md +87 -0
- package/docs/architecture/hmr.md +78 -0
- package/docs/architecture/import-rewriting.md +101 -0
- package/docs/architecture/index.md +16 -0
- package/docs/architecture/python-integration.md +93 -0
- package/docs/architecture/resolution.md +92 -0
- package/docs/cli/build.md +78 -0
- package/docs/cli/dev.md +90 -0
- package/docs/cli/index.md +15 -0
- package/docs/cli/start.md +45 -0
- package/docs/development/contributing.md +74 -0
- package/docs/development/index.md +12 -0
- package/docs/development/internals.md +101 -0
- package/docs/guide/configuration.md +89 -0
- package/docs/guide/index.md +13 -0
- package/docs/guide/project-structure.md +75 -0
- package/docs/guide/quickstart.md +113 -0
- package/docs/index.md +16 -0
- package/package.json +5 -5
- package/src/cli.ts +1 -1
- package/src/config/config.ts +11 -0
- package/src/dev-engine/handlers/base-handler.ts +4 -2
- package/src/dev-engine/handlers/node-module-handler.ts +51 -78
- package/src/dev-engine/middleware/middleware-setup.ts +1 -0
- package/src/dev-engine/server.ts +38 -33
- package/src/kernel/package-finder.ts +59 -43
- package/src/resolution/bare-import-resolver.ts +14 -4
- package/src/resolution/path/file-path-resolver.ts +44 -10
- package/src/resolution/url-resolver.ts +1 -1
- package/dist/builder.d.ts.map +0 -1
- package/dist/cache/compilation-cache.d.ts.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/dev/pythonDevManager.d.ts.map +0 -1
- package/dist/env.d.ts +0 -19
- package/dist/env.d.ts.map +0 -1
- package/dist/env.js +0 -112
- package/dist/handlers/base-handler.d.ts.map +0 -1
- package/dist/handlers/base-handler.js +0 -38
- package/dist/handlers/js-handler.d.ts.map +0 -1
- package/dist/handlers/mjs-handler.d.ts.map +0 -1
- package/dist/handlers/node-module-handler.d.ts.map +0 -1
- package/dist/handlers/ts-handler.d.ts.map +0 -1
- package/dist/handlers/ui-handler.d.ts.map +0 -1
- package/dist/handlers/ui-handler.js +0 -182
- package/dist/handlers/uix-handler.d.ts.map +0 -1
- package/dist/handlers/uix-handler.js +0 -135
- package/dist/hmr.d.ts.map +0 -1
- package/dist/import-rewriter.d.ts.map +0 -1
- package/dist/import-rewriter.js +0 -351
- package/dist/middleware/hmr-routes.d.ts.map +0 -1
- package/dist/middleware/middleware-setup.d.ts +0 -23
- package/dist/middleware/middleware-setup.d.ts.map +0 -1
- package/dist/middleware/middleware-setup.js +0 -596
- package/dist/middleware/static-files.d.ts.map +0 -1
- package/dist/proxy/SwiteProxyError.d.ts.map +0 -1
- package/dist/proxy/proxyToPython.d.ts.map +0 -1
- package/dist/resolver/bare-import-resolver.d.ts.map +0 -1
- package/dist/resolver/symlink-registry.d.ts.map +0 -1
- package/dist/resolver/url-resolver.d.ts.map +0 -1
- package/dist/resolver/workspace-package-resolver.d.ts.map +0 -1
- package/dist/resolver/workspace-package-resolver.js +0 -185
- package/dist/resolver.d.ts.map +0 -1
- package/dist/router/file-router.d.ts.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/utils/cdn-fallback.d.ts.map +0 -1
- package/dist/utils/file-path-resolver.d.ts.map +0 -1
- package/dist/utils/generate-import-map-cli.d.ts.map +0 -1
- package/dist/utils/generate-import-map.d.ts.map +0 -1
- package/dist/utils/package-finder.d.ts.map +0 -1
- package/dist/utils/package-finder.js +0 -161
- package/dist/utils/package-registry.d.ts.map +0 -1
- package/dist/utils/workspace.d.ts.map +0 -1
- /package/dist/{proxy → adapters/proxy}/SwiteProxyError.d.ts +0 -0
- /package/dist/{proxy → adapters/proxy}/SwiteProxyError.js +0 -0
- /package/dist/{proxy → adapters/proxy}/proxyToPython.js +0 -0
- /package/dist/{builder.d.ts → build-engine/builder.d.ts} +0 -0
- /package/dist/{config-loader.d.ts → config/config-loader.d.ts} +0 -0
- /package/dist/{config-loader.js → config/config-loader.js} +0 -0
- /package/dist/{config.js → config/config.js} +0 -0
- /package/dist/{handlers → dev-engine/handlers}/js-handler.d.ts +0 -0
- /package/dist/{handlers → dev-engine/handlers}/mjs-handler.d.ts +0 -0
- /package/dist/{handlers → dev-engine/handlers}/node-module-handler.d.ts +0 -0
- /package/dist/{hmr.d.ts → dev-engine/hmr/hmr.d.ts} +0 -0
- /package/dist/{middleware → dev-engine/middleware}/static-files.d.ts +0 -0
- /package/dist/{server.d.ts → dev-engine/server.d.ts} +0 -0
- /package/dist/{cache → internal/cache}/compilation-cache.d.ts +0 -0
- /package/dist/{utils → internal}/generate-import-map-cli.d.ts +0 -0
- /package/dist/{utils → internal}/generate-import-map.d.ts +0 -0
- /package/dist/{utils → kernel}/package-registry.d.ts +0 -0
- /package/dist/{utils → kernel}/package-registry.js +0 -0
- /package/dist/{utils → kernel}/workspace.d.ts +0 -0
- /package/dist/{utils → kernel}/workspace.js +0 -0
- /package/dist/{utils → resolution/cdn}/cdn-fallback.d.ts +0 -0
- /package/dist/{utils → resolution/cdn}/cdn-fallback.js +0 -0
- /package/dist/{resolver → resolution}/url-resolver.d.ts +0 -0
- /package/dist/{resolver → resolution}/workspace-package-resolver.d.ts +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Themba Mzumara
|
|
3
|
+
* SWITE - SWISS Development Server
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
import { promises as fs } from "node:fs";
|
|
7
|
+
import { UiCompiler } from "@swissjs/compiler";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import { rewriteImports } from "../../resolution/rewriting/import-rewriter.js";
|
|
10
|
+
import { inlineEnvReferences } from "../../config/env.js";
|
|
11
|
+
import { compilationCache } from "../../internal/cache/compilation-cache.js";
|
|
12
|
+
import { fixSwissLibPaths } from "../../resolution/path/path-fixup.js";
|
|
13
|
+
import { BaseHandler, setDevHeaders, } from "./base-handler.js";
|
|
14
|
+
export class UIHandler extends BaseHandler {
|
|
15
|
+
constructor(context) {
|
|
16
|
+
super(context);
|
|
17
|
+
this.compiler = new UiCompiler();
|
|
18
|
+
}
|
|
19
|
+
async handle(url, res) {
|
|
20
|
+
const filePath = await this.resolveFilePath(url);
|
|
21
|
+
console.log(chalk.blue(`[.ui] ${url} → ${filePath}`));
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(filePath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.error(chalk.red(`[.ui] File not found: ${filePath}`));
|
|
27
|
+
throw new Error(`File not found: ${url} (resolved to: ${filePath})`);
|
|
28
|
+
}
|
|
29
|
+
// Cache hit
|
|
30
|
+
const cached = await compilationCache.get(filePath, (compiled) => this.getDependencies(compiled));
|
|
31
|
+
if (cached) {
|
|
32
|
+
const fixed = fixSwissLibPaths(cached);
|
|
33
|
+
setDevHeaders(res);
|
|
34
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
35
|
+
res.setHeader("Content-Length", Buffer.byteLength(fixed, "utf-8"));
|
|
36
|
+
res.end(fixed, "utf-8");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Cache miss — compile
|
|
40
|
+
const source = await fs.readFile(filePath, "utf-8");
|
|
41
|
+
let compiled = await this.compiler.compileAsync(source, filePath);
|
|
42
|
+
const esbuild = await import("esbuild");
|
|
43
|
+
const tsResult = await esbuild.transform(compiled, {
|
|
44
|
+
loader: "ts",
|
|
45
|
+
format: "esm",
|
|
46
|
+
target: "esnext",
|
|
47
|
+
sourcefile: filePath,
|
|
48
|
+
});
|
|
49
|
+
compiled = tsResult.code;
|
|
50
|
+
// Fix compiler-emitted wrong paths before import rewriting
|
|
51
|
+
compiled = fixSwissLibPaths(compiled);
|
|
52
|
+
// Inline import.meta.env references before import rewriting
|
|
53
|
+
compiled = inlineEnvReferences(compiled, this.context.env);
|
|
54
|
+
// Strip CSS static-asset imports — they are not ES modules
|
|
55
|
+
compiled = stripCssImports(compiled, url);
|
|
56
|
+
const bareImportPattern = /(?:import|from|export).*['"](@[^'"]+\/[^'"]+)(?!\/)[^'"]*['"]/;
|
|
57
|
+
if (bareImportPattern.test(compiled)) {
|
|
58
|
+
console.warn(`[.ui] Compiled output contains bare imports: ${url}`);
|
|
59
|
+
}
|
|
60
|
+
const rewritten = await rewriteImports(compiled, filePath, this.context.resolver);
|
|
61
|
+
const finalCode = fixSwissLibPaths(rewritten);
|
|
62
|
+
await compilationCache.set(filePath, compiled, finalCode, (c) => this.getDependencies(c));
|
|
63
|
+
if (bareImportPattern.test(finalCode)) {
|
|
64
|
+
console.error(`[.ui] Bare imports still present after rewriting: ${url}`);
|
|
65
|
+
for (const m of Array.from(rewritten.matchAll(/(?:import|from|export).*['"](@[^'"]+\/[^'"]+)(?!\/)[^'"]*['"]/g)).slice(0, 3)) {
|
|
66
|
+
console.error(`[.ui] Unresolved import: ${m[1]}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
setDevHeaders(res);
|
|
70
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
71
|
+
res.setHeader("Content-Length", Buffer.byteLength(finalCode, "utf-8"));
|
|
72
|
+
res.end(finalCode, "utf-8");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function stripCssImports(code, url) {
|
|
76
|
+
// Single well-ordered pass: static imports first, then dynamic imports
|
|
77
|
+
const before = code;
|
|
78
|
+
code = code.replace(/^[^\S\r\n]*import\s[^'"]*['"][^'"]*\.css['"]\s*;?[^\S\r\n]*$/gm, "");
|
|
79
|
+
code = code.replace(/\bimport\s*\(\s*['"][^'"]*\.css['"]\s*\)/g, "undefined");
|
|
80
|
+
if (before !== code) {
|
|
81
|
+
console.log(chalk.blue(`[.ui] Stripped CSS imports from ${url}`));
|
|
82
|
+
}
|
|
83
|
+
return code;
|
|
84
|
+
}
|
|
@@ -3,10 +3,6 @@ import { BaseHandler, type HandlerContext } from "./base-handler.js";
|
|
|
3
3
|
export declare class UIXHandler extends BaseHandler {
|
|
4
4
|
private compiler;
|
|
5
5
|
constructor(context: HandlerContext);
|
|
6
|
-
/**
|
|
7
|
-
* Extract dependencies from compiled code (import paths)
|
|
8
|
-
*/
|
|
9
|
-
private getDependencies;
|
|
10
6
|
handle(url: string, res: Response): Promise<void>;
|
|
11
7
|
}
|
|
12
8
|
//# sourceMappingURL=uix-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uix-handler.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/handlers/uix-handler.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQxC,OAAO,EACL,WAAW,EAEX,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,QAAQ,CAAoB;gBAExB,OAAO,EAAE,cAAc;IAI7B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CA8DxD"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Themba Mzumara
|
|
3
|
+
* SWITE - SWISS Development Server
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
import { promises as fs } from "node:fs";
|
|
7
|
+
import { UiCompiler } from "@swissjs/compiler";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import { rewriteImports } from "../../resolution/rewriting/import-rewriter.js";
|
|
10
|
+
import { inlineEnvReferences } from "../../config/env.js";
|
|
11
|
+
import { compilationCache } from "../../internal/cache/compilation-cache.js";
|
|
12
|
+
import { fixSwissLibPaths } from "../../resolution/path/path-fixup.js";
|
|
13
|
+
import { BaseHandler, setDevHeaders, } from "./base-handler.js";
|
|
14
|
+
export class UIXHandler extends BaseHandler {
|
|
15
|
+
constructor(context) {
|
|
16
|
+
super(context);
|
|
17
|
+
this.compiler = new UiCompiler();
|
|
18
|
+
}
|
|
19
|
+
async handle(url, res) {
|
|
20
|
+
const filePath = await this.resolveFilePath(url);
|
|
21
|
+
console.log(chalk.blue(`[.uix] ${url}`));
|
|
22
|
+
// Cache hit
|
|
23
|
+
const cached = await compilationCache.get(filePath, (compiled) => this.getDependencies(compiled));
|
|
24
|
+
if (cached) {
|
|
25
|
+
const fixed = fixSwissLibPaths(cached);
|
|
26
|
+
setDevHeaders(res);
|
|
27
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
28
|
+
res.send(fixed);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Cache miss — compile
|
|
32
|
+
const source = await fs.readFile(filePath, "utf-8");
|
|
33
|
+
let compiled = await this.compiler.compileAsync(source, filePath);
|
|
34
|
+
const esbuild = await import("esbuild");
|
|
35
|
+
const tsResult = await esbuild.transform(compiled, {
|
|
36
|
+
loader: "ts",
|
|
37
|
+
format: "esm",
|
|
38
|
+
target: "esnext",
|
|
39
|
+
sourcefile: filePath,
|
|
40
|
+
});
|
|
41
|
+
compiled = tsResult.code;
|
|
42
|
+
// Fix compiler-emitted wrong paths before import rewriting
|
|
43
|
+
compiled = fixSwissLibPaths(compiled);
|
|
44
|
+
// Inline import.meta.env references before import rewriting
|
|
45
|
+
compiled = inlineEnvReferences(compiled, this.context.env);
|
|
46
|
+
// Strip CSS static-asset imports — they are not ES modules
|
|
47
|
+
const beforeCss = compiled;
|
|
48
|
+
compiled = compiled.replace(/^[^\S\r\n]*import\s[^'"]*['"][^'"]*\.css['"]\s*;?[^\S\r\n]*$/gm, "");
|
|
49
|
+
compiled = compiled.replace(/\bimport\s*\(\s*['"][^'"]*\.css['"]\s*\)/g, "undefined");
|
|
50
|
+
if (beforeCss !== compiled) {
|
|
51
|
+
console.log(chalk.blue(`[.uix] Stripped CSS imports from ${url}`));
|
|
52
|
+
}
|
|
53
|
+
const bareImportPattern = /(?:import|from|export).*['"](@[^'"]+\/[^'"]+)(?!\/)[^'"]*['"]/;
|
|
54
|
+
if (bareImportPattern.test(compiled)) {
|
|
55
|
+
console.warn(`[.uix] Compiled output contains bare imports: ${url}`);
|
|
56
|
+
}
|
|
57
|
+
const rewritten = await rewriteImports(compiled, filePath, this.context.resolver);
|
|
58
|
+
const finalCode = fixSwissLibPaths(rewritten);
|
|
59
|
+
await compilationCache.set(filePath, compiled, finalCode, (c) => this.getDependencies(c));
|
|
60
|
+
if (bareImportPattern.test(finalCode)) {
|
|
61
|
+
console.error(`[.uix] Bare imports still present after rewriting: ${url}`);
|
|
62
|
+
for (const m of Array.from(rewritten.matchAll(/(?:import|from|export).*['"](@[^'"]+\/[^'"]+)(?!\/)[^'"]*['"]/g)).slice(0, 3)) {
|
|
63
|
+
console.error(`[.uix] Unresolved import: ${m[1]}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
setDevHeaders(res);
|
|
67
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
68
|
+
res.send(finalCode);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the HMR client script served to the browser at /__swite_hmr_client.
|
|
3
|
+
*
|
|
4
|
+
* The client is plain JavaScript (no TS syntax) because it is injected into
|
|
5
|
+
* browser pages as-is. Keeping it in a separate module rather than embedded
|
|
6
|
+
* inside hmr.ts makes it editable with syntax highlighting and avoids
|
|
7
|
+
* template-literal escaping issues.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildHmrClientScript(port: number): string;
|
|
10
|
+
//# sourceMappingURL=hmr-client-template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmr-client-template.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/hmr/hmr-client-template.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiHzD"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the HMR client script served to the browser at /__swite_hmr_client.
|
|
3
|
+
*
|
|
4
|
+
* The client is plain JavaScript (no TS syntax) because it is injected into
|
|
5
|
+
* browser pages as-is. Keeping it in a separate module rather than embedded
|
|
6
|
+
* inside hmr.ts makes it editable with syntax highlighting and avoids
|
|
7
|
+
* template-literal escaping issues.
|
|
8
|
+
*/
|
|
9
|
+
export function buildHmrClientScript(port) {
|
|
10
|
+
return `// SWITE HMR Client
|
|
11
|
+
console.log('[SWITE] HMR enabled');
|
|
12
|
+
|
|
13
|
+
const socket = new WebSocket('ws://' + window.location.hostname + ':${port}');
|
|
14
|
+
const moduleGraph = new Map();
|
|
15
|
+
const hotModules = new Map();
|
|
16
|
+
|
|
17
|
+
socket.addEventListener('open', () => {
|
|
18
|
+
console.log('[SWITE] HMR connected');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
socket.addEventListener('message', async (event) => {
|
|
22
|
+
const data = JSON.parse(event.data);
|
|
23
|
+
|
|
24
|
+
if (data.type === 'update') {
|
|
25
|
+
console.log('[SWITE] Processing update:', data.path, 'Type:', data.updateType);
|
|
26
|
+
|
|
27
|
+
if (data.updateType === 'style') {
|
|
28
|
+
updateStyles();
|
|
29
|
+
console.log('[SWITE] Styles hot updated');
|
|
30
|
+
} else if (data.updateType === 'hot') {
|
|
31
|
+
const moduleName = extractModuleName(data.path);
|
|
32
|
+
|
|
33
|
+
if (moduleName && hotModules.has(moduleName)) {
|
|
34
|
+
try {
|
|
35
|
+
invalidateModule(moduleName);
|
|
36
|
+
invalidateDependents(moduleName);
|
|
37
|
+
|
|
38
|
+
const updatedModule = await import(data.path + '?t=' + Date.now());
|
|
39
|
+
hotModules.set(moduleName, updatedModule);
|
|
40
|
+
|
|
41
|
+
updateComponent(moduleName, updatedModule);
|
|
42
|
+
console.log('[SWITE] Component hot updated:', moduleName);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('[SWITE] Hot update failed:', error);
|
|
45
|
+
window.location.reload();
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
console.log('[SWITE] New component detected, reloading page');
|
|
49
|
+
window.location.reload();
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
console.log('[SWITE] Full page reload required');
|
|
53
|
+
window.location.reload();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
function updateStyles() {
|
|
59
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
60
|
+
links.forEach(link => {
|
|
61
|
+
const href = link.getAttribute('href');
|
|
62
|
+
if (href) {
|
|
63
|
+
const base = href.replace(/[?&]t=\\d+/, '');
|
|
64
|
+
link.setAttribute('href', base + (base.includes('?') ? '&' : '?') + 't=' + Date.now());
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function extractModuleName(filePath) {
|
|
70
|
+
const parts = filePath.split('/');
|
|
71
|
+
const fileName = parts[parts.length - 1];
|
|
72
|
+
return fileName ? fileName.replace(/\\.[^.]+$/, '') : null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function invalidateModule(moduleName) {
|
|
76
|
+
if (window.__swiss_modules__) {
|
|
77
|
+
delete window.__swiss_modules__[moduleName];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function invalidateDependents(moduleName) {
|
|
82
|
+
const dependents = moduleGraph.get(moduleName);
|
|
83
|
+
if (dependents) {
|
|
84
|
+
for (const dependent of dependents) {
|
|
85
|
+
invalidateModule(dependent);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function updateComponent(moduleName, newModule) {
|
|
91
|
+
if (window.__swiss_instances__) {
|
|
92
|
+
const instances = window.__swiss_instances__[moduleName];
|
|
93
|
+
if (instances && Array.isArray(instances)) {
|
|
94
|
+
instances.forEach(instance => {
|
|
95
|
+
if (instance && typeof instance.update === 'function') {
|
|
96
|
+
instance.update(newModule.default || newModule);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
socket.addEventListener('close', () => {
|
|
104
|
+
console.log('[SWITE] HMR disconnected');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
socket.addEventListener('error', (error) => {
|
|
108
|
+
console.error('[SWITE] HMR error:', error);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
window.__swiss_modules__ = window.__swiss_modules__ || {};
|
|
112
|
+
window.__swiss_instances__ = window.__swiss_instances__ || {};
|
|
113
|
+
|
|
114
|
+
const currentScript = document.currentScript;
|
|
115
|
+
if (currentScript && currentScript.src) {
|
|
116
|
+
const moduleName = extractModuleName(currentScript.src);
|
|
117
|
+
if (moduleName) {
|
|
118
|
+
window.__swiss_modules__[moduleName] = true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/hmr/hmr.ts"],"names":[],"mappings":"AAUA,qBAAa,SAAS;IAOlB,OAAO,CAAC,IAAI;IANd,OAAO,CAAC,GAAG,CAAmB;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAAS;gBAGX,IAAI,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM;IAOZ,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBnB,kBAAkB;IAUhC,OAAO,CAAC,cAAc;YAYR,YAAY;IAmB1B,OAAO,IAAI,MAAM;IAIX,KAAK;IA4BX,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYpC,eAAe,IAAI,MAAM;IAIzB,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,SAAS;IAcX,IAAI;CAIX"}
|
|
@@ -5,6 +5,7 @@ import * as chokidar from "chokidar";
|
|
|
5
5
|
import { WebSocketServer, WebSocket } from "ws";
|
|
6
6
|
import * as net from "net";
|
|
7
7
|
import chalk from "chalk";
|
|
8
|
+
import { buildHmrClientScript } from "./hmr-client-template.js";
|
|
8
9
|
export class HMREngine {
|
|
9
10
|
constructor(root, hmrPort) {
|
|
10
11
|
this.root = root;
|
|
@@ -98,140 +99,7 @@ export class HMREngine {
|
|
|
98
99
|
});
|
|
99
100
|
}
|
|
100
101
|
getClientScript() {
|
|
101
|
-
return
|
|
102
|
-
// SWITE HMR Client
|
|
103
|
-
console.log('[SWITE] HMR enabled');
|
|
104
|
-
|
|
105
|
-
const socket = new WebSocket('ws://localhost:${this.port}');
|
|
106
|
-
const moduleGraph = new Map<string, Set<string>>();
|
|
107
|
-
const hotModules = new Map<string, any>();
|
|
108
|
-
|
|
109
|
-
socket.addEventListener('open', () => {
|
|
110
|
-
console.log('[SWITE] HMR connected');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
socket.addEventListener('message', (event) => {
|
|
114
|
-
const data = JSON.parse(event.data);
|
|
115
|
-
|
|
116
|
-
if (data.type === 'update') {
|
|
117
|
-
console.log('[SWITE] Processing update:', data.path, 'Type:', data.updateType);
|
|
118
|
-
|
|
119
|
-
if (data.updateType === 'style') {
|
|
120
|
-
// Hot swap CSS
|
|
121
|
-
updateStyles();
|
|
122
|
-
console.log('[SWITE] Styles hot updated');
|
|
123
|
-
} else if (data.updateType === 'hot') {
|
|
124
|
-
// Hot reload component
|
|
125
|
-
const moduleName = extractModuleName(data.path);
|
|
126
|
-
|
|
127
|
-
if (moduleName && hotModules.has(moduleName)) {
|
|
128
|
-
const oldModule = hotModules.get(moduleName);
|
|
129
|
-
try {
|
|
130
|
-
invalidateModule(moduleName);
|
|
131
|
-
invalidateDependents(moduleName);
|
|
132
|
-
|
|
133
|
-
const updatedModule = await import(data.path + '?t=' + Date.now());
|
|
134
|
-
hotModules.set(moduleName, updatedModule);
|
|
135
|
-
|
|
136
|
-
updateComponent(moduleName, updatedModule);
|
|
137
|
-
console.log('[SWITE] Component hot updated:', moduleName);
|
|
138
|
-
} catch (error) {
|
|
139
|
-
console.error('[SWITE] Hot update failed:', error);
|
|
140
|
-
window.location.reload();
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
console.log('[SWITE] New component detected, reloading page');
|
|
144
|
-
window.location.reload();
|
|
145
|
-
}
|
|
146
|
-
} else {
|
|
147
|
-
// Full reload for everything else
|
|
148
|
-
console.log('[SWITE] Full page reload required');
|
|
149
|
-
window.location.reload();
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
function updateStyles() {
|
|
155
|
-
// Find all style and link tags
|
|
156
|
-
const styles = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
157
|
-
styles.forEach(style => {
|
|
158
|
-
if (style.tagName === 'LINK' && style.getAttribute('href')) {
|
|
159
|
-
const href = style.getAttribute('href');
|
|
160
|
-
if (href && !href.includes('?t=')) {
|
|
161
|
-
// Add timestamp to force reload
|
|
162
|
-
style.setAttribute('href', href + '?t=' + Date.now());
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function extractModuleName(path: string): string | null {
|
|
169
|
-
// Extract module name from file path
|
|
170
|
-
const parts = path.split('/');
|
|
171
|
-
const fileName = parts[parts.length - 1];
|
|
172
|
-
|
|
173
|
-
if (fileName) {
|
|
174
|
-
const nameWithoutExt = fileName.replace(/.[^.]+$/, "");
|
|
175
|
-
return nameWithoutExt;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function invalidateModule(moduleName: string) {
|
|
182
|
-
// Clear module from cache
|
|
183
|
-
if (typeof window !== 'undefined' && (window as any).__swiss_modules__) {
|
|
184
|
-
delete (window as any).__swiss_modules__[moduleName];
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function invalidateDependents(moduleName: string) {
|
|
189
|
-
const dependents = moduleGraph.get(moduleName);
|
|
190
|
-
if (dependents) {
|
|
191
|
-
for (const dependent of dependents) {
|
|
192
|
-
invalidateModule(dependent);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function updateComponent(moduleName: string, newModule: any) {
|
|
198
|
-
// Find and update component instances
|
|
199
|
-
if (typeof window !== 'undefined' && (window as any).__swiss_instances__) {
|
|
200
|
-
const instances = (window as any).__swiss_instances__[moduleName];
|
|
201
|
-
if (instances && Array.isArray(instances)) {
|
|
202
|
-
instances.forEach(instance => {
|
|
203
|
-
// Update component state if it has update method
|
|
204
|
-
if (instance && typeof instance.update === 'function') {
|
|
205
|
-
instance.update(newModule.default || newModule);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
socket.addEventListener('close', () => {
|
|
213
|
-
console.log('[SWITE] HMR disconnected');
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
socket.addEventListener('error', (error) => {
|
|
217
|
-
console.error('[SWITE] HMR error:', error);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Register module for hot reloading
|
|
221
|
-
if (typeof window !== 'undefined') {
|
|
222
|
-
(window as any).__swiss_modules__ = (window as any).__swiss_modules__ || {};
|
|
223
|
-
(window as any).__swiss_instances__ = (window as any).__swiss_instances__ || {};
|
|
224
|
-
|
|
225
|
-
// Auto-register current module
|
|
226
|
-
const currentScript = document.currentScript;
|
|
227
|
-
if (currentScript && currentScript.src) {
|
|
228
|
-
const moduleName = extractModuleName(currentScript.src);
|
|
229
|
-
if (moduleName) {
|
|
230
|
-
(window as any).__swiss_modules__[moduleName] = true;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
`;
|
|
102
|
+
return buildHmrClientScript(this.port);
|
|
235
103
|
}
|
|
236
104
|
getUpdateType(fileExt, filePath) {
|
|
237
105
|
if (!fileExt || !filePath)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Express } from "express";
|
|
2
|
-
import type { RouteDefinition } from "@
|
|
3
|
-
import { HMREngine } from "../hmr.js";
|
|
2
|
+
import type { RouteDefinition } from "@swissjs/core";
|
|
3
|
+
import { HMREngine } from "../hmr/hmr.js";
|
|
4
4
|
export interface HMRRoutesConfig {
|
|
5
5
|
hmr: HMREngine;
|
|
6
6
|
routes: RouteDefinition[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmr-routes.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/middleware/hmr-routes.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqG1E"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import type { RouteDefinition } from "@swissjs/core";
|
|
3
|
+
import { RouteScanner } from "@swissjs/plugin-file-router/core";
|
|
4
|
+
import { createFileWatcher } from "@swissjs/plugin-file-router/dev";
|
|
5
|
+
import { ModuleResolver } from "../../resolution/resolver.js";
|
|
6
|
+
import { HMREngine } from "../hmr/hmr.js";
|
|
7
|
+
export interface MiddlewareConfig {
|
|
8
|
+
root: string;
|
|
9
|
+
workspaceRoot?: string | null;
|
|
10
|
+
publicDir: string;
|
|
11
|
+
resolver: ModuleResolver;
|
|
12
|
+
hmr: HMREngine;
|
|
13
|
+
userConfig?: import("../../config/config.js").SwiteUserConfig;
|
|
14
|
+
}
|
|
15
|
+
export interface MiddlewareResult {
|
|
16
|
+
routes: RouteDefinition[];
|
|
17
|
+
routeScanner: RouteScanner | null;
|
|
18
|
+
routeWatcher: Awaited<ReturnType<typeof createFileWatcher>> | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Setup all middleware for the SWITE server.
|
|
22
|
+
*
|
|
23
|
+
* Middleware registration order (matters for Express):
|
|
24
|
+
* 1. File router + HMR routes
|
|
25
|
+
* 2. /packages source files
|
|
26
|
+
* 3. /src source files (highest priority for that prefix)
|
|
27
|
+
* 4. /lib source files (pre-static guard)
|
|
28
|
+
* 5. .ui/.uix MIME-type guard (belt-and-suspenders for slipped-through requests)
|
|
29
|
+
* 6. /.skltn/modules.css → 204
|
|
30
|
+
* 7. Static file serving (public/, node_modules/, lib/)
|
|
31
|
+
* 8. General source-file transformation (all other paths)
|
|
32
|
+
* 9. SPA fallback
|
|
33
|
+
*/
|
|
34
|
+
export declare function setupMiddleware(app: Express, config: MiddlewareConfig): Promise<MiddlewareResult>;
|
|
35
|
+
//# sourceMappingURL=middleware-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware-setup.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/middleware/middleware-setup.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAmC,MAAM,SAAS,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAIpE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAa9D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAK1C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,SAAS,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,wBAAwB,EAAE,eAAe,CAAC;CAC/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,GAAG,IAAI,CAAC;CACpE;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CA2Q3B"}
|