unplugin-essor 0.0.17-beta.5 → 0.0.17-beta.6
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/astro.cjs +3 -3
- package/dist/astro.js +1 -1
- package/dist/chunk-KWEBR2TV.js +236 -0
- package/dist/chunk-KWEBR2TV.js.map +1 -0
- package/dist/chunk-KXK55FFZ.cjs +264 -0
- package/dist/chunk-KXK55FFZ.cjs.map +1 -0
- package/dist/esbuild.cjs +2 -2
- package/dist/esbuild.js +1 -1
- package/dist/farm.cjs +2 -2
- package/dist/farm.js +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.js +1 -1
- package/dist/rolldown.cjs +2 -2
- package/dist/rolldown.js +1 -1
- package/dist/rollup.cjs +2 -2
- package/dist/rollup.js +1 -1
- package/dist/rspack.cjs +2 -2
- package/dist/rspack.js +1 -1
- package/dist/vite.cjs +2 -2
- package/dist/vite.js +1 -1
- package/dist/webpack.cjs +2 -2
- package/dist/webpack.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-OH5T2AAA.cjs +0 -240
- package/dist/chunk-OH5T2AAA.cjs.map +0 -1
- package/dist/chunk-U2VPJOQJ.js +0 -212
- package/dist/chunk-U2VPJOQJ.js.map +0 -1
package/dist/astro.cjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkKXK55FFZ_cjs = require('./chunk-KXK55FFZ.cjs');
|
|
4
4
|
|
|
5
5
|
// src/astro.ts
|
|
6
6
|
var astro_default = (options) => ({
|
|
7
7
|
name: "unplugin-starter",
|
|
8
8
|
hooks: {
|
|
9
9
|
// eslint-disable-next-line require-await
|
|
10
|
-
"astro:config:setup": (astro) =>
|
|
10
|
+
"astro:config:setup": (astro) => chunkKXK55FFZ_cjs.__async(null, null, function* () {
|
|
11
11
|
var _a;
|
|
12
12
|
(_a = astro.config.vite).plugins || (_a.plugins = []);
|
|
13
|
-
astro.config.vite.plugins.push(
|
|
13
|
+
astro.config.vite.plugins.push(chunkKXK55FFZ_cjs.index_default.vite(options));
|
|
14
14
|
})
|
|
15
15
|
}
|
|
16
16
|
});
|
package/dist/astro.js
CHANGED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { createUnplugin } from 'unplugin';
|
|
2
|
+
import * as babel from '@babel/core';
|
|
3
|
+
import essorBabelPlugin from 'babel-plugin-essor';
|
|
4
|
+
import { createFilter } from 'vite';
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __defProps = Object.defineProperties;
|
|
8
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
9
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
25
|
+
var __async = (__this, __arguments, generator) => {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
var fulfilled = (value) => {
|
|
28
|
+
try {
|
|
29
|
+
step(generator.next(value));
|
|
30
|
+
} catch (e) {
|
|
31
|
+
reject(e);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var rejected = (value) => {
|
|
35
|
+
try {
|
|
36
|
+
step(generator.throw(value));
|
|
37
|
+
} catch (e) {
|
|
38
|
+
reject(e);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
42
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// raw-loader:/home/runner/work/essor/essor/packages/unplugin/src/hmr-runtime.js?raw
|
|
47
|
+
var hmr_runtime_default = "/**\n * Essor HMR Runtime - Registry-based Hot Module Replacement\n *\n * This runtime enables precise component-level HMR updates without full page reloads:\n *\n * 1. **Registry Tracking**: Each component id points to its latest implementation\n * 2. **Signature Tracking**: Components are tracked by code signatures (from babel plugin)\n * 3. **Precise Updates**: Only components with changed signatures are updated\n * 4. **Instance Reloading**: Live component instances remount when their implementation changes\n * 5. **Bundler Agnostic**: Works with Vite, Webpack, Rspack, and other bundlers\n */\nimport { createComponent, onDestroy } from 'essor';\n\nconst isFunction = (value) => typeof value === 'function';\nconst ESSOR_HMR = 'essor-hmr';\n/**\n * Global component registry for HMR tracking\n *\n * Maps hmrId -> ComponentInfo where:\n * - hmrId: Unique identifier for component (fileHash:componentName)\n * - component: Current component function\n * - signature: Hash of component code (changes when code changes)\n * - instances: Set of active component instances\n * - updated: True after HMR applies a newer implementation\n */\nconst componentRegistry = new Map();\n\nfunction cleanupInstance(hmrId, info, component) {\n info.instances.delete(component);\n\n if (info.instances.size === 0 && !info.updated && componentRegistry.get(hmrId) === info) {\n componentRegistry.delete(hmrId);\n }\n}\n\n/**\n * Utility function to handle invalidate or reload\n * @param hot - Hot module API object\n */\nfunction invalidateOrReload(hot) {\n if (isFunction(hot?.invalidate)) {\n hot.invalidate();\n } else if (typeof location !== 'undefined') {\n location.reload();\n }\n}\n\n/**\n * Create HMR-enabled component wrapper\n *\n * This function wraps a component to enable HMR:\n * 1. Creates or retrieves component registry entry\n * 2. Creates the component from the latest registered implementation\n * 3. Tracks the instance until destroy()\n * 4. applyUpdate() remounts tracked instances when the implementation changes\n *\n * @param componentFn - Component function with __hmrId and __signature\n * @param props - Component props\n * @returns Component instance that responds to HMR updates\n */\nexport function createHMRComponent(componentFn, props) {\n const { __hmrId: hmrId, __signature: signature } = componentFn;\n\n if (!hmrId) {\n // If no hmrId, create normal component\n return createComponent(componentFn, props);\n }\n\n let info = componentRegistry.get(hmrId);\n\n if (!info) {\n info = {\n component: componentFn,\n signature,\n instances: new Set(),\n updated: false,\n };\n componentRegistry.set(hmrId, info);\n } else if (info.instances.size === 0 && !info.updated) {\n info.signature = signature;\n info.component = componentFn;\n }\n\n let component;\n let disposed = false;\n let isForceUpdating = false;\n const cleanupHMR = () => {\n if (isForceUpdating) return;\n if (disposed) return;\n disposed = true;\n cleanupInstance(hmrId, info, component);\n };\n\n // Use a stable boundary function so destroy cleanup is registered only\n // after the component is mounted inside a real Essor scope. This also lets\n // stale closures render the latest implementation after a hot update.\n function HMRBoundary(nextProps) {\n onDestroy(cleanupHMR);\n return info.component.call(this, nextProps);\n }\n\n component = createComponent(HMRBoundary, props);\n info.instances.add(component);\n\n const originalForceUpdate = component.forceUpdate;\n if (isFunction(originalForceUpdate)) {\n component.forceUpdate = function (...args) {\n isForceUpdating = true;\n try {\n return originalForceUpdate.apply(this, args);\n } finally {\n isForceUpdating = false;\n }\n };\n }\n\n // Integrate with component lifecycle - cleanup only when the component is\n // actually unmounted, not during forceUpdate's destroy/remount cycle.\n const originalDestroy = component.destroy;\n component.destroy = function (...args) {\n try {\n if (isFunction(originalDestroy)) {\n return originalDestroy.apply(this, args);\n }\n } finally {\n if (!isForceUpdating) {\n cleanupHMR();\n }\n }\n };\n\n return component;\n}\n\n/**\n * Determine if a component needs to be updated\n *\n * A component should update if:\n * 1. Function instance changed (indicates module was re-executed)\n * 2. Signature changed (indicates component code was modified)\n *\n * @param oldInfo - Existing component registry info\n * @param newComponentFn - New component function from updated module\n * @param newSignature - New signature hash from updated module\n * @returns true if component should update\n */\nfunction shouldUpdate(oldInfo, newComponentFn, newSignature) {\n if (!oldInfo) return true;\n\n // Check function instance (handles constant updates via module re-execution)\n if (oldInfo.component !== newComponentFn) {\n return true;\n }\n\n // Check compile-time signature (handles component code changes)\n return oldInfo.signature !== newSignature;\n}\n\n/**\n * Check if a value is an HMR-enabled component\n *\n * @param value - Value to check\n * @returns true if value is a function with __hmrId property\n */\nfunction isHMRComponent(value) {\n return value && isFunction(value) && value.__hmrId;\n}\n\n/**\n * Apply HMR updates to components\n *\n * Iterates through the new component registry and force-updates live\n * component instances whose implementation changed.\n *\n * @param registry - Array of components from updated module\n * @returns true if reload needed (errors occurred), false otherwise\n */\nexport function applyUpdate(registry) {\n if (!Array.isArray(registry) || registry.length === 0) {\n return false;\n }\n\n let needsReload = false;\n\n for (const entry of registry) {\n if (!isHMRComponent(entry)) {\n continue;\n }\n\n const { __hmrId: hmrId, __signature: signature } = entry;\n const id = hmrId;\n const info = componentRegistry.get(hmrId);\n\n if (!info) {\n componentRegistry.set(hmrId, {\n component: entry,\n signature,\n instances: new Set(),\n updated: true,\n });\n continue;\n }\n\n // Use shouldUpdate to determine if update is needed\n if (!shouldUpdate(info, entry, signature)) {\n continue;\n }\n\n info.signature = signature;\n info.component = entry;\n info.updated = true;\n\n for (const component of [...info.instances]) {\n try {\n component.forceUpdate();\n } catch (error) {\n console.error(`[Essor HMR] Failed to update ${id}:`, error);\n cleanupInstance(hmrId, info, component);\n needsReload = true;\n }\n }\n }\n\n return needsReload;\n}\n\n/**\n * Common handler for HMR updates across bundlers\n * @param hot - Hot module API\n * @param newModule - Updated module\n * @returns true if handled successfully\n */\nfunction handleHMRUpdate(hot, newModule) {\n if (!newModule) {\n invalidateOrReload(hot);\n return false;\n }\n\n // Extract HMR components from new module\n const newRegistry = extractHMRComponents(newModule);\n if (newRegistry.length === 0) {\n return true;\n }\n\n const needsReload = applyUpdate(newRegistry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n return true;\n}\n\n/**\n * Setup HMR for Vite bundler\n *\n * Vite provides import.meta.hot.accept() callback that receives the new module\n */\nfunction setupViteHMR(hot, registry) {\n hot.data ??= {};\n const isUpdate = !!hot.data[ESSOR_HMR];\n hot.data[ESSOR_HMR] = registry;\n\n if (isUpdate) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n}\n\n/**\n * Setup HMR for Webpack/Rspack bundlers\n *\n * Webpack-style HMR uses module.hot.accept() and hot.data for state persistence\n */\nfunction setupWebpackHMR(hot, registry) {\n if (isFunction(hot.accept)) {\n hot.accept();\n }\n\n // Apply update if previous data exists from last hot reload\n if (hot.data?.[ESSOR_HMR]) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n\n // Save current registry for next update\n if (isFunction(hot.dispose)) {\n hot.dispose((data) => {\n data[ESSOR_HMR] = registry;\n });\n }\n}\n\n/**\n * Setup HMR for other bundlers (fallback)\n *\n * Attempts to work with any bundler that provides a basic hot module API\n */\nfunction setupStandardHMR(hot, registry) {\n // Try accept callback mode first (more efficient)\n if (isFunction(hot.accept)) {\n try {\n hot.accept((newModule) => handleHMRUpdate(hot, newModule));\n } catch {\n // Some bundlers don't support accept with callback\n // Fall back to simple accept (for Webpack-style pattern)\n try {\n hot.accept();\n } catch (error_) {\n console.warn('[Essor HMR] Failed to setup hot.accept:', error_);\n }\n }\n }\n\n // Setup dispose handler for state persistence\n if (isFunction(hot.dispose)) {\n hot.dispose((data) => {\n data.__$registry$__ = registry;\n data.__essor_timestamp__ = Date.now();\n });\n }\n\n // Apply update if previous data exists (for Webpack-style HMR)\n if (hot.data?.__$registry$__) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n}\n\n/**\n * Extract HMR components from a module\n *\n * Looks for __$registry$__ array first (generated by babel plugin),\n * then falls back to scanning all exports for HMR components\n *\n * @param module - Module object to scan\n * @returns Array of HMR component functions\n */\nfunction extractHMRComponents(module) {\n if (!module) return [];\n\n // Prefer __$registry$__\n if (Array.isArray(module.__$registry$__)) {\n return module.__$registry$__;\n }\n\n // Otherwise search in exports\n const components = [];\n for (const key of Object.keys(module)) {\n const value = module[key];\n if (isHMRComponent(value)) {\n components.push(value);\n }\n }\n return components;\n}\n\n/**\n * Main HMR entry point\n *\n * Called from transformed modules to set up HMR based on bundler type\n *\n * @param bundlerType - Type of bundler (vite, webpack5, rspack, etc.)\n * @param hot - Hot module API object (import.meta.hot or module.hot)\n * @param registry - Array of components from current module\n * @returns true if HMR setup succeeded, false otherwise\n */\nexport function hmrAccept(bundlerType, hot, registry) {\n if (!hot || !registry) {\n return false;\n }\n\n switch (bundlerType) {\n case 'vite':\n setupViteHMR(hot, registry);\n break;\n case 'webpack':\n case 'webpack5':\n case 'rspack':\n setupWebpackHMR(hot, registry);\n break;\n default:\n // Use standard HMR setup\n setupStandardHMR(hot, registry);\n break;\n }\n\n return true;\n}\n\n/**\n * Cleanup all instances of a component (utility function)\n *\n * @param hmrId - Component HMR ID\n * @returns Number of instances cleaned up\n */\nexport function unregisterAllInstances(hmrId) {\n const info = componentRegistry.get(hmrId);\n if (!info) return 0;\n\n let count = 0;\n for (const item of [...info.instances]) {\n try {\n cleanupInstance(hmrId, info, item);\n } catch (error) {\n console.error(`[Essor HMR] Failed to unregister component instance:`, error);\n }\n count++;\n }\n\n return count;\n}\n\n/**\n * Get registry information for debugging\n *\n * @returns Object mapping hmrId to component info (signature, instance count)\n */\nexport function getRegistryInfo() {\n const info = {};\n for (const [id, data] of componentRegistry) {\n info[id] = {\n signature: data.signature,\n instanceCount: data.instances.size,\n };\n }\n return info;\n}\n";
|
|
48
|
+
|
|
49
|
+
// src/index.ts
|
|
50
|
+
var VIRTUAL_MODULE_ID = "virtual:essor-hmr";
|
|
51
|
+
var RESOLVED_VIRTUAL_MODULE_ID = "\0virtual:essor-hmr";
|
|
52
|
+
var DEFAULT_OPTIONS = {
|
|
53
|
+
symbol: "$",
|
|
54
|
+
mode: "client",
|
|
55
|
+
props: true,
|
|
56
|
+
hmr: true,
|
|
57
|
+
enableFor: false,
|
|
58
|
+
omitClosingTags: true
|
|
59
|
+
};
|
|
60
|
+
var FILE_EXTENSION_REGEX = /\.[cm]?[jt]sx?$/i;
|
|
61
|
+
var SKIP_DIRECTORIES = ["node_modules", "dist", "public"];
|
|
62
|
+
var HMR_DISPOSE_PREFIX = "import.meta.hot?.dispose(";
|
|
63
|
+
var HMR_DISPOSE_SUFFIX = ");";
|
|
64
|
+
function detectBundler(meta) {
|
|
65
|
+
if (meta == null ? void 0 : meta.framework) {
|
|
66
|
+
switch (meta.framework) {
|
|
67
|
+
case "vite":
|
|
68
|
+
return "vite";
|
|
69
|
+
case "webpack":
|
|
70
|
+
return "webpack5";
|
|
71
|
+
case "rspack":
|
|
72
|
+
return "rspack";
|
|
73
|
+
case "rollup":
|
|
74
|
+
return "rollup";
|
|
75
|
+
case "esbuild":
|
|
76
|
+
return "esbuild";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (typeof process !== "undefined" && process.env) {
|
|
80
|
+
if (process.env.VITE || process.env.VITEST) return "vite";
|
|
81
|
+
if (process.env.WEBPACK_VERSION) return "webpack5";
|
|
82
|
+
if (process.env.RSPACK) return "rspack";
|
|
83
|
+
}
|
|
84
|
+
return "standard";
|
|
85
|
+
}
|
|
86
|
+
function extractHMRDisposeHandlers(code) {
|
|
87
|
+
const lines = code.split("\n");
|
|
88
|
+
const disposeHandlers = [];
|
|
89
|
+
const cleanedLines = lines.filter((line) => {
|
|
90
|
+
const trimmed = line.trim();
|
|
91
|
+
if (!trimmed.startsWith(HMR_DISPOSE_PREFIX) || !trimmed.endsWith(HMR_DISPOSE_SUFFIX)) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
disposeHandlers.push(trimmed.slice(HMR_DISPOSE_PREFIX.length, -HMR_DISPOSE_SUFFIX.length));
|
|
95
|
+
return false;
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
code: cleanedLines.join("\n"),
|
|
99
|
+
disposeHandlers
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function generateHMRCode(bundlerType, disposeHandlers = []) {
|
|
103
|
+
const imports = {
|
|
104
|
+
createHMRComponent: `import { createHMRComponent as __$createHMRComponent$__ } from "${VIRTUAL_MODULE_ID}";`,
|
|
105
|
+
hmrAccept: `import { hmrAccept as __$hmrAccept$__ } from "${VIRTUAL_MODULE_ID}";`
|
|
106
|
+
};
|
|
107
|
+
const disposeLines = disposeHandlers.map((handler) => ` import.meta.hot.dispose(${handler});`);
|
|
108
|
+
const register = bundlerType === "vite" ? [
|
|
109
|
+
"if (import.meta.hot) {",
|
|
110
|
+
...disposeLines,
|
|
111
|
+
" import.meta.hot.accept();",
|
|
112
|
+
' __$hmrAccept$__("vite", import.meta.hot, __$registry$__);',
|
|
113
|
+
"}"
|
|
114
|
+
].join("\n") : [
|
|
115
|
+
"if (import.meta.hot) {",
|
|
116
|
+
...disposeLines,
|
|
117
|
+
` __$hmrAccept$__("${bundlerType}", import.meta.hot, __$registry$__);`,
|
|
118
|
+
"}"
|
|
119
|
+
].join("\n");
|
|
120
|
+
return {
|
|
121
|
+
imports,
|
|
122
|
+
register
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
var unpluginFactory = (options = {}, meta) => {
|
|
126
|
+
const filter = createFilter(options.include, options.exclude);
|
|
127
|
+
const bundlerType = detectBundler(meta);
|
|
128
|
+
let isProd = process.env.NODE_ENV === "production";
|
|
129
|
+
const finalOptions = __spreadProps(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), options), {
|
|
130
|
+
bundler: bundlerType
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
name: "unplugin-essor",
|
|
134
|
+
/**
|
|
135
|
+
* Vite-specific config to preserve JSX so the babel plugin can handle it.
|
|
136
|
+
|
|
137
|
+
*/
|
|
138
|
+
vite: {
|
|
139
|
+
config() {
|
|
140
|
+
const ctx = this;
|
|
141
|
+
const isRolldownVite = !!(ctx == null ? void 0 : ctx.meta) && "rolldownVersion" in ctx.meta;
|
|
142
|
+
const key = isRolldownVite ? "oxc" : "esbuild";
|
|
143
|
+
return {
|
|
144
|
+
[key]: { jsx: "preserve" }
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
configResolved(config) {
|
|
148
|
+
isProd = config.command === "build";
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* Resolve virtual HMR runtime module
|
|
153
|
+
*/
|
|
154
|
+
resolveId(id) {
|
|
155
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
156
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* Load virtual HMR runtime module
|
|
162
|
+
*/
|
|
163
|
+
load(id) {
|
|
164
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
|
|
165
|
+
return {
|
|
166
|
+
code: hmr_runtime_default,
|
|
167
|
+
map: null
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
},
|
|
172
|
+
rolldown: {
|
|
173
|
+
options(opts) {
|
|
174
|
+
var _a;
|
|
175
|
+
(_a = opts.transform) != null ? _a : opts.transform = {
|
|
176
|
+
jsx: "preserve"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
/**
|
|
181
|
+
* Transform code with Babel plugin
|
|
182
|
+
*/
|
|
183
|
+
transform(code, id) {
|
|
184
|
+
if (SKIP_DIRECTORIES.some((p) => id.includes(p))) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (!filter(id) || !FILE_EXTENSION_REGEX.test(id)) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const babelOptions = __spreadProps(__spreadValues({}, finalOptions), { hmr: !isProd && finalOptions.hmr });
|
|
191
|
+
let result;
|
|
192
|
+
try {
|
|
193
|
+
result = babel.transformSync(code, {
|
|
194
|
+
filename: id,
|
|
195
|
+
sourceMaps: true,
|
|
196
|
+
sourceType: "module",
|
|
197
|
+
plugins: [[essorBabelPlugin, babelOptions]]
|
|
198
|
+
});
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error(`[unplugin-essor] Transform failed for ${id}:`, error);
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
if (!(result == null ? void 0 : result.code)) {
|
|
204
|
+
return code;
|
|
205
|
+
}
|
|
206
|
+
let finalCode = "";
|
|
207
|
+
if (babelOptions.hmr) {
|
|
208
|
+
const hmrResult = extractHMRDisposeHandlers(result.code);
|
|
209
|
+
const hmrCode = generateHMRCode(bundlerType, hmrResult.disposeHandlers);
|
|
210
|
+
const transformedCode = hmrResult.code;
|
|
211
|
+
if (transformedCode.includes("__$createHMRComponent$__")) {
|
|
212
|
+
finalCode = `${hmrCode.imports.createHMRComponent}
|
|
213
|
+
${finalCode}`;
|
|
214
|
+
}
|
|
215
|
+
finalCode += transformedCode;
|
|
216
|
+
if (transformedCode.includes("__$registry$__")) {
|
|
217
|
+
finalCode = `${hmrCode.imports.hmrAccept}
|
|
218
|
+
${finalCode}
|
|
219
|
+
${hmrCode.register}`;
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
finalCode += result.code;
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
code: finalCode,
|
|
226
|
+
map: result.map
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
var unplugin = /* @__PURE__ */ createUnplugin(unpluginFactory);
|
|
232
|
+
var index_default = unplugin;
|
|
233
|
+
|
|
234
|
+
export { __async, index_default, unplugin, unpluginFactory };
|
|
235
|
+
//# sourceMappingURL=chunk-KWEBR2TV.js.map
|
|
236
|
+
//# sourceMappingURL=chunk-KWEBR2TV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["raw-loader:/home/runner/work/essor/essor/packages/unplugin/src/hmr-runtime.js?raw","../src/index.ts"],"names":[],"mappings":"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","file":"chunk-KWEBR2TV.js","sourcesContent":["/**\n * Essor HMR Runtime - Registry-based Hot Module Replacement\n *\n * This runtime enables precise component-level HMR updates without full page reloads:\n *\n * 1. **Registry Tracking**: Each component id points to its latest implementation\n * 2. **Signature Tracking**: Components are tracked by code signatures (from babel plugin)\n * 3. **Precise Updates**: Only components with changed signatures are updated\n * 4. **Instance Reloading**: Live component instances remount when their implementation changes\n * 5. **Bundler Agnostic**: Works with Vite, Webpack, Rspack, and other bundlers\n */\nimport { createComponent, onDestroy } from 'essor';\n\nconst isFunction = (value) => typeof value === 'function';\nconst ESSOR_HMR = 'essor-hmr';\n/**\n * Global component registry for HMR tracking\n *\n * Maps hmrId -> ComponentInfo where:\n * - hmrId: Unique identifier for component (fileHash:componentName)\n * - component: Current component function\n * - signature: Hash of component code (changes when code changes)\n * - instances: Set of active component instances\n * - updated: True after HMR applies a newer implementation\n */\nconst componentRegistry = new Map();\n\nfunction cleanupInstance(hmrId, info, component) {\n info.instances.delete(component);\n\n if (info.instances.size === 0 && !info.updated && componentRegistry.get(hmrId) === info) {\n componentRegistry.delete(hmrId);\n }\n}\n\n/**\n * Utility function to handle invalidate or reload\n * @param hot - Hot module API object\n */\nfunction invalidateOrReload(hot) {\n if (isFunction(hot?.invalidate)) {\n hot.invalidate();\n } else if (typeof location !== 'undefined') {\n location.reload();\n }\n}\n\n/**\n * Create HMR-enabled component wrapper\n *\n * This function wraps a component to enable HMR:\n * 1. Creates or retrieves component registry entry\n * 2. Creates the component from the latest registered implementation\n * 3. Tracks the instance until destroy()\n * 4. applyUpdate() remounts tracked instances when the implementation changes\n *\n * @param componentFn - Component function with __hmrId and __signature\n * @param props - Component props\n * @returns Component instance that responds to HMR updates\n */\nexport function createHMRComponent(componentFn, props) {\n const { __hmrId: hmrId, __signature: signature } = componentFn;\n\n if (!hmrId) {\n // If no hmrId, create normal component\n return createComponent(componentFn, props);\n }\n\n let info = componentRegistry.get(hmrId);\n\n if (!info) {\n info = {\n component: componentFn,\n signature,\n instances: new Set(),\n updated: false,\n };\n componentRegistry.set(hmrId, info);\n } else if (info.instances.size === 0 && !info.updated) {\n info.signature = signature;\n info.component = componentFn;\n }\n\n let component;\n let disposed = false;\n let isForceUpdating = false;\n const cleanupHMR = () => {\n if (isForceUpdating) return;\n if (disposed) return;\n disposed = true;\n cleanupInstance(hmrId, info, component);\n };\n\n // Use a stable boundary function so destroy cleanup is registered only\n // after the component is mounted inside a real Essor scope. This also lets\n // stale closures render the latest implementation after a hot update.\n function HMRBoundary(nextProps) {\n onDestroy(cleanupHMR);\n return info.component.call(this, nextProps);\n }\n\n component = createComponent(HMRBoundary, props);\n info.instances.add(component);\n\n const originalForceUpdate = component.forceUpdate;\n if (isFunction(originalForceUpdate)) {\n component.forceUpdate = function (...args) {\n isForceUpdating = true;\n try {\n return originalForceUpdate.apply(this, args);\n } finally {\n isForceUpdating = false;\n }\n };\n }\n\n // Integrate with component lifecycle - cleanup only when the component is\n // actually unmounted, not during forceUpdate's destroy/remount cycle.\n const originalDestroy = component.destroy;\n component.destroy = function (...args) {\n try {\n if (isFunction(originalDestroy)) {\n return originalDestroy.apply(this, args);\n }\n } finally {\n if (!isForceUpdating) {\n cleanupHMR();\n }\n }\n };\n\n return component;\n}\n\n/**\n * Determine if a component needs to be updated\n *\n * A component should update if:\n * 1. Function instance changed (indicates module was re-executed)\n * 2. Signature changed (indicates component code was modified)\n *\n * @param oldInfo - Existing component registry info\n * @param newComponentFn - New component function from updated module\n * @param newSignature - New signature hash from updated module\n * @returns true if component should update\n */\nfunction shouldUpdate(oldInfo, newComponentFn, newSignature) {\n if (!oldInfo) return true;\n\n // Check function instance (handles constant updates via module re-execution)\n if (oldInfo.component !== newComponentFn) {\n return true;\n }\n\n // Check compile-time signature (handles component code changes)\n return oldInfo.signature !== newSignature;\n}\n\n/**\n * Check if a value is an HMR-enabled component\n *\n * @param value - Value to check\n * @returns true if value is a function with __hmrId property\n */\nfunction isHMRComponent(value) {\n return value && isFunction(value) && value.__hmrId;\n}\n\n/**\n * Apply HMR updates to components\n *\n * Iterates through the new component registry and force-updates live\n * component instances whose implementation changed.\n *\n * @param registry - Array of components from updated module\n * @returns true if reload needed (errors occurred), false otherwise\n */\nexport function applyUpdate(registry) {\n if (!Array.isArray(registry) || registry.length === 0) {\n return false;\n }\n\n let needsReload = false;\n\n for (const entry of registry) {\n if (!isHMRComponent(entry)) {\n continue;\n }\n\n const { __hmrId: hmrId, __signature: signature } = entry;\n const id = hmrId;\n const info = componentRegistry.get(hmrId);\n\n if (!info) {\n componentRegistry.set(hmrId, {\n component: entry,\n signature,\n instances: new Set(),\n updated: true,\n });\n continue;\n }\n\n // Use shouldUpdate to determine if update is needed\n if (!shouldUpdate(info, entry, signature)) {\n continue;\n }\n\n info.signature = signature;\n info.component = entry;\n info.updated = true;\n\n for (const component of [...info.instances]) {\n try {\n component.forceUpdate();\n } catch (error) {\n console.error(`[Essor HMR] Failed to update ${id}:`, error);\n cleanupInstance(hmrId, info, component);\n needsReload = true;\n }\n }\n }\n\n return needsReload;\n}\n\n/**\n * Common handler for HMR updates across bundlers\n * @param hot - Hot module API\n * @param newModule - Updated module\n * @returns true if handled successfully\n */\nfunction handleHMRUpdate(hot, newModule) {\n if (!newModule) {\n invalidateOrReload(hot);\n return false;\n }\n\n // Extract HMR components from new module\n const newRegistry = extractHMRComponents(newModule);\n if (newRegistry.length === 0) {\n return true;\n }\n\n const needsReload = applyUpdate(newRegistry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n return true;\n}\n\n/**\n * Setup HMR for Vite bundler\n *\n * Vite provides import.meta.hot.accept() callback that receives the new module\n */\nfunction setupViteHMR(hot, registry) {\n hot.data ??= {};\n const isUpdate = !!hot.data[ESSOR_HMR];\n hot.data[ESSOR_HMR] = registry;\n\n if (isUpdate) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n}\n\n/**\n * Setup HMR for Webpack/Rspack bundlers\n *\n * Webpack-style HMR uses module.hot.accept() and hot.data for state persistence\n */\nfunction setupWebpackHMR(hot, registry) {\n if (isFunction(hot.accept)) {\n hot.accept();\n }\n\n // Apply update if previous data exists from last hot reload\n if (hot.data?.[ESSOR_HMR]) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n\n // Save current registry for next update\n if (isFunction(hot.dispose)) {\n hot.dispose((data) => {\n data[ESSOR_HMR] = registry;\n });\n }\n}\n\n/**\n * Setup HMR for other bundlers (fallback)\n *\n * Attempts to work with any bundler that provides a basic hot module API\n */\nfunction setupStandardHMR(hot, registry) {\n // Try accept callback mode first (more efficient)\n if (isFunction(hot.accept)) {\n try {\n hot.accept((newModule) => handleHMRUpdate(hot, newModule));\n } catch {\n // Some bundlers don't support accept with callback\n // Fall back to simple accept (for Webpack-style pattern)\n try {\n hot.accept();\n } catch (error_) {\n console.warn('[Essor HMR] Failed to setup hot.accept:', error_);\n }\n }\n }\n\n // Setup dispose handler for state persistence\n if (isFunction(hot.dispose)) {\n hot.dispose((data) => {\n data.__$registry$__ = registry;\n data.__essor_timestamp__ = Date.now();\n });\n }\n\n // Apply update if previous data exists (for Webpack-style HMR)\n if (hot.data?.__$registry$__) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n}\n\n/**\n * Extract HMR components from a module\n *\n * Looks for __$registry$__ array first (generated by babel plugin),\n * then falls back to scanning all exports for HMR components\n *\n * @param module - Module object to scan\n * @returns Array of HMR component functions\n */\nfunction extractHMRComponents(module) {\n if (!module) return [];\n\n // Prefer __$registry$__\n if (Array.isArray(module.__$registry$__)) {\n return module.__$registry$__;\n }\n\n // Otherwise search in exports\n const components = [];\n for (const key of Object.keys(module)) {\n const value = module[key];\n if (isHMRComponent(value)) {\n components.push(value);\n }\n }\n return components;\n}\n\n/**\n * Main HMR entry point\n *\n * Called from transformed modules to set up HMR based on bundler type\n *\n * @param bundlerType - Type of bundler (vite, webpack5, rspack, etc.)\n * @param hot - Hot module API object (import.meta.hot or module.hot)\n * @param registry - Array of components from current module\n * @returns true if HMR setup succeeded, false otherwise\n */\nexport function hmrAccept(bundlerType, hot, registry) {\n if (!hot || !registry) {\n return false;\n }\n\n switch (bundlerType) {\n case 'vite':\n setupViteHMR(hot, registry);\n break;\n case 'webpack':\n case 'webpack5':\n case 'rspack':\n setupWebpackHMR(hot, registry);\n break;\n default:\n // Use standard HMR setup\n setupStandardHMR(hot, registry);\n break;\n }\n\n return true;\n}\n\n/**\n * Cleanup all instances of a component (utility function)\n *\n * @param hmrId - Component HMR ID\n * @returns Number of instances cleaned up\n */\nexport function unregisterAllInstances(hmrId) {\n const info = componentRegistry.get(hmrId);\n if (!info) return 0;\n\n let count = 0;\n for (const item of [...info.instances]) {\n try {\n cleanupInstance(hmrId, info, item);\n } catch (error) {\n console.error(`[Essor HMR] Failed to unregister component instance:`, error);\n }\n count++;\n }\n\n return count;\n}\n\n/**\n * Get registry information for debugging\n *\n * @returns Object mapping hmrId to component info (signature, instance count)\n */\nexport function getRegistryInfo() {\n const info = {};\n for (const [id, data] of componentRegistry) {\n info[id] = {\n signature: data.signature,\n instanceCount: data.instances.size,\n };\n }\n return info;\n}\n","import { createUnplugin } from 'unplugin';\nimport * as babel from '@babel/core';\nimport essorBabelPlugin from 'babel-plugin-essor';\nimport { createFilter } from 'vite';\n// @ts-ignore - resolved by esbuild raw plugin at build time\nimport hmrRuntimeCode from './hmr-runtime.js?raw';\nimport type { UnpluginContextMeta, UnpluginFactory } from 'unplugin';\nimport type { Options } from './types';\n\n/**\n * Virtual module ID for HMR runtime\n * Injected as an import in transformed files that have HMR components\n */\nconst VIRTUAL_MODULE_ID = 'virtual:essor-hmr';\nconst RESOLVED_VIRTUAL_MODULE_ID = '\\0virtual:essor-hmr';\n\n/**\n * Default plugin options\n */\nconst DEFAULT_OPTIONS = {\n symbol: '$',\n mode: 'client',\n props: true,\n hmr: true,\n enableFor: false,\n omitClosingTags: true,\n};\n\n/**\n * Performance: Pre-compiled regex and constants\n */\nconst FILE_EXTENSION_REGEX = /\\.[cm]?[jt]sx?$/i;\nconst SKIP_DIRECTORIES = ['node_modules', 'dist', 'public'];\nconst HMR_DISPOSE_PREFIX = 'import.meta.hot?.dispose(';\nconst HMR_DISPOSE_SUFFIX = ');';\n\ntype BundlerType = 'vite' | 'webpack5' | 'rspack' | 'rollup' | 'esbuild' | 'standard';\n\n/**\n * Detect bundler type from unplugin meta or environment variables\n *\n * This is important for HMR because different bundlers have different\n * HMR APIs (import.meta.hot.accept, module.hot.accept, etc.)\n */\nfunction detectBundler(meta: UnpluginContextMeta): BundlerType {\n // First, try to detect from unplugin meta\n if (meta?.framework) {\n switch (meta.framework) {\n case 'vite':\n return 'vite';\n case 'webpack':\n return 'webpack5';\n case 'rspack':\n return 'rspack';\n case 'rollup':\n return 'rollup';\n case 'esbuild':\n return 'esbuild';\n }\n }\n\n // Fallback: detect from environment variables\n if (typeof process !== 'undefined' && process.env) {\n if (process.env.VITE || process.env.VITEST) return 'vite';\n if (process.env.WEBPACK_VERSION) return 'webpack5';\n if (process.env.RSPACK) return 'rspack';\n }\n\n // Default to standard if detection fails\n return 'standard';\n}\n\n/**\n * Extract mount cleanup handlers emitted by the Babel HMR pass.\n *\n * @param code - Transformed module code.\n * @returns Module code without inline disposal calls and the extracted handlers.\n */\nfunction extractHMRDisposeHandlers(code: string) {\n const lines = code.split('\\n');\n const disposeHandlers: string[] = [];\n const cleanedLines = lines.filter((line) => {\n const trimmed = line.trim();\n if (!trimmed.startsWith(HMR_DISPOSE_PREFIX) || !trimmed.endsWith(HMR_DISPOSE_SUFFIX)) {\n return true;\n }\n\n disposeHandlers.push(trimmed.slice(HMR_DISPOSE_PREFIX.length, -HMR_DISPOSE_SUFFIX.length));\n return false;\n });\n\n return {\n code: cleanedLines.join('\\n'),\n disposeHandlers,\n };\n}\n\nfunction generateHMRCode(bundlerType: BundlerType, disposeHandlers: string[] = []) {\n // Import HMR utilities from virtual module\n const imports = {\n createHMRComponent: `import { createHMRComponent as __$createHMRComponent$__ } from \"${VIRTUAL_MODULE_ID}\";`,\n hmrAccept: `import { hmrAccept as __$hmrAccept$__ } from \"${VIRTUAL_MODULE_ID}\";`,\n };\n const disposeLines = disposeHandlers.map((handler) => ` import.meta.hot.dispose(${handler});`);\n\n const register =\n bundlerType === 'vite'\n ? [\n 'if (import.meta.hot) {',\n ...disposeLines,\n ' import.meta.hot.accept();',\n ' __$hmrAccept$__(\"vite\", import.meta.hot, __$registry$__);',\n '}',\n ].join('\\n')\n : [\n 'if (import.meta.hot) {',\n ...disposeLines,\n ` __$hmrAccept$__(\"${bundlerType}\", import.meta.hot, __$registry$__);`,\n '}',\n ].join('\\n');\n\n return {\n imports,\n register,\n };\n}\n\nexport const unpluginFactory: UnpluginFactory<Options | undefined> = (\n options: Options = {},\n meta,\n) => {\n // Create file filter based on include/exclude patterns\n const filter = createFilter(options.include, options.exclude);\n\n // Detect bundler type for HMR\n const bundlerType = detectBundler(meta);\n\n // NODE_ENV is set by most bundlers; fallback treats unknown env as dev (HMR on)\n let isProd = process.env.NODE_ENV === 'production';\n\n // Merge user options with defaults (hmr excluded — computed dynamically in transform)\n const finalOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n bundler: bundlerType,\n };\n\n return {\n name: 'unplugin-essor',\n /**\n * Vite-specific config to preserve JSX so the babel plugin can handle it.\n \n */\n vite: {\n config(this: unknown) {\n // Inside a vite hook, `this` is the rollup plugin context. On Vite 8 /\n // rolldown-vite it exposes `meta.rolldownVersion`.\n const ctx = this as { meta?: Record<string, unknown> } | undefined;\n const isRolldownVite = !!ctx?.meta && 'rolldownVersion' in ctx.meta;\n const key = (isRolldownVite ? 'oxc' : 'esbuild') as 'esbuild';\n return {\n [key]: { jsx: 'preserve' },\n };\n },\n configResolved(config: { command: string }) {\n // Vite's command is more reliable than NODE_ENV for detecting dev vs build\n isProd = config.command === 'build';\n },\n },\n\n /**\n * Resolve virtual HMR runtime module\n */\n resolveId(id: string) {\n if (id === VIRTUAL_MODULE_ID) {\n return RESOLVED_VIRTUAL_MODULE_ID;\n }\n return null;\n },\n\n /**\n * Load virtual HMR runtime module\n */\n load(id: string) {\n if (id === RESOLVED_VIRTUAL_MODULE_ID) {\n return {\n code: hmrRuntimeCode,\n map: null,\n };\n }\n return null;\n },\n rolldown: {\n options(opts) {\n opts.transform ??= {\n jsx: 'preserve',\n };\n },\n },\n /**\n * Transform code with Babel plugin\n */\n transform(code, id) {\n // Skip node_modules, dist, and public directories\n if (SKIP_DIRECTORIES.some((p) => id.includes(p))) {\n return;\n }\n\n // Only transform JS/TS files\n if (!filter(id) || !FILE_EXTENSION_REGEX.test(id)) {\n return null;\n }\n\n // options.hmr explicit value wins; otherwise enable only in dev\n const babelOptions = { ...finalOptions, hmr: !isProd && finalOptions.hmr };\n\n // Transform with Babel (with error handling)\n let result;\n try {\n result = babel.transformSync(code, {\n filename: id,\n sourceMaps: true,\n sourceType: 'module',\n plugins: [[essorBabelPlugin, babelOptions]],\n });\n } catch (error) {\n console.error(`[unplugin-essor] Transform failed for ${id}:`, error);\n return null;\n }\n\n if (!result?.code) {\n return code;\n }\n\n let finalCode = '';\n\n // Inject HMR code if enabled and components are present\n if (babelOptions.hmr) {\n const hmrResult = extractHMRDisposeHandlers(result.code);\n const hmrCode = generateHMRCode(bundlerType, hmrResult.disposeHandlers);\n const transformedCode = hmrResult.code;\n\n if (transformedCode.includes('__$createHMRComponent$__')) {\n finalCode = `${hmrCode.imports.createHMRComponent}\\n${finalCode}`;\n }\n finalCode += transformedCode;\n if (transformedCode.includes('__$registry$__')) {\n finalCode = `${hmrCode.imports.hmrAccept}\\n${finalCode}\\n${hmrCode.register}`;\n }\n } else {\n finalCode += result.code;\n }\n\n return {\n code: finalCode,\n map: result.map,\n };\n },\n };\n};\n\nexport const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory);\n\nexport default unplugin;\n"]}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var unplugin$1 = require('unplugin');
|
|
4
|
+
var babel = require('@babel/core');
|
|
5
|
+
var essorBabelPlugin = require('babel-plugin-essor');
|
|
6
|
+
var vite = require('vite');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var babel__namespace = /*#__PURE__*/_interopNamespace(babel);
|
|
29
|
+
var essorBabelPlugin__default = /*#__PURE__*/_interopDefault(essorBabelPlugin);
|
|
30
|
+
|
|
31
|
+
var __defProp = Object.defineProperty;
|
|
32
|
+
var __defProps = Object.defineProperties;
|
|
33
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
34
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
35
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
36
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
37
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
38
|
+
var __spreadValues = (a, b) => {
|
|
39
|
+
for (var prop in b || (b = {}))
|
|
40
|
+
if (__hasOwnProp.call(b, prop))
|
|
41
|
+
__defNormalProp(a, prop, b[prop]);
|
|
42
|
+
if (__getOwnPropSymbols)
|
|
43
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
44
|
+
if (__propIsEnum.call(b, prop))
|
|
45
|
+
__defNormalProp(a, prop, b[prop]);
|
|
46
|
+
}
|
|
47
|
+
return a;
|
|
48
|
+
};
|
|
49
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
50
|
+
var __async = (__this, __arguments, generator) => {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
var fulfilled = (value) => {
|
|
53
|
+
try {
|
|
54
|
+
step(generator.next(value));
|
|
55
|
+
} catch (e) {
|
|
56
|
+
reject(e);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var rejected = (value) => {
|
|
60
|
+
try {
|
|
61
|
+
step(generator.throw(value));
|
|
62
|
+
} catch (e) {
|
|
63
|
+
reject(e);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
67
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// raw-loader:/home/runner/work/essor/essor/packages/unplugin/src/hmr-runtime.js?raw
|
|
72
|
+
var hmr_runtime_default = "/**\n * Essor HMR Runtime - Registry-based Hot Module Replacement\n *\n * This runtime enables precise component-level HMR updates without full page reloads:\n *\n * 1. **Registry Tracking**: Each component id points to its latest implementation\n * 2. **Signature Tracking**: Components are tracked by code signatures (from babel plugin)\n * 3. **Precise Updates**: Only components with changed signatures are updated\n * 4. **Instance Reloading**: Live component instances remount when their implementation changes\n * 5. **Bundler Agnostic**: Works with Vite, Webpack, Rspack, and other bundlers\n */\nimport { createComponent, onDestroy } from 'essor';\n\nconst isFunction = (value) => typeof value === 'function';\nconst ESSOR_HMR = 'essor-hmr';\n/**\n * Global component registry for HMR tracking\n *\n * Maps hmrId -> ComponentInfo where:\n * - hmrId: Unique identifier for component (fileHash:componentName)\n * - component: Current component function\n * - signature: Hash of component code (changes when code changes)\n * - instances: Set of active component instances\n * - updated: True after HMR applies a newer implementation\n */\nconst componentRegistry = new Map();\n\nfunction cleanupInstance(hmrId, info, component) {\n info.instances.delete(component);\n\n if (info.instances.size === 0 && !info.updated && componentRegistry.get(hmrId) === info) {\n componentRegistry.delete(hmrId);\n }\n}\n\n/**\n * Utility function to handle invalidate or reload\n * @param hot - Hot module API object\n */\nfunction invalidateOrReload(hot) {\n if (isFunction(hot?.invalidate)) {\n hot.invalidate();\n } else if (typeof location !== 'undefined') {\n location.reload();\n }\n}\n\n/**\n * Create HMR-enabled component wrapper\n *\n * This function wraps a component to enable HMR:\n * 1. Creates or retrieves component registry entry\n * 2. Creates the component from the latest registered implementation\n * 3. Tracks the instance until destroy()\n * 4. applyUpdate() remounts tracked instances when the implementation changes\n *\n * @param componentFn - Component function with __hmrId and __signature\n * @param props - Component props\n * @returns Component instance that responds to HMR updates\n */\nexport function createHMRComponent(componentFn, props) {\n const { __hmrId: hmrId, __signature: signature } = componentFn;\n\n if (!hmrId) {\n // If no hmrId, create normal component\n return createComponent(componentFn, props);\n }\n\n let info = componentRegistry.get(hmrId);\n\n if (!info) {\n info = {\n component: componentFn,\n signature,\n instances: new Set(),\n updated: false,\n };\n componentRegistry.set(hmrId, info);\n } else if (info.instances.size === 0 && !info.updated) {\n info.signature = signature;\n info.component = componentFn;\n }\n\n let component;\n let disposed = false;\n let isForceUpdating = false;\n const cleanupHMR = () => {\n if (isForceUpdating) return;\n if (disposed) return;\n disposed = true;\n cleanupInstance(hmrId, info, component);\n };\n\n // Use a stable boundary function so destroy cleanup is registered only\n // after the component is mounted inside a real Essor scope. This also lets\n // stale closures render the latest implementation after a hot update.\n function HMRBoundary(nextProps) {\n onDestroy(cleanupHMR);\n return info.component.call(this, nextProps);\n }\n\n component = createComponent(HMRBoundary, props);\n info.instances.add(component);\n\n const originalForceUpdate = component.forceUpdate;\n if (isFunction(originalForceUpdate)) {\n component.forceUpdate = function (...args) {\n isForceUpdating = true;\n try {\n return originalForceUpdate.apply(this, args);\n } finally {\n isForceUpdating = false;\n }\n };\n }\n\n // Integrate with component lifecycle - cleanup only when the component is\n // actually unmounted, not during forceUpdate's destroy/remount cycle.\n const originalDestroy = component.destroy;\n component.destroy = function (...args) {\n try {\n if (isFunction(originalDestroy)) {\n return originalDestroy.apply(this, args);\n }\n } finally {\n if (!isForceUpdating) {\n cleanupHMR();\n }\n }\n };\n\n return component;\n}\n\n/**\n * Determine if a component needs to be updated\n *\n * A component should update if:\n * 1. Function instance changed (indicates module was re-executed)\n * 2. Signature changed (indicates component code was modified)\n *\n * @param oldInfo - Existing component registry info\n * @param newComponentFn - New component function from updated module\n * @param newSignature - New signature hash from updated module\n * @returns true if component should update\n */\nfunction shouldUpdate(oldInfo, newComponentFn, newSignature) {\n if (!oldInfo) return true;\n\n // Check function instance (handles constant updates via module re-execution)\n if (oldInfo.component !== newComponentFn) {\n return true;\n }\n\n // Check compile-time signature (handles component code changes)\n return oldInfo.signature !== newSignature;\n}\n\n/**\n * Check if a value is an HMR-enabled component\n *\n * @param value - Value to check\n * @returns true if value is a function with __hmrId property\n */\nfunction isHMRComponent(value) {\n return value && isFunction(value) && value.__hmrId;\n}\n\n/**\n * Apply HMR updates to components\n *\n * Iterates through the new component registry and force-updates live\n * component instances whose implementation changed.\n *\n * @param registry - Array of components from updated module\n * @returns true if reload needed (errors occurred), false otherwise\n */\nexport function applyUpdate(registry) {\n if (!Array.isArray(registry) || registry.length === 0) {\n return false;\n }\n\n let needsReload = false;\n\n for (const entry of registry) {\n if (!isHMRComponent(entry)) {\n continue;\n }\n\n const { __hmrId: hmrId, __signature: signature } = entry;\n const id = hmrId;\n const info = componentRegistry.get(hmrId);\n\n if (!info) {\n componentRegistry.set(hmrId, {\n component: entry,\n signature,\n instances: new Set(),\n updated: true,\n });\n continue;\n }\n\n // Use shouldUpdate to determine if update is needed\n if (!shouldUpdate(info, entry, signature)) {\n continue;\n }\n\n info.signature = signature;\n info.component = entry;\n info.updated = true;\n\n for (const component of [...info.instances]) {\n try {\n component.forceUpdate();\n } catch (error) {\n console.error(`[Essor HMR] Failed to update ${id}:`, error);\n cleanupInstance(hmrId, info, component);\n needsReload = true;\n }\n }\n }\n\n return needsReload;\n}\n\n/**\n * Common handler for HMR updates across bundlers\n * @param hot - Hot module API\n * @param newModule - Updated module\n * @returns true if handled successfully\n */\nfunction handleHMRUpdate(hot, newModule) {\n if (!newModule) {\n invalidateOrReload(hot);\n return false;\n }\n\n // Extract HMR components from new module\n const newRegistry = extractHMRComponents(newModule);\n if (newRegistry.length === 0) {\n return true;\n }\n\n const needsReload = applyUpdate(newRegistry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n return true;\n}\n\n/**\n * Setup HMR for Vite bundler\n *\n * Vite provides import.meta.hot.accept() callback that receives the new module\n */\nfunction setupViteHMR(hot, registry) {\n hot.data ??= {};\n const isUpdate = !!hot.data[ESSOR_HMR];\n hot.data[ESSOR_HMR] = registry;\n\n if (isUpdate) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n}\n\n/**\n * Setup HMR for Webpack/Rspack bundlers\n *\n * Webpack-style HMR uses module.hot.accept() and hot.data for state persistence\n */\nfunction setupWebpackHMR(hot, registry) {\n if (isFunction(hot.accept)) {\n hot.accept();\n }\n\n // Apply update if previous data exists from last hot reload\n if (hot.data?.[ESSOR_HMR]) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n\n // Save current registry for next update\n if (isFunction(hot.dispose)) {\n hot.dispose((data) => {\n data[ESSOR_HMR] = registry;\n });\n }\n}\n\n/**\n * Setup HMR for other bundlers (fallback)\n *\n * Attempts to work with any bundler that provides a basic hot module API\n */\nfunction setupStandardHMR(hot, registry) {\n // Try accept callback mode first (more efficient)\n if (isFunction(hot.accept)) {\n try {\n hot.accept((newModule) => handleHMRUpdate(hot, newModule));\n } catch {\n // Some bundlers don't support accept with callback\n // Fall back to simple accept (for Webpack-style pattern)\n try {\n hot.accept();\n } catch (error_) {\n console.warn('[Essor HMR] Failed to setup hot.accept:', error_);\n }\n }\n }\n\n // Setup dispose handler for state persistence\n if (isFunction(hot.dispose)) {\n hot.dispose((data) => {\n data.__$registry$__ = registry;\n data.__essor_timestamp__ = Date.now();\n });\n }\n\n // Apply update if previous data exists (for Webpack-style HMR)\n if (hot.data?.__$registry$__) {\n const needsReload = applyUpdate(registry);\n if (needsReload) {\n invalidateOrReload(hot);\n }\n }\n}\n\n/**\n * Extract HMR components from a module\n *\n * Looks for __$registry$__ array first (generated by babel plugin),\n * then falls back to scanning all exports for HMR components\n *\n * @param module - Module object to scan\n * @returns Array of HMR component functions\n */\nfunction extractHMRComponents(module) {\n if (!module) return [];\n\n // Prefer __$registry$__\n if (Array.isArray(module.__$registry$__)) {\n return module.__$registry$__;\n }\n\n // Otherwise search in exports\n const components = [];\n for (const key of Object.keys(module)) {\n const value = module[key];\n if (isHMRComponent(value)) {\n components.push(value);\n }\n }\n return components;\n}\n\n/**\n * Main HMR entry point\n *\n * Called from transformed modules to set up HMR based on bundler type\n *\n * @param bundlerType - Type of bundler (vite, webpack5, rspack, etc.)\n * @param hot - Hot module API object (import.meta.hot or module.hot)\n * @param registry - Array of components from current module\n * @returns true if HMR setup succeeded, false otherwise\n */\nexport function hmrAccept(bundlerType, hot, registry) {\n if (!hot || !registry) {\n return false;\n }\n\n switch (bundlerType) {\n case 'vite':\n setupViteHMR(hot, registry);\n break;\n case 'webpack':\n case 'webpack5':\n case 'rspack':\n setupWebpackHMR(hot, registry);\n break;\n default:\n // Use standard HMR setup\n setupStandardHMR(hot, registry);\n break;\n }\n\n return true;\n}\n\n/**\n * Cleanup all instances of a component (utility function)\n *\n * @param hmrId - Component HMR ID\n * @returns Number of instances cleaned up\n */\nexport function unregisterAllInstances(hmrId) {\n const info = componentRegistry.get(hmrId);\n if (!info) return 0;\n\n let count = 0;\n for (const item of [...info.instances]) {\n try {\n cleanupInstance(hmrId, info, item);\n } catch (error) {\n console.error(`[Essor HMR] Failed to unregister component instance:`, error);\n }\n count++;\n }\n\n return count;\n}\n\n/**\n * Get registry information for debugging\n *\n * @returns Object mapping hmrId to component info (signature, instance count)\n */\nexport function getRegistryInfo() {\n const info = {};\n for (const [id, data] of componentRegistry) {\n info[id] = {\n signature: data.signature,\n instanceCount: data.instances.size,\n };\n }\n return info;\n}\n";
|
|
73
|
+
|
|
74
|
+
// src/index.ts
|
|
75
|
+
var VIRTUAL_MODULE_ID = "virtual:essor-hmr";
|
|
76
|
+
var RESOLVED_VIRTUAL_MODULE_ID = "\0virtual:essor-hmr";
|
|
77
|
+
var DEFAULT_OPTIONS = {
|
|
78
|
+
symbol: "$",
|
|
79
|
+
mode: "client",
|
|
80
|
+
props: true,
|
|
81
|
+
hmr: true,
|
|
82
|
+
enableFor: false,
|
|
83
|
+
omitClosingTags: true
|
|
84
|
+
};
|
|
85
|
+
var FILE_EXTENSION_REGEX = /\.[cm]?[jt]sx?$/i;
|
|
86
|
+
var SKIP_DIRECTORIES = ["node_modules", "dist", "public"];
|
|
87
|
+
var HMR_DISPOSE_PREFIX = "import.meta.hot?.dispose(";
|
|
88
|
+
var HMR_DISPOSE_SUFFIX = ");";
|
|
89
|
+
function detectBundler(meta) {
|
|
90
|
+
if (meta == null ? void 0 : meta.framework) {
|
|
91
|
+
switch (meta.framework) {
|
|
92
|
+
case "vite":
|
|
93
|
+
return "vite";
|
|
94
|
+
case "webpack":
|
|
95
|
+
return "webpack5";
|
|
96
|
+
case "rspack":
|
|
97
|
+
return "rspack";
|
|
98
|
+
case "rollup":
|
|
99
|
+
return "rollup";
|
|
100
|
+
case "esbuild":
|
|
101
|
+
return "esbuild";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (typeof process !== "undefined" && process.env) {
|
|
105
|
+
if (process.env.VITE || process.env.VITEST) return "vite";
|
|
106
|
+
if (process.env.WEBPACK_VERSION) return "webpack5";
|
|
107
|
+
if (process.env.RSPACK) return "rspack";
|
|
108
|
+
}
|
|
109
|
+
return "standard";
|
|
110
|
+
}
|
|
111
|
+
function extractHMRDisposeHandlers(code) {
|
|
112
|
+
const lines = code.split("\n");
|
|
113
|
+
const disposeHandlers = [];
|
|
114
|
+
const cleanedLines = lines.filter((line) => {
|
|
115
|
+
const trimmed = line.trim();
|
|
116
|
+
if (!trimmed.startsWith(HMR_DISPOSE_PREFIX) || !trimmed.endsWith(HMR_DISPOSE_SUFFIX)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
disposeHandlers.push(trimmed.slice(HMR_DISPOSE_PREFIX.length, -HMR_DISPOSE_SUFFIX.length));
|
|
120
|
+
return false;
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
code: cleanedLines.join("\n"),
|
|
124
|
+
disposeHandlers
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function generateHMRCode(bundlerType, disposeHandlers = []) {
|
|
128
|
+
const imports = {
|
|
129
|
+
createHMRComponent: `import { createHMRComponent as __$createHMRComponent$__ } from "${VIRTUAL_MODULE_ID}";`,
|
|
130
|
+
hmrAccept: `import { hmrAccept as __$hmrAccept$__ } from "${VIRTUAL_MODULE_ID}";`
|
|
131
|
+
};
|
|
132
|
+
const disposeLines = disposeHandlers.map((handler) => ` import.meta.hot.dispose(${handler});`);
|
|
133
|
+
const register = bundlerType === "vite" ? [
|
|
134
|
+
"if (import.meta.hot) {",
|
|
135
|
+
...disposeLines,
|
|
136
|
+
" import.meta.hot.accept();",
|
|
137
|
+
' __$hmrAccept$__("vite", import.meta.hot, __$registry$__);',
|
|
138
|
+
"}"
|
|
139
|
+
].join("\n") : [
|
|
140
|
+
"if (import.meta.hot) {",
|
|
141
|
+
...disposeLines,
|
|
142
|
+
` __$hmrAccept$__("${bundlerType}", import.meta.hot, __$registry$__);`,
|
|
143
|
+
"}"
|
|
144
|
+
].join("\n");
|
|
145
|
+
return {
|
|
146
|
+
imports,
|
|
147
|
+
register
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
var unpluginFactory = (options = {}, meta) => {
|
|
151
|
+
const filter = vite.createFilter(options.include, options.exclude);
|
|
152
|
+
const bundlerType = detectBundler(meta);
|
|
153
|
+
let isProd = process.env.NODE_ENV === "production";
|
|
154
|
+
const finalOptions = __spreadProps(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), options), {
|
|
155
|
+
bundler: bundlerType
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
name: "unplugin-essor",
|
|
159
|
+
/**
|
|
160
|
+
* Vite-specific config to preserve JSX so the babel plugin can handle it.
|
|
161
|
+
|
|
162
|
+
*/
|
|
163
|
+
vite: {
|
|
164
|
+
config() {
|
|
165
|
+
const ctx = this;
|
|
166
|
+
const isRolldownVite = !!(ctx == null ? void 0 : ctx.meta) && "rolldownVersion" in ctx.meta;
|
|
167
|
+
const key = isRolldownVite ? "oxc" : "esbuild";
|
|
168
|
+
return {
|
|
169
|
+
[key]: { jsx: "preserve" }
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
configResolved(config) {
|
|
173
|
+
isProd = config.command === "build";
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
/**
|
|
177
|
+
* Resolve virtual HMR runtime module
|
|
178
|
+
*/
|
|
179
|
+
resolveId(id) {
|
|
180
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
181
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* Load virtual HMR runtime module
|
|
187
|
+
*/
|
|
188
|
+
load(id) {
|
|
189
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
|
|
190
|
+
return {
|
|
191
|
+
code: hmr_runtime_default,
|
|
192
|
+
map: null
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
},
|
|
197
|
+
rolldown: {
|
|
198
|
+
options(opts) {
|
|
199
|
+
var _a;
|
|
200
|
+
(_a = opts.transform) != null ? _a : opts.transform = {
|
|
201
|
+
jsx: "preserve"
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
/**
|
|
206
|
+
* Transform code with Babel plugin
|
|
207
|
+
*/
|
|
208
|
+
transform(code, id) {
|
|
209
|
+
if (SKIP_DIRECTORIES.some((p) => id.includes(p))) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (!filter(id) || !FILE_EXTENSION_REGEX.test(id)) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const babelOptions = __spreadProps(__spreadValues({}, finalOptions), { hmr: !isProd && finalOptions.hmr });
|
|
216
|
+
let result;
|
|
217
|
+
try {
|
|
218
|
+
result = babel__namespace.transformSync(code, {
|
|
219
|
+
filename: id,
|
|
220
|
+
sourceMaps: true,
|
|
221
|
+
sourceType: "module",
|
|
222
|
+
plugins: [[essorBabelPlugin__default.default, babelOptions]]
|
|
223
|
+
});
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error(`[unplugin-essor] Transform failed for ${id}:`, error);
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
if (!(result == null ? void 0 : result.code)) {
|
|
229
|
+
return code;
|
|
230
|
+
}
|
|
231
|
+
let finalCode = "";
|
|
232
|
+
if (babelOptions.hmr) {
|
|
233
|
+
const hmrResult = extractHMRDisposeHandlers(result.code);
|
|
234
|
+
const hmrCode = generateHMRCode(bundlerType, hmrResult.disposeHandlers);
|
|
235
|
+
const transformedCode = hmrResult.code;
|
|
236
|
+
if (transformedCode.includes("__$createHMRComponent$__")) {
|
|
237
|
+
finalCode = `${hmrCode.imports.createHMRComponent}
|
|
238
|
+
${finalCode}`;
|
|
239
|
+
}
|
|
240
|
+
finalCode += transformedCode;
|
|
241
|
+
if (transformedCode.includes("__$registry$__")) {
|
|
242
|
+
finalCode = `${hmrCode.imports.hmrAccept}
|
|
243
|
+
${finalCode}
|
|
244
|
+
${hmrCode.register}`;
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
finalCode += result.code;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
code: finalCode,
|
|
251
|
+
map: result.map
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
var unplugin = /* @__PURE__ */ unplugin$1.createUnplugin(unpluginFactory);
|
|
257
|
+
var index_default = unplugin;
|
|
258
|
+
|
|
259
|
+
exports.__async = __async;
|
|
260
|
+
exports.index_default = index_default;
|
|
261
|
+
exports.unplugin = unplugin;
|
|
262
|
+
exports.unpluginFactory = unpluginFactory;
|
|
263
|
+
//# sourceMappingURL=chunk-KXK55FFZ.cjs.map
|
|
264
|
+
//# sourceMappingURL=chunk-KXK55FFZ.cjs.map
|