unplugin-essor 0.0.17-beta.5 → 0.0.17-beta.7

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 CHANGED
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var chunkOH5T2AAA_cjs = require('./chunk-OH5T2AAA.cjs');
3
+ var chunkASRB37BB_cjs = require('./chunk-ASRB37BB.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) => chunkOH5T2AAA_cjs.__async(null, null, function* () {
10
+ "astro:config:setup": (astro) => chunkASRB37BB_cjs.__async(null, null, function* () {
11
11
  var _a;
12
12
  (_a = astro.config.vite).plugins || (_a.plugins = []);
13
- astro.config.vite.plugins.push(chunkOH5T2AAA_cjs.index_default.vite(options));
13
+ astro.config.vite.plugins.push(chunkASRB37BB_cjs.index_default.vite(options));
14
14
  })
15
15
  }
16
16
  });
package/dist/astro.js CHANGED
@@ -1,4 +1,4 @@
1
- import { __async, index_default } from './chunk-U2VPJOQJ.js';
1
+ import { __async, index_default } from './chunk-REX4A3LQ.js';
2
2
 
3
3
  // src/astro.ts
4
4
  var astro_default = (options) => ({
@@ -0,0 +1,297 @@
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 __objRest = (source, exclude) => {
51
+ var target = {};
52
+ for (var prop in source)
53
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
54
+ target[prop] = source[prop];
55
+ if (source != null && __getOwnPropSymbols)
56
+ for (var prop of __getOwnPropSymbols(source)) {
57
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
58
+ target[prop] = source[prop];
59
+ }
60
+ return target;
61
+ };
62
+ var __async = (__this, __arguments, generator) => {
63
+ return new Promise((resolve, reject) => {
64
+ var fulfilled = (value) => {
65
+ try {
66
+ step(generator.next(value));
67
+ } catch (e) {
68
+ reject(e);
69
+ }
70
+ };
71
+ var rejected = (value) => {
72
+ try {
73
+ step(generator.throw(value));
74
+ } catch (e) {
75
+ reject(e);
76
+ }
77
+ };
78
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
79
+ step((generator = generator.apply(__this, __arguments)).next());
80
+ });
81
+ };
82
+
83
+ // raw-loader:/home/runner/work/essor/essor/packages/unplugin/src/hmr-runtime.js?raw
84
+ 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\nfunction emitHmrEvent(detail) {\n if (typeof CustomEvent !== 'undefined' && typeof dispatchEvent !== 'undefined') {\n dispatchEvent(new CustomEvent('essor:hmr-update', { detail }));\n }\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 const updatedIds = [];\n\n for (const entry of registry) {\n if (!isHMRComponent(entry)) {\n continue;\n }\n\n const { __hmrId: hmrId, __signature: signature } = entry;\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 updatedIds.push(hmrId);\n\n for (const component of [...info.instances]) {\n try {\n component.forceUpdate();\n } catch (error) {\n console.error(`[Essor HMR] Failed to update ${hmrId}:`, error);\n cleanupInstance(hmrId, info, component);\n needsReload = true;\n }\n }\n }\n\n if (updatedIds.length > 0) {\n emitHmrEvent({ updatedIds });\n }\n\n return needsReload;\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 if (applyUpdate(registry)) invalidateOrReload(hot);\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 if (hot.data?.[ESSOR_HMR]) {\n if (applyUpdate(registry)) invalidateOrReload(hot);\n }\n\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 with a callback that receives the new module.\n if (isFunction(hot.accept)) {\n try {\n hot.accept((newModule) => {\n if (!newModule) {\n invalidateOrReload(hot);\n return;\n }\n const newRegistry = extractHMRComponents(newModule);\n if (newRegistry.length === 0) return;\n if (applyUpdate(newRegistry)) invalidateOrReload(hot);\n });\n } catch {\n // Some bundlers don't support accept with callback \u2014 fall back to simple accept.\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[ESSOR_HMR] = registry;\n });\n }\n\n // Apply update if previous data exists\n if (hot.data?.[ESSOR_HMR]) {\n if (applyUpdate(registry)) invalidateOrReload(hot);\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";
85
+
86
+ // src/index.ts
87
+ var VIRTUAL_MODULE_ID = "virtual:essor-hmr";
88
+ var RESOLVED_VIRTUAL_MODULE_ID = "\0virtual:essor-hmr";
89
+ var DEFAULT_OPTIONS = {
90
+ symbol: "$",
91
+ mode: "client",
92
+ props: true,
93
+ hmr: true,
94
+ enableFor: false,
95
+ omitClosingTags: true,
96
+ delegateEvents: true
97
+ };
98
+ var LEGACY_MODE_ALIASES = {
99
+ ssg: "server",
100
+ ssr: "hydrate"
101
+ };
102
+ function normalizeMode(mode) {
103
+ if (mode) {
104
+ return LEGACY_MODE_ALIASES[mode] || mode;
105
+ }
106
+ return "client";
107
+ }
108
+ var FILE_EXTENSION_REGEX = /\.[cm]?[jt]sx?$/i;
109
+ var SKIP_DIRECTORIES_REGEX = /[\\/](?:node_modules|dist|public)[\\/]/;
110
+ var HMR_DISPOSE_PREFIX = "import.meta.hot?.dispose(";
111
+ var HMR_DISPOSE_SUFFIX = ");";
112
+ var HMR_IMPORTS = {
113
+ createHMRComponent: `import { createHMRComponent as __$createHMRComponent$__ } from "${VIRTUAL_MODULE_ID}";`,
114
+ hmrAccept: `import { hmrAccept as __$hmrAccept$__ } from "${VIRTUAL_MODULE_ID}";`
115
+ };
116
+ function detectBundler(meta) {
117
+ if (meta == null ? void 0 : meta.framework) {
118
+ switch (meta.framework) {
119
+ case "vite":
120
+ return "vite";
121
+ case "webpack":
122
+ return "webpack5";
123
+ case "rspack":
124
+ return "rspack";
125
+ case "rollup":
126
+ return "rollup";
127
+ case "esbuild":
128
+ return "esbuild";
129
+ }
130
+ }
131
+ if (typeof process !== "undefined" && process.env) {
132
+ if (process.env.VITE || process.env.VITEST) return "vite";
133
+ if (process.env.WEBPACK_VERSION) return "webpack5";
134
+ if (process.env.RSPACK) return "rspack";
135
+ }
136
+ return "standard";
137
+ }
138
+ function extractHMRDisposeHandlers(code) {
139
+ if (!code.includes(HMR_DISPOSE_PREFIX)) {
140
+ return { code, disposeHandlers: [] };
141
+ }
142
+ const lines = code.split("\n");
143
+ const disposeHandlers = [];
144
+ const cleanedLines = lines.filter((line) => {
145
+ const trimmed = line.trim();
146
+ if (!trimmed.startsWith(HMR_DISPOSE_PREFIX) || !trimmed.endsWith(HMR_DISPOSE_SUFFIX)) {
147
+ return true;
148
+ }
149
+ disposeHandlers.push(trimmed.slice(HMR_DISPOSE_PREFIX.length, -HMR_DISPOSE_SUFFIX.length));
150
+ return false;
151
+ });
152
+ return {
153
+ code: cleanedLines.join("\n"),
154
+ disposeHandlers
155
+ };
156
+ }
157
+ function getHotExpression(bundlerType) {
158
+ if (bundlerType === "webpack5" || bundlerType === "rspack") {
159
+ return "import.meta.webpackHot";
160
+ }
161
+ return "import.meta.hot";
162
+ }
163
+ function generateHMRCode(bundlerType, disposeHandlers = []) {
164
+ const hot = getHotExpression(bundlerType);
165
+ const disposeLines = disposeHandlers.map((handler) => ` ${hot}.dispose(${handler});`);
166
+ const lines = [`if (${hot}) {`, ...disposeLines];
167
+ if (bundlerType === "vite") {
168
+ lines.push(` ${hot}.accept();`);
169
+ }
170
+ lines.push(` __$hmrAccept$__("${bundlerType}", ${hot}, __$registry$__);`, "}");
171
+ return { imports: HMR_IMPORTS, register: lines.join("\n") };
172
+ }
173
+ var unpluginFactory = (options = {}, meta) => {
174
+ var _a;
175
+ const filter = vite.createFilter(options.include, options.exclude);
176
+ const bundlerType = detectBundler(meta);
177
+ let isProd = process.env.NODE_ENV === "production";
178
+ const finalOptions = __spreadProps(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), options), {
179
+ mode: normalizeMode((_a = options.mode) != null ? _a : DEFAULT_OPTIONS.mode),
180
+ bundler: bundlerType
181
+ });
182
+ return {
183
+ name: "unplugin-essor",
184
+ /**
185
+ * Vite-specific config to preserve JSX so the babel plugin can handle it.
186
+
187
+ */
188
+ vite: {
189
+ config() {
190
+ const ctx = this;
191
+ const isRolldownVite = !!(ctx == null ? void 0 : ctx.meta) && "rolldownVersion" in ctx.meta;
192
+ const key = isRolldownVite ? "oxc" : "esbuild";
193
+ return {
194
+ [key]: { jsx: "preserve" }
195
+ };
196
+ },
197
+ configResolved(config) {
198
+ isProd = config.command === "build";
199
+ }
200
+ },
201
+ /**
202
+ * Resolve virtual HMR runtime module
203
+ */
204
+ resolveId(id) {
205
+ if (id === VIRTUAL_MODULE_ID) {
206
+ return RESOLVED_VIRTUAL_MODULE_ID;
207
+ }
208
+ return null;
209
+ },
210
+ /**
211
+ * Load virtual HMR runtime module
212
+ */
213
+ load(id) {
214
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
215
+ return {
216
+ code: hmr_runtime_default,
217
+ map: null
218
+ };
219
+ }
220
+ return null;
221
+ },
222
+ rolldown: {
223
+ options(opts) {
224
+ var _a2;
225
+ (_a2 = opts.transform) != null ? _a2 : opts.transform = {
226
+ jsx: "preserve"
227
+ };
228
+ }
229
+ },
230
+ /**
231
+ * Transform code with Babel plugin
232
+ */
233
+ transform(code, id, options2) {
234
+ var _b, _c;
235
+ if (SKIP_DIRECTORIES_REGEX.test(id) || !FILE_EXTENSION_REGEX.test(id) || !filter(id)) {
236
+ return;
237
+ }
238
+ if (!filter(id) || !FILE_EXTENSION_REGEX.test(id)) {
239
+ return;
240
+ }
241
+ const isSsr = finalOptions.mode === "server" || (options2 == null ? void 0 : options2.ssr) === true;
242
+ const _a2 = finalOptions, { symbol, include, exclude } = _a2, babelPassOptions = __objRest(_a2, ["symbol", "include", "exclude"]);
243
+ const babelOptions = __spreadProps(__spreadValues({}, babelPassOptions), {
244
+ signalPrefix: (_c = (_b = finalOptions.signalPrefix) != null ? _b : symbol) != null ? _c : "$",
245
+ mode: isSsr ? "server" : finalOptions.mode,
246
+ hmr: !isSsr && !isProd && finalOptions.hmr
247
+ });
248
+ let result;
249
+ try {
250
+ result = babel__namespace.transformSync(code, {
251
+ filename: id,
252
+ sourceMaps: true,
253
+ sourceType: "module",
254
+ plugins: [[essorBabelPlugin__default.default, babelOptions]]
255
+ });
256
+ } catch (error) {
257
+ console.error(`[unplugin-essor] Transform failed for ${id}:`, error);
258
+ return null;
259
+ }
260
+ if (!(result == null ? void 0 : result.code)) {
261
+ return code;
262
+ }
263
+ let finalCode;
264
+ if (babelOptions.hmr) {
265
+ const { code: strippedCode, disposeHandlers } = extractHMRDisposeHandlers(result.code);
266
+ const hasComponents = strippedCode.includes("__$createHMRComponent$__");
267
+ const hasRegistry = strippedCode.includes("__$registry$__");
268
+ if (!hasComponents && !hasRegistry && disposeHandlers.length === 0) {
269
+ finalCode = result.code;
270
+ } else {
271
+ const hmrCode = generateHMRCode(bundlerType, disposeHandlers);
272
+ const parts = [];
273
+ if (hasRegistry) parts.push(hmrCode.imports.hmrAccept);
274
+ if (hasComponents) parts.push(hmrCode.imports.createHMRComponent);
275
+ parts.push(strippedCode);
276
+ if (hasRegistry) parts.push(hmrCode.register);
277
+ finalCode = parts.join("\n");
278
+ }
279
+ } else {
280
+ finalCode = result.code;
281
+ }
282
+ return {
283
+ code: finalCode,
284
+ map: result.map
285
+ };
286
+ }
287
+ };
288
+ };
289
+ var unplugin = /* @__PURE__ */ unplugin$1.createUnplugin(unpluginFactory);
290
+ var index_default = unplugin;
291
+
292
+ exports.__async = __async;
293
+ exports.index_default = index_default;
294
+ exports.unplugin = unplugin;
295
+ exports.unpluginFactory = unpluginFactory;
296
+ //# sourceMappingURL=chunk-ASRB37BB.cjs.map
297
+ //# sourceMappingURL=chunk-ASRB37BB.cjs.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":["createFilter","_a","options","babel","essorBabelPlugin"],"mappings":"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","file":"chunk-ASRB37BB.cjs","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\nfunction emitHmrEvent(detail) {\n if (typeof CustomEvent !== 'undefined' && typeof dispatchEvent !== 'undefined') {\n dispatchEvent(new CustomEvent('essor:hmr-update', { detail }));\n }\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 const updatedIds = [];\n\n for (const entry of registry) {\n if (!isHMRComponent(entry)) {\n continue;\n }\n\n const { __hmrId: hmrId, __signature: signature } = entry;\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 updatedIds.push(hmrId);\n\n for (const component of [...info.instances]) {\n try {\n component.forceUpdate();\n } catch (error) {\n console.error(`[Essor HMR] Failed to update ${hmrId}:`, error);\n cleanupInstance(hmrId, info, component);\n needsReload = true;\n }\n }\n }\n\n if (updatedIds.length > 0) {\n emitHmrEvent({ updatedIds });\n }\n\n return needsReload;\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 if (applyUpdate(registry)) invalidateOrReload(hot);\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 if (hot.data?.[ESSOR_HMR]) {\n if (applyUpdate(registry)) invalidateOrReload(hot);\n }\n\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 with a callback that receives the new module.\n if (isFunction(hot.accept)) {\n try {\n hot.accept((newModule) => {\n if (!newModule) {\n invalidateOrReload(hot);\n return;\n }\n const newRegistry = extractHMRComponents(newModule);\n if (newRegistry.length === 0) return;\n if (applyUpdate(newRegistry)) invalidateOrReload(hot);\n });\n } catch {\n // Some bundlers don't support accept with callback — fall back to simple accept.\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[ESSOR_HMR] = registry;\n });\n }\n\n // Apply update if previous data exists\n if (hot.data?.[ESSOR_HMR]) {\n if (applyUpdate(registry)) invalidateOrReload(hot);\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","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 { LegacyRenderMode, Options, RenderMode } 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: '$' as const,\n mode: 'client' as RenderMode,\n props: true,\n hmr: true,\n enableFor: false,\n omitClosingTags: true,\n delegateEvents: true,\n};\n\n/**\n * Maps the deprecated `ssg` / `ssr` mode aliases onto the canonical render\n * modes understood by `babel-plugin-essor`:\n * - `ssg` → `server` (emit static HTML strings via `renderToString`)\n * - `ssr` → `hydrate` (emit hydration-ready client output)\n *\n * Retained only for backwards compatibility; the aliases will be removed in a\n * future major release (see {@link LegacyRenderMode}). Use the canonical\n * `client` | `server` | `hydrate` names instead.\n */\nconst LEGACY_MODE_ALIASES: Record<string, RenderMode> = {\n ssg: 'server',\n ssr: 'hydrate',\n};\n\n/**\n * Normalizes a user-supplied `mode` to a canonical {@link RenderMode}. Accepts\n * the canonical names verbatim and translates the deprecated `ssg` / `ssr`\n * aliases so the rest of the plugin and the Babel plugin only ever see\n * `client` | `server` | `hydrate`.\n */\nfunction normalizeMode(mode: RenderMode | LegacyRenderMode | undefined): RenderMode {\n if (mode) {\n return LEGACY_MODE_ALIASES[mode] || (mode as RenderMode);\n }\n return 'client';\n}\n\n/**\n * Performance: Pre-compiled regex and constants\n */\nconst FILE_EXTENSION_REGEX = /\\.[cm]?[jt]sx?$/i;\nconst SKIP_DIRECTORIES_REGEX = /[\\\\/](?:node_modules|dist|public)[\\\\/]/;\nconst HMR_DISPOSE_PREFIX = 'import.meta.hot?.dispose(';\nconst HMR_DISPOSE_SUFFIX = ');';\n\nconst HMR_IMPORTS = {\n createHMRComponent: `import { createHMRComponent as __$createHMRComponent$__ } from \"${VIRTUAL_MODULE_ID}\";`,\n hmrAccept: `import { hmrAccept as __$hmrAccept$__ } from \"${VIRTUAL_MODULE_ID}\";`,\n} as const;\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 // Defensive fallback: unplugin always provides meta.framework, but in edge\n // cases (custom wrappers, test harnesses) these env vars act as a safety net.\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 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 if (!code.includes(HMR_DISPOSE_PREFIX)) {\n return { code, disposeHandlers: [] };\n }\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\n/**\n * Returns the correct hot-module-replacement global expression for a bundler.\n *\n * - Vite: `import.meta.hot`\n * - webpack / rspack: `import.meta.webpackHot` (webpack-compatible HMR protocol)\n * - others: `import.meta.hot` (no real HMR; guard is always falsy — safe)\n */\nfunction getHotExpression(bundlerType: BundlerType): string {\n if (bundlerType === 'webpack5' || bundlerType === 'rspack') {\n return 'import.meta.webpackHot';\n }\n return 'import.meta.hot';\n}\n\nfunction generateHMRCode(bundlerType: BundlerType, disposeHandlers: string[] = []) {\n const hot = getHotExpression(bundlerType);\n const disposeLines = disposeHandlers.map((handler) => ` ${hot}.dispose(${handler});`);\n\n // Build the HMR registration block. Vite needs an explicit `accept()` call;\n // webpack/rspack handle acceptance inside `__$hmrAccept$__`.\n const lines = [`if (${hot}) {`, ...disposeLines];\n if (bundlerType === 'vite') {\n lines.push(` ${hot}.accept();`);\n }\n lines.push(` __$hmrAccept$__(\"${bundlerType}\", ${hot}, __$registry$__);`, '}');\n\n return { imports: HMR_IMPORTS, register: lines.join('\\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\n // transform). `mode` is normalized to a canonical RenderMode so the Babel\n // plugin only ever receives `client` | `server` | `hydrate`.\n const finalOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n mode: normalizeMode(options.mode ?? DEFAULT_OPTIONS.mode),\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, options?: { ssr?: boolean }) {\n // Skip node_modules, dist, public and non-JS/TS files\n if (SKIP_DIRECTORIES_REGEX.test(id) || !FILE_EXTENSION_REGEX.test(id) || !filter(id)) {\n return;\n }\n // Only transform JS/TS files\n if (!filter(id) || !FILE_EXTENSION_REGEX.test(id)) {\n return;\n }\n const isSsr = finalOptions.mode === 'server' || options?.ssr === true;\n\n // Extract unplugin-only options before passing to Babel\n const { symbol, include, exclude, ...babelPassOptions } = finalOptions;\n\n const babelOptions = {\n ...babelPassOptions,\n signalPrefix: finalOptions.signalPrefix ?? symbol ?? '$',\n mode: isSsr ? 'server' : finalOptions.mode,\n hmr: !isSsr && !isProd && finalOptions.hmr,\n };\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: string;\n\n if (babelOptions.hmr) {\n const { code: strippedCode, disposeHandlers } = extractHMRDisposeHandlers(result.code);\n const hasComponents = strippedCode.includes('__$createHMRComponent$__');\n const hasRegistry = strippedCode.includes('__$registry$__');\n\n if (!hasComponents && !hasRegistry && disposeHandlers.length === 0) {\n finalCode = result.code;\n } else {\n const hmrCode = generateHMRCode(bundlerType, disposeHandlers);\n const parts: string[] = [];\n if (hasRegistry) parts.push(hmrCode.imports.hmrAccept);\n if (hasComponents) parts.push(hmrCode.imports.createHMRComponent);\n parts.push(strippedCode);\n if (hasRegistry) parts.push(hmrCode.register);\n\n finalCode = parts.join('\\n');\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"]}