@akashjs/vite-plugin 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @akashjs/vite-plugin
2
+
3
+ AkashJS Vite plugin — .akash file transformation and HMR
4
+
5
+ Part of the [AkashJS](https://github.com/phpirate/akashjs) framework.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @akashjs/vite-plugin
11
+ ```
12
+
13
+ ## Documentation
14
+
15
+ - [Guide](https://akash.js.org/guide/introduction)
16
+ - [API Reference](https://akash.js.org/api/vite-plugin)
17
+ - [GitHub](https://github.com/phpirate/akashjs)
18
+
19
+ ## License
20
+
21
+ MIT
package/dist/index.cjs CHANGED
@@ -1,51 +1,4 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- akash: () => akash,
24
- default: () => akash
25
- });
26
- module.exports = __toCommonJS(index_exports);
27
- var import_compiler2 = require("@akashjs/compiler");
28
-
29
- // src/hmr.ts
30
- var import_compiler = require("@akashjs/compiler");
31
- function analyzeHmrChange(oldSource, newSource) {
32
- const oldSfc = (0, import_compiler.parse)(oldSource);
33
- const newSfc = (0, import_compiler.parse)(newSource);
34
- const scriptChanged = (oldSfc.script?.content ?? "") !== (newSfc.script?.content ?? "");
35
- const templateChanged = (oldSfc.template?.content ?? "") !== (newSfc.template?.content ?? "");
36
- const styleChanged = (oldSfc.style?.content ?? "") !== (newSfc.style?.content ?? "");
37
- const styleOnly = styleChanged && !scriptChanged && !templateChanged;
38
- const needsFullReload = scriptChanged;
39
- return {
40
- scriptChanged,
41
- templateChanged,
42
- styleChanged,
43
- styleOnly,
44
- needsFullReload
45
- };
46
- }
47
- function generateHmrCode(id) {
48
- return `
1
+ 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var compiler=require('@akashjs/compiler');function p(l,i){let o=compiler.parse(l),a=compiler.parse(i),e=(o.script?.content??"")!==(a.script?.content??""),n=(o.template?.content??"")!==(a.template?.content??""),s=(o.style?.content??"")!==(a.style?.content??"");return {scriptChanged:e,templateChanged:n,styleChanged:s,styleOnly:s&&!e&&!n,needsFullReload:e}}function u(l){return `
49
2
  // HMR
50
3
  if (import.meta.hot) {
51
4
  import.meta.hot.accept((newModule) => {
@@ -55,89 +8,19 @@ if (import.meta.hot) {
55
8
  }
56
9
  });
57
10
  }
58
- `;
59
- }
60
- function generateStyleHmrCode(styleId) {
61
- return `
11
+ `}function y(l){return `
62
12
  // Style HMR
63
13
  if (import.meta.hot) {
64
14
  import.meta.hot.accept();
65
15
  // Remove old style element and re-inject
66
- const oldStyle = document.querySelector('[data-akash-style="${styleId}"]');
16
+ const oldStyle = document.querySelector('[data-akash-style="${l}"]');
67
17
  if (oldStyle) oldStyle.remove();
68
18
  }
69
- `;
70
- }
71
-
72
- // src/index.ts
73
- function akash(options = {}) {
74
- const cssMode = options.css ?? "injected";
75
- let isProduction = false;
76
- const sourceCache = /* @__PURE__ */ new Map();
77
- return {
78
- name: "akash",
79
- enforce: "pre",
80
- configResolved(config) {
81
- isProduction = config.command === "build";
82
- },
83
- transform(code, id) {
84
- if (!id.endsWith(".akash")) return null;
85
- const result = (0, import_compiler2.compile)(code, {
86
- filename: id,
87
- dev: !isProduction
88
- });
89
- let output = result.code;
90
- if (result.css) {
91
- if (cssMode === "injected") {
92
- const cssCode = result.css.replace(/`/g, "\\`").replace(/\\/g, "\\\\");
93
- const styleId = id.replace(/[^a-zA-Z0-9]/g, "_");
94
- output += `
19
+ `}function f(l={}){let i=l.css??"injected",o=false,a=new Map;return {name:"akash",enforce:"pre",configResolved(e){o=e.command==="build";},transform(e,n){if(!n.endsWith(".akash"))return null;let s=compiler.compile(e,{filename:n,dev:!o}),t=s.code;if(s.css&&i==="injected"){let r=s.css.replace(/`/g,"\\`").replace(/\\/g,"\\\\"),c=n.replace(/[^a-zA-Z0-9]/g,"_");t+=`
95
20
  // Injected scoped styles
96
- `;
97
- output += `const __akash_style = document.createElement('style');
98
- `;
99
- output += `__akash_style.setAttribute('data-akash-style', '${styleId}');
100
- `;
101
- output += `__akash_style.textContent = \`${cssCode}\`;
102
- `;
103
- output += `document.head.appendChild(__akash_style);
104
- `;
105
- if (!isProduction) {
106
- output += generateStyleHmrCode(styleId);
107
- }
108
- }
109
- }
110
- if (!isProduction) {
111
- output += generateHmrCode(id);
112
- }
113
- sourceCache.set(id, code);
114
- return {
115
- code: output,
116
- map: null
117
- // TODO: integrate SourceMapBuilder
118
- };
119
- },
120
- handleHotUpdate({ file, server, modules, read }) {
121
- if (!file.endsWith(".akash")) return;
122
- const oldSource = sourceCache.get(file);
123
- if (oldSource) {
124
- read().then((newSource) => {
125
- const analysis = analyzeHmrChange(oldSource, newSource);
126
- if (analysis.styleOnly) {
127
- server.ws.send({
128
- type: "custom",
129
- event: "akash:style-update",
130
- data: { file }
131
- });
132
- }
133
- });
134
- }
135
- return modules;
136
- }
137
- };
138
- }
139
- // Annotate the CommonJS export names for ESM import in node:
140
- 0 && (module.exports = {
141
- akash
142
- });
21
+ `,t+=`const __akash_style = document.createElement('style');
22
+ `,t+=`__akash_style.setAttribute('data-akash-style', '${c}');
23
+ `,t+=`__akash_style.textContent = \`${r}\`;
24
+ `,t+=`document.head.appendChild(__akash_style);
25
+ `,o||(t+=y(c));}return o||(t+=u()),a.set(n,e),{code:t,map:null}},handleHotUpdate({file:e,server:n,modules:s,read:t}){if(!e.endsWith(".akash"))return;let r=a.get(e);return r&&t().then(c=>{p(r,c).styleOnly&&n.ws.send({type:"custom",event:"akash:style-update",data:{file:e}});}),s}}}exports.akash=f;exports.default=f;//# sourceMappingURL=index.cjs.map
143
26
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/hmr.ts"],"sourcesContent":["/**\n * AkashJS Vite plugin.\n *\n * Transforms .akash single-file components during development\n * and production builds. Handles HMR for style-only and\n * template-only changes.\n */\n\nimport { compile } from '@akashjs/compiler';\nimport type { Plugin } from 'vite';\nimport { analyzeHmrChange, generateHmrCode, generateStyleHmrCode } from './hmr.js';\n\nexport interface AkashPluginOptions {\n /** Include file patterns (default: .akash files) */\n include?: string[];\n /** CSS injection mode: 'external' extracts CSS, 'injected' inlines it */\n css?: 'external' | 'injected';\n}\n\nexport default function akash(options: AkashPluginOptions = {}): Plugin {\n const cssMode = options.css ?? 'injected';\n let isProduction = false;\n\n // Cache previous source for HMR diffing\n const sourceCache = new Map<string, string>();\n\n return {\n name: 'akash',\n enforce: 'pre',\n\n configResolved(config) {\n isProduction = config.command === 'build';\n },\n\n transform(code, id) {\n if (!id.endsWith('.akash')) return null;\n\n const result = compile(code, {\n filename: id,\n dev: !isProduction,\n });\n\n let output = result.code;\n\n // Inject CSS\n if (result.css) {\n if (cssMode === 'injected') {\n const cssCode = result.css.replace(/`/g, '\\\\`').replace(/\\\\/g, '\\\\\\\\');\n const styleId = id.replace(/[^a-zA-Z0-9]/g, '_');\n output += `\\n// Injected scoped styles\\n`;\n output += `const __akash_style = document.createElement('style');\\n`;\n output += `__akash_style.setAttribute('data-akash-style', '${styleId}');\\n`;\n output += `__akash_style.textContent = \\`${cssCode}\\`;\\n`;\n output += `document.head.appendChild(__akash_style);\\n`;\n\n // Add style HMR in dev mode\n if (!isProduction) {\n output += generateStyleHmrCode(styleId);\n }\n }\n }\n\n // Add HMR support in dev mode\n if (!isProduction) {\n output += generateHmrCode(id);\n }\n\n // Cache source for HMR diffing\n sourceCache.set(id, code);\n\n return {\n code: output,\n map: null, // TODO: integrate SourceMapBuilder\n };\n },\n\n handleHotUpdate({ file, server, modules, read }) {\n if (!file.endsWith('.akash')) return;\n\n const oldSource = sourceCache.get(file);\n\n if (oldSource) {\n // Read new source to analyze what changed\n read().then((newSource) => {\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only change — Vite will handle the CSS update\n // via the style HMR code we injected\n server.ws.send({\n type: 'custom',\n event: 'akash:style-update',\n data: { file },\n });\n }\n });\n }\n\n // Always return modules to invalidate — the HMR code in the\n // client handles the actual update strategy\n return modules;\n },\n };\n}\n\nexport { akash };\n","/**\n * HMR handling for .akash files.\n *\n * Determines the type of change (script, template, style) and\n * sends targeted HMR updates. Style-only changes can hot-swap\n * without a full component reload.\n */\n\nimport { parse } from '@akashjs/compiler';\nimport type { HmrContext, ModuleNode } from 'vite';\n\nexport interface HmrAnalysis {\n /** Whether the script block changed */\n scriptChanged: boolean;\n /** Whether the template block changed */\n templateChanged: boolean;\n /** Whether the style block changed */\n styleChanged: boolean;\n /** Whether this is a style-only change (can hot-swap) */\n styleOnly: boolean;\n /** Whether a full reload is needed */\n needsFullReload: boolean;\n}\n\n/**\n * Compare old and new source to determine what changed.\n */\nexport function analyzeHmrChange(oldSource: string, newSource: string): HmrAnalysis {\n const oldSfc = parse(oldSource);\n const newSfc = parse(newSource);\n\n const scriptChanged = (oldSfc.script?.content ?? '') !== (newSfc.script?.content ?? '');\n const templateChanged = (oldSfc.template?.content ?? '') !== (newSfc.template?.content ?? '');\n const styleChanged = (oldSfc.style?.content ?? '') !== (newSfc.style?.content ?? '');\n\n const styleOnly = styleChanged && !scriptChanged && !templateChanged;\n const needsFullReload = scriptChanged;\n\n return {\n scriptChanged,\n templateChanged,\n styleChanged,\n styleOnly,\n needsFullReload,\n };\n}\n\n/**\n * Generate the HMR client code that gets injected into the module.\n * This code is appended to the compiled output in dev mode.\n */\nexport function generateHmrCode(id: string): string {\n return `\n// HMR\nif (import.meta.hot) {\n import.meta.hot.accept((newModule) => {\n if (newModule) {\n // Full module replacement — the new default export\n // replaces the component in the parent's render tree\n }\n });\n}\n`;\n}\n\n/**\n * Generate style-only HMR code.\n * When only styles change, we can hot-swap the <style> element\n * without re-rendering the component.\n */\nexport function generateStyleHmrCode(styleId: string): string {\n return `\n// Style HMR\nif (import.meta.hot) {\n import.meta.hot.accept();\n // Remove old style element and re-inject\n const oldStyle = document.querySelector('[data-akash-style=\"${styleId}\"]');\n if (oldStyle) oldStyle.remove();\n}\n`;\n}\n\n/**\n * Handle hot update for .akash files.\n * Returns the affected modules that need updating.\n */\nexport function handleAkashHotUpdate(\n file: string,\n modules: ModuleNode[],\n oldSource: string | undefined,\n newSource: string,\n): { modules: ModuleNode[]; type: 'full' | 'style-only' } {\n if (!oldSource) {\n return { modules, type: 'full' };\n }\n\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only update — can be applied without full reload\n return { modules, type: 'style-only' };\n }\n\n // Script or template changed — need full module invalidation\n return { modules, type: 'full' };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,IAAAA,mBAAwB;;;ACAxB,sBAAsB;AAmBf,SAAS,iBAAiB,WAAmB,WAAgC;AAClF,QAAM,aAAS,uBAAM,SAAS;AAC9B,QAAM,aAAS,uBAAM,SAAS;AAE9B,QAAM,iBAAiB,OAAO,QAAQ,WAAW,SAAS,OAAO,QAAQ,WAAW;AACpF,QAAM,mBAAmB,OAAO,UAAU,WAAW,SAAS,OAAO,UAAU,WAAW;AAC1F,QAAM,gBAAgB,OAAO,OAAO,WAAW,SAAS,OAAO,OAAO,WAAW;AAEjF,QAAM,YAAY,gBAAgB,CAAC,iBAAiB,CAAC;AACrD,QAAM,kBAAkB;AAExB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAMO,SAAS,gBAAgB,IAAoB;AAClD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWT;AAOO,SAAS,qBAAqB,SAAyB;AAC5D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,gEAKuD,OAAO;AAAA;AAAA;AAAA;AAIvE;;;AD7De,SAAR,MAAuB,UAA8B,CAAC,GAAW;AACtE,QAAM,UAAU,QAAQ,OAAO;AAC/B,MAAI,eAAe;AAGnB,QAAM,cAAc,oBAAI,IAAoB;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,eAAe,QAAQ;AACrB,qBAAe,OAAO,YAAY;AAAA,IACpC;AAAA,IAEA,UAAU,MAAM,IAAI;AAClB,UAAI,CAAC,GAAG,SAAS,QAAQ,EAAG,QAAO;AAEnC,YAAM,aAAS,0BAAQ,MAAM;AAAA,QAC3B,UAAU;AAAA,QACV,KAAK,CAAC;AAAA,MACR,CAAC;AAED,UAAI,SAAS,OAAO;AAGpB,UAAI,OAAO,KAAK;AACd,YAAI,YAAY,YAAY;AAC1B,gBAAM,UAAU,OAAO,IAAI,QAAQ,MAAM,KAAK,EAAE,QAAQ,OAAO,MAAM;AACrE,gBAAM,UAAU,GAAG,QAAQ,iBAAiB,GAAG;AAC/C,oBAAU;AAAA;AAAA;AACV,oBAAU;AAAA;AACV,oBAAU,mDAAmD,OAAO;AAAA;AACpE,oBAAU,iCAAiC,OAAO;AAAA;AAClD,oBAAU;AAAA;AAGV,cAAI,CAAC,cAAc;AACjB,sBAAU,qBAAqB,OAAO;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAGA,UAAI,CAAC,cAAc;AACjB,kBAAU,gBAAgB,EAAE;AAAA,MAC9B;AAGA,kBAAY,IAAI,IAAI,IAAI;AAExB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,KAAK;AAAA;AAAA,MACP;AAAA,IACF;AAAA,IAEA,gBAAgB,EAAE,MAAM,QAAQ,SAAS,KAAK,GAAG;AAC/C,UAAI,CAAC,KAAK,SAAS,QAAQ,EAAG;AAE9B,YAAM,YAAY,YAAY,IAAI,IAAI;AAEtC,UAAI,WAAW;AAEb,aAAK,EAAE,KAAK,CAAC,cAAc;AACzB,gBAAM,WAAW,iBAAiB,WAAW,SAAS;AAEtD,cAAI,SAAS,WAAW;AAGtB,mBAAO,GAAG,KAAK;AAAA,cACb,MAAM;AAAA,cACN,OAAO;AAAA,cACP,MAAM,EAAE,KAAK;AAAA,YACf,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAIA,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":["import_compiler"]}
1
+ {"version":3,"sources":["../src/hmr.ts","../src/index.ts"],"names":["analyzeHmrChange","oldSource","newSource","oldSfc","parse","newSfc","scriptChanged","templateChanged","styleChanged","generateHmrCode","id","generateStyleHmrCode","styleId","akash","options","cssMode","isProduction","sourceCache","config","code","result","compile","output","cssCode","file","server","modules","read"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * HMR handling for .akash files.\n *\n * Determines the type of change (script, template, style) and\n * sends targeted HMR updates. Style-only changes can hot-swap\n * without a full component reload.\n */\n\nimport { parse } from '@akashjs/compiler';\nimport type { HmrContext, ModuleNode } from 'vite';\n\nexport interface HmrAnalysis {\n /** Whether the script block changed */\n scriptChanged: boolean;\n /** Whether the template block changed */\n templateChanged: boolean;\n /** Whether the style block changed */\n styleChanged: boolean;\n /** Whether this is a style-only change (can hot-swap) */\n styleOnly: boolean;\n /** Whether a full reload is needed */\n needsFullReload: boolean;\n}\n\n/**\n * Compare old and new source to determine what changed.\n */\nexport function analyzeHmrChange(oldSource: string, newSource: string): HmrAnalysis {\n const oldSfc = parse(oldSource);\n const newSfc = parse(newSource);\n\n const scriptChanged = (oldSfc.script?.content ?? '') !== (newSfc.script?.content ?? '');\n const templateChanged = (oldSfc.template?.content ?? '') !== (newSfc.template?.content ?? '');\n const styleChanged = (oldSfc.style?.content ?? '') !== (newSfc.style?.content ?? '');\n\n const styleOnly = styleChanged && !scriptChanged && !templateChanged;\n const needsFullReload = scriptChanged;\n\n return {\n scriptChanged,\n templateChanged,\n styleChanged,\n styleOnly,\n needsFullReload,\n };\n}\n\n/**\n * Generate the HMR client code that gets injected into the module.\n * This code is appended to the compiled output in dev mode.\n */\nexport function generateHmrCode(id: string): string {\n return `\n// HMR\nif (import.meta.hot) {\n import.meta.hot.accept((newModule) => {\n if (newModule) {\n // Full module replacement — the new default export\n // replaces the component in the parent's render tree\n }\n });\n}\n`;\n}\n\n/**\n * Generate style-only HMR code.\n * When only styles change, we can hot-swap the <style> element\n * without re-rendering the component.\n */\nexport function generateStyleHmrCode(styleId: string): string {\n return `\n// Style HMR\nif (import.meta.hot) {\n import.meta.hot.accept();\n // Remove old style element and re-inject\n const oldStyle = document.querySelector('[data-akash-style=\"${styleId}\"]');\n if (oldStyle) oldStyle.remove();\n}\n`;\n}\n\n/**\n * Handle hot update for .akash files.\n * Returns the affected modules that need updating.\n */\nexport function handleAkashHotUpdate(\n file: string,\n modules: ModuleNode[],\n oldSource: string | undefined,\n newSource: string,\n): { modules: ModuleNode[]; type: 'full' | 'style-only' } {\n if (!oldSource) {\n return { modules, type: 'full' };\n }\n\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only update — can be applied without full reload\n return { modules, type: 'style-only' };\n }\n\n // Script or template changed — need full module invalidation\n return { modules, type: 'full' };\n}\n","/**\n * AkashJS Vite plugin.\n *\n * Transforms .akash single-file components during development\n * and production builds. Handles HMR for style-only and\n * template-only changes.\n */\n\nimport { compile } from '@akashjs/compiler';\nimport type { Plugin } from 'vite';\nimport { analyzeHmrChange, generateHmrCode, generateStyleHmrCode } from './hmr.js';\n\nexport interface AkashPluginOptions {\n /** Include file patterns (default: .akash files) */\n include?: string[];\n /** CSS injection mode: 'external' extracts CSS, 'injected' inlines it */\n css?: 'external' | 'injected';\n}\n\nexport default function akash(options: AkashPluginOptions = {}): Plugin {\n const cssMode = options.css ?? 'injected';\n let isProduction = false;\n\n // Cache previous source for HMR diffing\n const sourceCache = new Map<string, string>();\n\n return {\n name: 'akash',\n enforce: 'pre',\n\n configResolved(config) {\n isProduction = config.command === 'build';\n },\n\n transform(code, id) {\n if (!id.endsWith('.akash')) return null;\n\n const result = compile(code, {\n filename: id,\n dev: !isProduction,\n });\n\n let output = result.code;\n\n // Inject CSS\n if (result.css) {\n if (cssMode === 'injected') {\n const cssCode = result.css.replace(/`/g, '\\\\`').replace(/\\\\/g, '\\\\\\\\');\n const styleId = id.replace(/[^a-zA-Z0-9]/g, '_');\n output += `\\n// Injected scoped styles\\n`;\n output += `const __akash_style = document.createElement('style');\\n`;\n output += `__akash_style.setAttribute('data-akash-style', '${styleId}');\\n`;\n output += `__akash_style.textContent = \\`${cssCode}\\`;\\n`;\n output += `document.head.appendChild(__akash_style);\\n`;\n\n // Add style HMR in dev mode\n if (!isProduction) {\n output += generateStyleHmrCode(styleId);\n }\n }\n }\n\n // Add HMR support in dev mode\n if (!isProduction) {\n output += generateHmrCode(id);\n }\n\n // Cache source for HMR diffing\n sourceCache.set(id, code);\n\n return {\n code: output,\n map: null, // TODO: integrate SourceMapBuilder\n };\n },\n\n handleHotUpdate({ file, server, modules, read }) {\n if (!file.endsWith('.akash')) return;\n\n const oldSource = sourceCache.get(file);\n\n if (oldSource) {\n // Read new source to analyze what changed\n read().then((newSource) => {\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only change — Vite will handle the CSS update\n // via the style HMR code we injected\n server.ws.send({\n type: 'custom',\n event: 'akash:style-update',\n data: { file },\n });\n }\n });\n }\n\n // Always return modules to invalidate — the HMR code in the\n // client handles the actual update strategy\n return modules;\n },\n };\n}\n\nexport { akash };\n"]}
package/dist/index.js CHANGED
@@ -1,26 +1,4 @@
1
- // src/index.ts
2
- import { compile } from "@akashjs/compiler";
3
-
4
- // src/hmr.ts
5
- import { parse } from "@akashjs/compiler";
6
- function analyzeHmrChange(oldSource, newSource) {
7
- const oldSfc = parse(oldSource);
8
- const newSfc = parse(newSource);
9
- const scriptChanged = (oldSfc.script?.content ?? "") !== (newSfc.script?.content ?? "");
10
- const templateChanged = (oldSfc.template?.content ?? "") !== (newSfc.template?.content ?? "");
11
- const styleChanged = (oldSfc.style?.content ?? "") !== (newSfc.style?.content ?? "");
12
- const styleOnly = styleChanged && !scriptChanged && !templateChanged;
13
- const needsFullReload = scriptChanged;
14
- return {
15
- scriptChanged,
16
- templateChanged,
17
- styleChanged,
18
- styleOnly,
19
- needsFullReload
20
- };
21
- }
22
- function generateHmrCode(id) {
23
- return `
1
+ import {compile,parse}from'@akashjs/compiler';function p(l,i){let o=parse(l),a=parse(i),e=(o.script?.content??"")!==(a.script?.content??""),n=(o.template?.content??"")!==(a.template?.content??""),s=(o.style?.content??"")!==(a.style?.content??"");return {scriptChanged:e,templateChanged:n,styleChanged:s,styleOnly:s&&!e&&!n,needsFullReload:e}}function u(l){return `
24
2
  // HMR
25
3
  if (import.meta.hot) {
26
4
  import.meta.hot.accept((newModule) => {
@@ -30,89 +8,19 @@ if (import.meta.hot) {
30
8
  }
31
9
  });
32
10
  }
33
- `;
34
- }
35
- function generateStyleHmrCode(styleId) {
36
- return `
11
+ `}function y(l){return `
37
12
  // Style HMR
38
13
  if (import.meta.hot) {
39
14
  import.meta.hot.accept();
40
15
  // Remove old style element and re-inject
41
- const oldStyle = document.querySelector('[data-akash-style="${styleId}"]');
16
+ const oldStyle = document.querySelector('[data-akash-style="${l}"]');
42
17
  if (oldStyle) oldStyle.remove();
43
18
  }
44
- `;
45
- }
46
-
47
- // src/index.ts
48
- function akash(options = {}) {
49
- const cssMode = options.css ?? "injected";
50
- let isProduction = false;
51
- const sourceCache = /* @__PURE__ */ new Map();
52
- return {
53
- name: "akash",
54
- enforce: "pre",
55
- configResolved(config) {
56
- isProduction = config.command === "build";
57
- },
58
- transform(code, id) {
59
- if (!id.endsWith(".akash")) return null;
60
- const result = compile(code, {
61
- filename: id,
62
- dev: !isProduction
63
- });
64
- let output = result.code;
65
- if (result.css) {
66
- if (cssMode === "injected") {
67
- const cssCode = result.css.replace(/`/g, "\\`").replace(/\\/g, "\\\\");
68
- const styleId = id.replace(/[^a-zA-Z0-9]/g, "_");
69
- output += `
19
+ `}function f(l={}){let i=l.css??"injected",o=false,a=new Map;return {name:"akash",enforce:"pre",configResolved(e){o=e.command==="build";},transform(e,n){if(!n.endsWith(".akash"))return null;let s=compile(e,{filename:n,dev:!o}),t=s.code;if(s.css&&i==="injected"){let r=s.css.replace(/`/g,"\\`").replace(/\\/g,"\\\\"),c=n.replace(/[^a-zA-Z0-9]/g,"_");t+=`
70
20
  // Injected scoped styles
71
- `;
72
- output += `const __akash_style = document.createElement('style');
73
- `;
74
- output += `__akash_style.setAttribute('data-akash-style', '${styleId}');
75
- `;
76
- output += `__akash_style.textContent = \`${cssCode}\`;
77
- `;
78
- output += `document.head.appendChild(__akash_style);
79
- `;
80
- if (!isProduction) {
81
- output += generateStyleHmrCode(styleId);
82
- }
83
- }
84
- }
85
- if (!isProduction) {
86
- output += generateHmrCode(id);
87
- }
88
- sourceCache.set(id, code);
89
- return {
90
- code: output,
91
- map: null
92
- // TODO: integrate SourceMapBuilder
93
- };
94
- },
95
- handleHotUpdate({ file, server, modules, read }) {
96
- if (!file.endsWith(".akash")) return;
97
- const oldSource = sourceCache.get(file);
98
- if (oldSource) {
99
- read().then((newSource) => {
100
- const analysis = analyzeHmrChange(oldSource, newSource);
101
- if (analysis.styleOnly) {
102
- server.ws.send({
103
- type: "custom",
104
- event: "akash:style-update",
105
- data: { file }
106
- });
107
- }
108
- });
109
- }
110
- return modules;
111
- }
112
- };
113
- }
114
- export {
115
- akash,
116
- akash as default
117
- };
21
+ `,t+=`const __akash_style = document.createElement('style');
22
+ `,t+=`__akash_style.setAttribute('data-akash-style', '${c}');
23
+ `,t+=`__akash_style.textContent = \`${r}\`;
24
+ `,t+=`document.head.appendChild(__akash_style);
25
+ `,o||(t+=y(c));}return o||(t+=u()),a.set(n,e),{code:t,map:null}},handleHotUpdate({file:e,server:n,modules:s,read:t}){if(!e.endsWith(".akash"))return;let r=a.get(e);return r&&t().then(c=>{p(r,c).styleOnly&&n.ws.send({type:"custom",event:"akash:style-update",data:{file:e}});}),s}}}export{f as akash,f as default};//# sourceMappingURL=index.js.map
118
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/hmr.ts"],"sourcesContent":["/**\n * AkashJS Vite plugin.\n *\n * Transforms .akash single-file components during development\n * and production builds. Handles HMR for style-only and\n * template-only changes.\n */\n\nimport { compile } from '@akashjs/compiler';\nimport type { Plugin } from 'vite';\nimport { analyzeHmrChange, generateHmrCode, generateStyleHmrCode } from './hmr.js';\n\nexport interface AkashPluginOptions {\n /** Include file patterns (default: .akash files) */\n include?: string[];\n /** CSS injection mode: 'external' extracts CSS, 'injected' inlines it */\n css?: 'external' | 'injected';\n}\n\nexport default function akash(options: AkashPluginOptions = {}): Plugin {\n const cssMode = options.css ?? 'injected';\n let isProduction = false;\n\n // Cache previous source for HMR diffing\n const sourceCache = new Map<string, string>();\n\n return {\n name: 'akash',\n enforce: 'pre',\n\n configResolved(config) {\n isProduction = config.command === 'build';\n },\n\n transform(code, id) {\n if (!id.endsWith('.akash')) return null;\n\n const result = compile(code, {\n filename: id,\n dev: !isProduction,\n });\n\n let output = result.code;\n\n // Inject CSS\n if (result.css) {\n if (cssMode === 'injected') {\n const cssCode = result.css.replace(/`/g, '\\\\`').replace(/\\\\/g, '\\\\\\\\');\n const styleId = id.replace(/[^a-zA-Z0-9]/g, '_');\n output += `\\n// Injected scoped styles\\n`;\n output += `const __akash_style = document.createElement('style');\\n`;\n output += `__akash_style.setAttribute('data-akash-style', '${styleId}');\\n`;\n output += `__akash_style.textContent = \\`${cssCode}\\`;\\n`;\n output += `document.head.appendChild(__akash_style);\\n`;\n\n // Add style HMR in dev mode\n if (!isProduction) {\n output += generateStyleHmrCode(styleId);\n }\n }\n }\n\n // Add HMR support in dev mode\n if (!isProduction) {\n output += generateHmrCode(id);\n }\n\n // Cache source for HMR diffing\n sourceCache.set(id, code);\n\n return {\n code: output,\n map: null, // TODO: integrate SourceMapBuilder\n };\n },\n\n handleHotUpdate({ file, server, modules, read }) {\n if (!file.endsWith('.akash')) return;\n\n const oldSource = sourceCache.get(file);\n\n if (oldSource) {\n // Read new source to analyze what changed\n read().then((newSource) => {\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only change — Vite will handle the CSS update\n // via the style HMR code we injected\n server.ws.send({\n type: 'custom',\n event: 'akash:style-update',\n data: { file },\n });\n }\n });\n }\n\n // Always return modules to invalidate — the HMR code in the\n // client handles the actual update strategy\n return modules;\n },\n };\n}\n\nexport { akash };\n","/**\n * HMR handling for .akash files.\n *\n * Determines the type of change (script, template, style) and\n * sends targeted HMR updates. Style-only changes can hot-swap\n * without a full component reload.\n */\n\nimport { parse } from '@akashjs/compiler';\nimport type { HmrContext, ModuleNode } from 'vite';\n\nexport interface HmrAnalysis {\n /** Whether the script block changed */\n scriptChanged: boolean;\n /** Whether the template block changed */\n templateChanged: boolean;\n /** Whether the style block changed */\n styleChanged: boolean;\n /** Whether this is a style-only change (can hot-swap) */\n styleOnly: boolean;\n /** Whether a full reload is needed */\n needsFullReload: boolean;\n}\n\n/**\n * Compare old and new source to determine what changed.\n */\nexport function analyzeHmrChange(oldSource: string, newSource: string): HmrAnalysis {\n const oldSfc = parse(oldSource);\n const newSfc = parse(newSource);\n\n const scriptChanged = (oldSfc.script?.content ?? '') !== (newSfc.script?.content ?? '');\n const templateChanged = (oldSfc.template?.content ?? '') !== (newSfc.template?.content ?? '');\n const styleChanged = (oldSfc.style?.content ?? '') !== (newSfc.style?.content ?? '');\n\n const styleOnly = styleChanged && !scriptChanged && !templateChanged;\n const needsFullReload = scriptChanged;\n\n return {\n scriptChanged,\n templateChanged,\n styleChanged,\n styleOnly,\n needsFullReload,\n };\n}\n\n/**\n * Generate the HMR client code that gets injected into the module.\n * This code is appended to the compiled output in dev mode.\n */\nexport function generateHmrCode(id: string): string {\n return `\n// HMR\nif (import.meta.hot) {\n import.meta.hot.accept((newModule) => {\n if (newModule) {\n // Full module replacement — the new default export\n // replaces the component in the parent's render tree\n }\n });\n}\n`;\n}\n\n/**\n * Generate style-only HMR code.\n * When only styles change, we can hot-swap the <style> element\n * without re-rendering the component.\n */\nexport function generateStyleHmrCode(styleId: string): string {\n return `\n// Style HMR\nif (import.meta.hot) {\n import.meta.hot.accept();\n // Remove old style element and re-inject\n const oldStyle = document.querySelector('[data-akash-style=\"${styleId}\"]');\n if (oldStyle) oldStyle.remove();\n}\n`;\n}\n\n/**\n * Handle hot update for .akash files.\n * Returns the affected modules that need updating.\n */\nexport function handleAkashHotUpdate(\n file: string,\n modules: ModuleNode[],\n oldSource: string | undefined,\n newSource: string,\n): { modules: ModuleNode[]; type: 'full' | 'style-only' } {\n if (!oldSource) {\n return { modules, type: 'full' };\n }\n\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only update — can be applied without full reload\n return { modules, type: 'style-only' };\n }\n\n // Script or template changed — need full module invalidation\n return { modules, type: 'full' };\n}\n"],"mappings":";AAQA,SAAS,eAAe;;;ACAxB,SAAS,aAAa;AAmBf,SAAS,iBAAiB,WAAmB,WAAgC;AAClF,QAAM,SAAS,MAAM,SAAS;AAC9B,QAAM,SAAS,MAAM,SAAS;AAE9B,QAAM,iBAAiB,OAAO,QAAQ,WAAW,SAAS,OAAO,QAAQ,WAAW;AACpF,QAAM,mBAAmB,OAAO,UAAU,WAAW,SAAS,OAAO,UAAU,WAAW;AAC1F,QAAM,gBAAgB,OAAO,OAAO,WAAW,SAAS,OAAO,OAAO,WAAW;AAEjF,QAAM,YAAY,gBAAgB,CAAC,iBAAiB,CAAC;AACrD,QAAM,kBAAkB;AAExB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAMO,SAAS,gBAAgB,IAAoB;AAClD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWT;AAOO,SAAS,qBAAqB,SAAyB;AAC5D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,gEAKuD,OAAO;AAAA;AAAA;AAAA;AAIvE;;;AD7De,SAAR,MAAuB,UAA8B,CAAC,GAAW;AACtE,QAAM,UAAU,QAAQ,OAAO;AAC/B,MAAI,eAAe;AAGnB,QAAM,cAAc,oBAAI,IAAoB;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,eAAe,QAAQ;AACrB,qBAAe,OAAO,YAAY;AAAA,IACpC;AAAA,IAEA,UAAU,MAAM,IAAI;AAClB,UAAI,CAAC,GAAG,SAAS,QAAQ,EAAG,QAAO;AAEnC,YAAM,SAAS,QAAQ,MAAM;AAAA,QAC3B,UAAU;AAAA,QACV,KAAK,CAAC;AAAA,MACR,CAAC;AAED,UAAI,SAAS,OAAO;AAGpB,UAAI,OAAO,KAAK;AACd,YAAI,YAAY,YAAY;AAC1B,gBAAM,UAAU,OAAO,IAAI,QAAQ,MAAM,KAAK,EAAE,QAAQ,OAAO,MAAM;AACrE,gBAAM,UAAU,GAAG,QAAQ,iBAAiB,GAAG;AAC/C,oBAAU;AAAA;AAAA;AACV,oBAAU;AAAA;AACV,oBAAU,mDAAmD,OAAO;AAAA;AACpE,oBAAU,iCAAiC,OAAO;AAAA;AAClD,oBAAU;AAAA;AAGV,cAAI,CAAC,cAAc;AACjB,sBAAU,qBAAqB,OAAO;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAGA,UAAI,CAAC,cAAc;AACjB,kBAAU,gBAAgB,EAAE;AAAA,MAC9B;AAGA,kBAAY,IAAI,IAAI,IAAI;AAExB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,KAAK;AAAA;AAAA,MACP;AAAA,IACF;AAAA,IAEA,gBAAgB,EAAE,MAAM,QAAQ,SAAS,KAAK,GAAG;AAC/C,UAAI,CAAC,KAAK,SAAS,QAAQ,EAAG;AAE9B,YAAM,YAAY,YAAY,IAAI,IAAI;AAEtC,UAAI,WAAW;AAEb,aAAK,EAAE,KAAK,CAAC,cAAc;AACzB,gBAAM,WAAW,iBAAiB,WAAW,SAAS;AAEtD,cAAI,SAAS,WAAW;AAGtB,mBAAO,GAAG,KAAK;AAAA,cACb,MAAM;AAAA,cACN,OAAO;AAAA,cACP,MAAM,EAAE,KAAK;AAAA,YACf,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAIA,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/hmr.ts","../src/index.ts"],"names":["analyzeHmrChange","oldSource","newSource","oldSfc","parse","newSfc","scriptChanged","templateChanged","styleChanged","generateHmrCode","id","generateStyleHmrCode","styleId","akash","options","cssMode","isProduction","sourceCache","config","code","result","compile","output","cssCode","file","server","modules","read"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * HMR handling for .akash files.\n *\n * Determines the type of change (script, template, style) and\n * sends targeted HMR updates. Style-only changes can hot-swap\n * without a full component reload.\n */\n\nimport { parse } from '@akashjs/compiler';\nimport type { HmrContext, ModuleNode } from 'vite';\n\nexport interface HmrAnalysis {\n /** Whether the script block changed */\n scriptChanged: boolean;\n /** Whether the template block changed */\n templateChanged: boolean;\n /** Whether the style block changed */\n styleChanged: boolean;\n /** Whether this is a style-only change (can hot-swap) */\n styleOnly: boolean;\n /** Whether a full reload is needed */\n needsFullReload: boolean;\n}\n\n/**\n * Compare old and new source to determine what changed.\n */\nexport function analyzeHmrChange(oldSource: string, newSource: string): HmrAnalysis {\n const oldSfc = parse(oldSource);\n const newSfc = parse(newSource);\n\n const scriptChanged = (oldSfc.script?.content ?? '') !== (newSfc.script?.content ?? '');\n const templateChanged = (oldSfc.template?.content ?? '') !== (newSfc.template?.content ?? '');\n const styleChanged = (oldSfc.style?.content ?? '') !== (newSfc.style?.content ?? '');\n\n const styleOnly = styleChanged && !scriptChanged && !templateChanged;\n const needsFullReload = scriptChanged;\n\n return {\n scriptChanged,\n templateChanged,\n styleChanged,\n styleOnly,\n needsFullReload,\n };\n}\n\n/**\n * Generate the HMR client code that gets injected into the module.\n * This code is appended to the compiled output in dev mode.\n */\nexport function generateHmrCode(id: string): string {\n return `\n// HMR\nif (import.meta.hot) {\n import.meta.hot.accept((newModule) => {\n if (newModule) {\n // Full module replacement — the new default export\n // replaces the component in the parent's render tree\n }\n });\n}\n`;\n}\n\n/**\n * Generate style-only HMR code.\n * When only styles change, we can hot-swap the <style> element\n * without re-rendering the component.\n */\nexport function generateStyleHmrCode(styleId: string): string {\n return `\n// Style HMR\nif (import.meta.hot) {\n import.meta.hot.accept();\n // Remove old style element and re-inject\n const oldStyle = document.querySelector('[data-akash-style=\"${styleId}\"]');\n if (oldStyle) oldStyle.remove();\n}\n`;\n}\n\n/**\n * Handle hot update for .akash files.\n * Returns the affected modules that need updating.\n */\nexport function handleAkashHotUpdate(\n file: string,\n modules: ModuleNode[],\n oldSource: string | undefined,\n newSource: string,\n): { modules: ModuleNode[]; type: 'full' | 'style-only' } {\n if (!oldSource) {\n return { modules, type: 'full' };\n }\n\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only update — can be applied without full reload\n return { modules, type: 'style-only' };\n }\n\n // Script or template changed — need full module invalidation\n return { modules, type: 'full' };\n}\n","/**\n * AkashJS Vite plugin.\n *\n * Transforms .akash single-file components during development\n * and production builds. Handles HMR for style-only and\n * template-only changes.\n */\n\nimport { compile } from '@akashjs/compiler';\nimport type { Plugin } from 'vite';\nimport { analyzeHmrChange, generateHmrCode, generateStyleHmrCode } from './hmr.js';\n\nexport interface AkashPluginOptions {\n /** Include file patterns (default: .akash files) */\n include?: string[];\n /** CSS injection mode: 'external' extracts CSS, 'injected' inlines it */\n css?: 'external' | 'injected';\n}\n\nexport default function akash(options: AkashPluginOptions = {}): Plugin {\n const cssMode = options.css ?? 'injected';\n let isProduction = false;\n\n // Cache previous source for HMR diffing\n const sourceCache = new Map<string, string>();\n\n return {\n name: 'akash',\n enforce: 'pre',\n\n configResolved(config) {\n isProduction = config.command === 'build';\n },\n\n transform(code, id) {\n if (!id.endsWith('.akash')) return null;\n\n const result = compile(code, {\n filename: id,\n dev: !isProduction,\n });\n\n let output = result.code;\n\n // Inject CSS\n if (result.css) {\n if (cssMode === 'injected') {\n const cssCode = result.css.replace(/`/g, '\\\\`').replace(/\\\\/g, '\\\\\\\\');\n const styleId = id.replace(/[^a-zA-Z0-9]/g, '_');\n output += `\\n// Injected scoped styles\\n`;\n output += `const __akash_style = document.createElement('style');\\n`;\n output += `__akash_style.setAttribute('data-akash-style', '${styleId}');\\n`;\n output += `__akash_style.textContent = \\`${cssCode}\\`;\\n`;\n output += `document.head.appendChild(__akash_style);\\n`;\n\n // Add style HMR in dev mode\n if (!isProduction) {\n output += generateStyleHmrCode(styleId);\n }\n }\n }\n\n // Add HMR support in dev mode\n if (!isProduction) {\n output += generateHmrCode(id);\n }\n\n // Cache source for HMR diffing\n sourceCache.set(id, code);\n\n return {\n code: output,\n map: null, // TODO: integrate SourceMapBuilder\n };\n },\n\n handleHotUpdate({ file, server, modules, read }) {\n if (!file.endsWith('.akash')) return;\n\n const oldSource = sourceCache.get(file);\n\n if (oldSource) {\n // Read new source to analyze what changed\n read().then((newSource) => {\n const analysis = analyzeHmrChange(oldSource, newSource);\n\n if (analysis.styleOnly) {\n // Style-only change — Vite will handle the CSS update\n // via the style HMR code we injected\n server.ws.send({\n type: 'custom',\n event: 'akash:style-update',\n data: { file },\n });\n }\n });\n }\n\n // Always return modules to invalidate — the HMR code in the\n // client handles the actual update strategy\n return modules;\n },\n };\n}\n\nexport { akash };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akashjs/vite-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "AkashJS Vite plugin — .akash file transformation and HMR",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -23,10 +23,11 @@
23
23
  "vite": "^5.0.0"
24
24
  },
25
25
  "dependencies": {
26
- "@akashjs/compiler": "^0.1.1"
26
+ "@akashjs/compiler": "^0.1.3"
27
27
  },
28
28
  "files": [
29
- "dist"
29
+ "dist",
30
+ "README.md"
30
31
  ],
31
32
  "license": "MIT",
32
33
  "publishConfig": {