@geajs/vite-plugin 1.2.1 → 1.2.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/dist/index.mjs +99 -35
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import _generate from "@babel/generator";
|
|
|
3
3
|
import * as t from "@babel/types";
|
|
4
4
|
import { parse } from "@babel/parser";
|
|
5
5
|
import { appendToBody, id, js, jsAll, jsBlockBody, jsClassProp, jsExpr, jsImport, jsMethod, jsObjectExpr, jsPrivateProp, num, str, tpl } from "eszter";
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, relative, resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
//#region src/utils/babel-interop.ts
|
|
@@ -9726,39 +9726,41 @@ const legacyShouldProxyDep = (p) => /\.(js|ts)$/.test(p) && !p.match(/(store|sta
|
|
|
9726
9726
|
* Returns `true` when HMR code was added, `false` otherwise (no component
|
|
9727
9727
|
* class, or the file contains a `gea-auto-register plugin` comment).
|
|
9728
9728
|
*/
|
|
9729
|
-
function injectHMR(ast,
|
|
9729
|
+
function injectHMR(ast, componentClassNames, defaultExportClassName, componentImports, componentImportsUsedAsTags, hmrImportSource = "virtual:gea-hmr", shouldProxyDep, shouldSkipDepAccept) {
|
|
9730
9730
|
if (hasAutoRegisterComment(ast)) return false;
|
|
9731
|
+
if (componentClassNames.length === 0) return false;
|
|
9731
9732
|
const hmrStmts = [];
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9733
|
+
ensureImport(ast, hmrImportSource, "handleComponentUpdate");
|
|
9734
|
+
ensureImport(ast, hmrImportSource, "registerHotModule");
|
|
9735
|
+
ensureImport(ast, hmrImportSource, "registerComponentInstance");
|
|
9736
|
+
ensureImport(ast, hmrImportSource, "unregisterComponentInstance");
|
|
9737
|
+
const proxyDep = shouldProxyDep ?? legacyShouldProxyDep;
|
|
9738
|
+
if (rewriteComponentDeps(ast, componentImports, proxyDep).length > 0) ensureImport(ast, hmrImportSource, "createHotComponentProxy");
|
|
9739
|
+
const exportProperties = [];
|
|
9740
|
+
for (const cn of componentClassNames) if (cn === defaultExportClassName) exportProperties.push(t.objectProperty(t.identifier("default"), t.identifier(cn)));
|
|
9741
|
+
else exportProperties.push(t.objectProperty(t.identifier(cn), t.identifier(cn), false, true));
|
|
9742
|
+
hmrStmts.push(js`const __moduleExports = ${t.objectExpression(exportProperties)};`);
|
|
9743
|
+
hmrStmts.push(js`registerHotModule(${jsExpr`${importMeta()}.url`}, __moduleExports);`);
|
|
9744
|
+
const acceptBody = [t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__updatedModule"), t.logicalExpression("||", t.identifier("newModule"), t.identifier("__moduleExports")))]), t.expressionStatement(t.callExpression(t.identifier("registerHotModule"), [t.memberExpression(importMeta(), t.identifier("url")), t.identifier("__updatedModule")]))];
|
|
9745
|
+
for (const cn of componentClassNames) {
|
|
9746
|
+
const key = cn === defaultExportClassName ? "default" : cn;
|
|
9747
|
+
acceptBody.push(t.expressionStatement(t.callExpression(t.identifier("handleComponentUpdate"), [t.memberExpression(importMeta(), t.identifier("url")), t.objectExpression([t.objectProperty(t.identifier("default"), t.memberExpression(t.identifier("__updatedModule"), t.identifier(key)))])])));
|
|
9748
|
+
}
|
|
9749
|
+
hmrStmts.push(t.expressionStatement(t.callExpression(t.memberExpression(hot(), t.identifier("accept")), [t.arrowFunctionExpression([t.identifier("newModule")], t.blockStatement(acceptBody))])));
|
|
9750
|
+
hmrStmts.push(...createAccepts(componentImports, proxyDep, shouldSkipDepAccept));
|
|
9751
|
+
for (const cn of componentClassNames) {
|
|
9752
|
+
const suffix = componentClassNames.length > 1 ? `_${cn}` : "";
|
|
9753
|
+
hmrStmts.push(js`const ${id("__origCreated" + suffix)} = ${id(cn)}.prototype.created;`);
|
|
9754
|
+
hmrStmts.push(js`${id(cn)}.prototype.created = function(__geaProps) {
|
|
9752
9755
|
registerComponentInstance(this.constructor.name, this);
|
|
9753
|
-
return __origCreated.call(this, __geaProps);
|
|
9756
|
+
return ${id("__origCreated" + suffix)}.call(this, __geaProps);
|
|
9754
9757
|
};`);
|
|
9755
|
-
hmrStmts.push(js`const __origDispose = ${id(
|
|
9756
|
-
hmrStmts.push(js`${id(
|
|
9758
|
+
hmrStmts.push(js`const ${id("__origDispose" + suffix)} = ${id(cn)}.prototype.dispose;`);
|
|
9759
|
+
hmrStmts.push(js`${id(cn)}.prototype.dispose = function() {
|
|
9757
9760
|
unregisterComponentInstance(this.constructor.name, this);
|
|
9758
|
-
return __origDispose.call(this);
|
|
9761
|
+
return ${id("__origDispose" + suffix)}.call(this);
|
|
9759
9762
|
};`);
|
|
9760
9763
|
}
|
|
9761
|
-
if (hmrStmts.length === 0) return false;
|
|
9762
9764
|
ast.program.body.push(t.ifStatement(hot(), t.blockStatement(hmrStmts)));
|
|
9763
9765
|
return true;
|
|
9764
9766
|
}
|
|
@@ -9800,10 +9802,11 @@ function rewriteComponentDeps(ast, imports, proxyDep) {
|
|
|
9800
9802
|
* add `hot.accept(dep, () => hot.invalidate())` so the page reloads when
|
|
9801
9803
|
* stores/utils change.
|
|
9802
9804
|
*/
|
|
9803
|
-
function createAccepts(imports, proxyDep) {
|
|
9805
|
+
function createAccepts(imports, proxyDep, shouldSkip) {
|
|
9804
9806
|
const stmts = [];
|
|
9805
9807
|
for (const p of imports) {
|
|
9806
9808
|
if (!isRelative(p)) continue;
|
|
9809
|
+
if (shouldSkip?.(p)) continue;
|
|
9807
9810
|
if (!proxyDep(p)) stmts.push(js`${hot()}.accept(${p}, ${invalidateCb()});`);
|
|
9808
9811
|
}
|
|
9809
9812
|
return stmts;
|
|
@@ -9864,6 +9867,14 @@ function isComponentImportSource(source) {
|
|
|
9864
9867
|
if (source.startsWith("node:")) return false;
|
|
9865
9868
|
return true;
|
|
9866
9869
|
}
|
|
9870
|
+
/**
|
|
9871
|
+
* In dev mode, convert relative store imports (e.g. `import { router } from '../router'`)
|
|
9872
|
+
* to `const { router } = await import('../router')` placed after all class declarations.
|
|
9873
|
+
*
|
|
9874
|
+
* This breaks circular-dependency TDZ during HMR: classes are fully initialized
|
|
9875
|
+
* before the store module is loaded, so the store can safely import the component
|
|
9876
|
+
* classes back without hitting the temporal dead zone.
|
|
9877
|
+
*/
|
|
9867
9878
|
function transform(ctx) {
|
|
9868
9879
|
const { sourceFile, code, isServe, isSSR, hmrImportSource } = ctx;
|
|
9869
9880
|
if (!(code.includes("<") && code.includes(">"))) return null;
|
|
@@ -9889,7 +9900,6 @@ function transform(ctx) {
|
|
|
9889
9900
|
let transformed = false;
|
|
9890
9901
|
const componentImportSet = /* @__PURE__ */ new Set();
|
|
9891
9902
|
const componentImportsUsedAsTags = /* @__PURE__ */ new Set();
|
|
9892
|
-
let isDefaultExport = false;
|
|
9893
9903
|
imports.forEach((source) => {
|
|
9894
9904
|
if (!isComponentImportSource(source)) return;
|
|
9895
9905
|
componentImportSet.add(source);
|
|
@@ -9899,9 +9909,6 @@ function transform(ctx) {
|
|
|
9899
9909
|
const knownComponentImports = /* @__PURE__ */ new Set();
|
|
9900
9910
|
const namedImportSources = /* @__PURE__ */ new Map();
|
|
9901
9911
|
traverse(ast, {
|
|
9902
|
-
ExportDefaultDeclaration() {
|
|
9903
|
-
isDefaultExport = true;
|
|
9904
|
-
},
|
|
9905
9912
|
ImportDeclaration(path) {
|
|
9906
9913
|
const source = path.node.source.value;
|
|
9907
9914
|
if (!isComponentImportSource(source)) return;
|
|
@@ -9950,7 +9957,9 @@ function transform(ctx) {
|
|
|
9950
9957
|
}
|
|
9951
9958
|
} else transformed = transformNonComponentJSX(ast, imports);
|
|
9952
9959
|
}
|
|
9953
|
-
if (isServe &&
|
|
9960
|
+
if (isServe && componentClassNames.length > 0) {
|
|
9961
|
+
let defaultExportClassName = null;
|
|
9962
|
+
for (const node of ast.program.body) if (t.isExportDefaultDeclaration(node) && t.isClassDeclaration(node.declaration) && node.declaration.id) defaultExportClassName = node.declaration.id.name;
|
|
9954
9963
|
const shouldProxyDep = (source) => {
|
|
9955
9964
|
if (!source.startsWith(".")) return false;
|
|
9956
9965
|
const resolved = ctx.resolveImportPath(sourceFile, source);
|
|
@@ -9959,7 +9968,13 @@ function transform(ctx) {
|
|
|
9959
9968
|
if (ctx.isComponentModule(resolved)) return true;
|
|
9960
9969
|
return false;
|
|
9961
9970
|
};
|
|
9962
|
-
|
|
9971
|
+
const shouldSkipDepAccept = (source) => {
|
|
9972
|
+
if (!source.startsWith(".")) return false;
|
|
9973
|
+
const resolved = ctx.resolveImportPath(sourceFile, source);
|
|
9974
|
+
if (!resolved) return false;
|
|
9975
|
+
return ctx.isStoreModule(resolved);
|
|
9976
|
+
};
|
|
9977
|
+
if (injectHMR(ast, componentClassNames, defaultExportClassName, componentImports, componentImportsUsedAsTags, hmrImportSource, shouldProxyDep, shouldSkipDepAccept)) transformed = true;
|
|
9963
9978
|
}
|
|
9964
9979
|
if (!transformed) return null;
|
|
9965
9980
|
ensureGeaCompilerSymbolImports(ast);
|
|
@@ -10038,6 +10053,13 @@ export function reconcile(oldC, newC) {
|
|
|
10038
10053
|
}
|
|
10039
10054
|
`;
|
|
10040
10055
|
const HMR_RUNTIME_SOURCE = `
|
|
10056
|
+
var GEA_ELEMENT = Symbol.for('gea.element');
|
|
10057
|
+
var GEA_RENDERED = Symbol.for('gea.rendered');
|
|
10058
|
+
var GEA_CLEANUP_BINDINGS = Symbol.for('gea.component.cleanupBindings');
|
|
10059
|
+
var GEA_TEARDOWN_SELF_LISTENERS = Symbol.for('gea.component.teardownSelfListeners');
|
|
10060
|
+
var GEA_CHILD_COMPONENTS = Symbol.for('gea.childComponents');
|
|
10061
|
+
var GEA_BINDINGS = Symbol.for('gea.bindings');
|
|
10062
|
+
var GEA_SELF_LISTENERS = Symbol.for('gea.selfListeners');
|
|
10041
10063
|
var hot = import.meta.hot;
|
|
10042
10064
|
var componentInstances = hot && hot.data && hot.data.componentInstances || new Map();
|
|
10043
10065
|
if (hot) hot.data.componentInstances = componentInstances;
|
|
@@ -10349,7 +10371,7 @@ function geaPlugin() {
|
|
|
10349
10371
|
}
|
|
10350
10372
|
}
|
|
10351
10373
|
if (/\bclass\s+Component\s+extends\s+Store\b/.test(code)) return null;
|
|
10352
|
-
|
|
10374
|
+
const result = transform({
|
|
10353
10375
|
sourceFile: cleanId,
|
|
10354
10376
|
code,
|
|
10355
10377
|
isServe: isServeCommand,
|
|
@@ -10361,8 +10383,50 @@ function geaPlugin() {
|
|
|
10361
10383
|
registerStoreModule: (fp) => storeModules.add(fp),
|
|
10362
10384
|
registerComponentModule: (fp) => componentModules.add(fp)
|
|
10363
10385
|
});
|
|
10386
|
+
if (result) return result;
|
|
10387
|
+
if (isServeCommand && !isSSR) {
|
|
10388
|
+
const componentDeps = findComponentDeps(code, cleanId);
|
|
10389
|
+
if (componentDeps.length > 0) return {
|
|
10390
|
+
code: code + `\nif (import.meta.hot) {\n${componentDeps.map((dep) => ` import.meta.hot.accept('${dep}', () => {});`).join("\n")}\n}\n`,
|
|
10391
|
+
map: null
|
|
10392
|
+
};
|
|
10393
|
+
}
|
|
10394
|
+
return null;
|
|
10364
10395
|
}
|
|
10365
10396
|
};
|
|
10366
10397
|
}
|
|
10398
|
+
function resolveToFile(base) {
|
|
10399
|
+
const exts = [
|
|
10400
|
+
".ts",
|
|
10401
|
+
".tsx",
|
|
10402
|
+
".js",
|
|
10403
|
+
".jsx"
|
|
10404
|
+
];
|
|
10405
|
+
const indexFiles = exts.map((ext) => resolve(base, "index" + ext));
|
|
10406
|
+
const candidates = [
|
|
10407
|
+
base,
|
|
10408
|
+
...exts.map((ext) => base + ext),
|
|
10409
|
+
...indexFiles
|
|
10410
|
+
];
|
|
10411
|
+
for (const c of candidates) try {
|
|
10412
|
+
if (existsSync(c) && statSync(c).isFile()) return c;
|
|
10413
|
+
} catch {}
|
|
10414
|
+
return null;
|
|
10415
|
+
}
|
|
10416
|
+
function findComponentDeps(code, filePath) {
|
|
10417
|
+
const deps = [];
|
|
10418
|
+
const importRegex = /import\s+(?:[\w{},\s*]+)\s+from\s+['"](\.[^'"]+)['"]/g;
|
|
10419
|
+
let match;
|
|
10420
|
+
while ((match = importRegex.exec(code)) !== null) {
|
|
10421
|
+
const source = match[1];
|
|
10422
|
+
const resolved = resolveToFile(resolve(dirname(filePath), source));
|
|
10423
|
+
if (!resolved) continue;
|
|
10424
|
+
try {
|
|
10425
|
+
const depCode = readFileSync(resolved, "utf8");
|
|
10426
|
+
if (/class\s+\w+\s+extends\s+Component\b/.test(depCode) && depCode.includes("<") && depCode.includes(">")) deps.push(source);
|
|
10427
|
+
} catch {}
|
|
10428
|
+
}
|
|
10429
|
+
return deps;
|
|
10430
|
+
}
|
|
10367
10431
|
//#endregion
|
|
10368
10432
|
export { geaPlugin };
|