lumix-js 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/bin/lumix.js CHANGED
@@ -6,7 +6,7 @@ import { build } from "../dist/cli/build.js";
6
6
  import { preview } from "../dist/cli/preview.js";
7
7
  import { init } from "../dist/cli/init.js";
8
8
 
9
- const VERSION = "0.1.0";
9
+ const VERSION = "0.1.3";
10
10
 
11
11
  const program = new Command();
12
12
 
package/dist/cli/build.js CHANGED
@@ -5,24 +5,34 @@ import { loadConfig } from "./loader.js";
5
5
  import path from "path";
6
6
  import fs from "fs-extra";
7
7
  import { __dirname } from "./utils.js";
8
+ import { VERSION } from "./constants.js";
8
9
  export async function build() {
9
10
  const cwd = process.cwd();
10
11
  const config = await loadConfig(cwd);
11
12
  console.log("");
12
- console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim("v0.1.0")}`);
13
+ console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim(`v${VERSION}`)}`);
13
14
  console.log(pc.dim(" Building for production...\n"));
14
15
  const indexPath = path.join(cwd, "index.html");
15
16
  const hasIndex = fs.existsSync(indexPath);
16
- let tempIndex = false;
17
17
  try {
18
- if (!hasIndex) {
19
- tempIndex = true;
20
- // Auto-detect entry: main.ts > main.js
21
- const entry = fs.existsSync(path.join(cwd, "main.ts"))
22
- ? "/main.ts"
23
- : "/main.js";
24
- const defaultHtml = `
25
- <!DOCTYPE html>
18
+ // Auto-detect JS entry module: main.ts > main.js
19
+ const entryModule = fs.existsSync(path.join(cwd, "main.ts"))
20
+ ? path.join(cwd, "main.ts")
21
+ : path.join(cwd, "main.js");
22
+ // If there is no physical index.html, emit one directly into dist/index.html
23
+ // after the JS build is generated.
24
+ const htmlEmitPlugin = !hasIndex
25
+ ? {
26
+ name: "lumix-html-index-emitter",
27
+ generateBundle(_opts, bundle) {
28
+ // Find the main entry chunk (the one corresponding to main.ts/js)
29
+ const chunks = Object.values(bundle);
30
+ const entryChunk = chunks.find((c) => c.type === "chunk" && c.isEntry && c.facadeModuleId?.endsWith("main.ts")) ||
31
+ chunks.find((c) => c.type === "chunk" && c.isEntry);
32
+ const jsFile = entryChunk?.fileName;
33
+ if (!jsFile)
34
+ return;
35
+ const html = `<!DOCTYPE html>
26
36
  <html lang="en">
27
37
  <head>
28
38
  <meta charset="UTF-8">
@@ -30,19 +40,38 @@ export async function build() {
30
40
  </head>
31
41
  <body>
32
42
  <div id="${config?.rootId || "app"}"></div>
33
- <script type="module" src="${entry}"></script>
43
+ <script type="module" src="/${jsFile}"></script>
34
44
  </body>
35
- </html>
36
- `.trim();
37
- fs.writeFileSync(indexPath, defaultHtml);
38
- }
45
+ </html>`;
46
+ this.emitFile({
47
+ type: "asset",
48
+ fileName: "index.html",
49
+ source: html,
50
+ });
51
+ },
52
+ }
53
+ : null;
39
54
  await viteBuild({
40
55
  root: cwd,
41
56
  base: "/",
42
- plugins: [lumix(config), ...(config.vite?.plugins || [])],
57
+ plugins: [
58
+ ...(htmlEmitPlugin ? [htmlEmitPlugin] : []),
59
+ lumix(config),
60
+ ...(config.vite?.plugins || []),
61
+ ],
43
62
  build: {
44
63
  outDir: "dist",
45
64
  emptyOutDir: true,
65
+ // If there is no index.html, tell Vite/Rollup to use the JS entry module
66
+ // instead of the default HTML entry. The HTML file will be emitted by
67
+ // htmlEmitPlugin as dist/index.html.
68
+ ...(hasIndex
69
+ ? {}
70
+ : {
71
+ rollupOptions: {
72
+ input: entryModule,
73
+ },
74
+ }),
46
75
  ...config.vite?.build,
47
76
  },
48
77
  resolve: {
@@ -61,9 +90,4 @@ export async function build() {
61
90
  console.error(pc.red(` ${e.message}\n`));
62
91
  process.exit(1);
63
92
  }
64
- finally {
65
- if (tempIndex && fs.existsSync(indexPath)) {
66
- fs.removeSync(indexPath);
67
- }
68
- }
69
93
  }
@@ -0,0 +1 @@
1
+ export declare const VERSION = "0.1.3";
@@ -0,0 +1 @@
1
+ export const VERSION = "0.1.3";
package/dist/cli/dev.js CHANGED
@@ -5,6 +5,7 @@ import { loadConfig, findConfigPath } from "./loader.js";
5
5
  import path from "path";
6
6
  import fs from "fs";
7
7
  import { __dirname } from "./utils.js";
8
+ import { VERSION } from "./constants.js";
8
9
  async function startServer(cwd) {
9
10
  const config = await loadConfig(cwd);
10
11
  const server = await createServer({
@@ -30,7 +31,7 @@ async function startServer(cwd) {
30
31
  export async function dev() {
31
32
  const cwd = process.cwd();
32
33
  console.log("");
33
- console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim("v0.1.0")}`);
34
+ console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim(`v${VERSION}`)}`);
34
35
  console.log(pc.dim(" Starting development server...\n"));
35
36
  try {
36
37
  let server = await startServer(cwd);
package/dist/cli/init.js CHANGED
@@ -4,6 +4,7 @@ import fs from "fs-extra";
4
4
  import path from "path";
5
5
  import { __dirname } from "./utils.js";
6
6
  import { spawnSync } from "child_process";
7
+ import { VERSION } from "./constants.js";
7
8
  function isPackageManagerAvailable(pm) {
8
9
  try {
9
10
  let res = spawnSync(pm, ["--version"], { stdio: "ignore" });
@@ -86,7 +87,7 @@ function getInstallFailure(e) {
86
87
  }
87
88
  export async function init(name, options) {
88
89
  console.log("");
89
- console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim("v0.1.0")}`);
90
+ console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim(`v${VERSION}`)}`);
90
91
  console.log(pc.dim(" Scaffolding a new project...\n"));
91
92
  const templates = [
92
93
  { title: "Blank", value: "blank" },
@@ -4,11 +4,12 @@ import pc from "picocolors";
4
4
  import { loadConfig } from "./loader.js";
5
5
  import path from "path";
6
6
  import { __dirname } from "./utils.js";
7
+ import { VERSION } from "./constants.js";
7
8
  export async function preview() {
8
9
  const cwd = process.cwd();
9
10
  const config = await loadConfig(cwd);
10
11
  console.log("");
11
- console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim("v0.1.0")}`);
12
+ console.log(` ${pc.bold(pc.cyan("⚡ LumixJS"))} ${pc.dim(`v${VERSION}`)}`);
12
13
  console.log(pc.dim(" Previewing production build...\n"));
13
14
  try {
14
15
  const server = await vitePreview({
package/dist/config.d.ts CHANGED
@@ -19,6 +19,11 @@ export interface LuminConfig {
19
19
  * Root element ID to hydrate into. Defaults to 'app'.
20
20
  */
21
21
  rootId?: string;
22
+ /**
23
+ * Optional path (Vite id) of the root .lumix component for HMR.
24
+ * Example: "/LayoutDemo.lumix" or "/src/App.lumix".
25
+ */
26
+ rootComponent?: string;
22
27
  /**
23
28
  * Vite specific configuration overrides.
24
29
  */
package/dist/config.js CHANGED
@@ -6,6 +6,7 @@ const VALID_KEYS = new Set([
6
6
  "vite",
7
7
  "srcDir",
8
8
  "checkTypes",
9
+ "rootComponent",
9
10
  ]);
10
11
  /**
11
12
  * Helper function to provide types for the LuminJS config.
@@ -14,8 +15,8 @@ const VALID_KEYS = new Set([
14
15
  export function defineConfig(config) {
15
16
  const unknown = Object.keys(config).filter((k) => !VALID_KEYS.has(k));
16
17
  if (unknown.length > 0) {
17
- console.warn(`\x1b[33m[lumin] Warning: Unknown config field(s): ${unknown.map((k) => `"${k}"`).join(", ")}.\x1b[0m`);
18
- console.warn(`\x1b[33m[lumin] Valid fields are: ${[...VALID_KEYS].join(", ")}.\x1b[0m`);
18
+ console.warn(`\x1b[33m[lumix] Warning: Unknown config field(s): ${unknown.map((k) => `"${k}"`).join(", ")}.\x1b[0m`);
19
+ console.warn(`\x1b[33m[lumix] Valid fields are: ${[...VALID_KEYS].join(", ")}.\x1b[0m`);
19
20
  }
20
21
  return config;
21
22
  }
package/dist/dom.d.ts CHANGED
@@ -5,4 +5,8 @@ export interface Props {
5
5
  }
6
6
  export declare function h(tag: string | ((props: Props, ...children: any[]) => any), props: Props | null, ...children: any[]): any;
7
7
  export declare function Fragment(_props: any, ...children: any[]): any[];
8
- export declare function hydrate(root: HTMLElement, component: (props?: any) => HTMLElement, props?: any): void;
8
+ export declare function hydrate(root: HTMLElement, component: (props?: any) => any, props?: any): void;
9
+ export declare function mount(root: HTMLElement, component: (props?: any) => any, props?: any): {
10
+ update(nextComponent: (props?: any) => any): void;
11
+ destroy(): void;
12
+ };
package/dist/dom.js CHANGED
@@ -4,14 +4,16 @@ import { withHooks, runHooks } from "./lifecycle.js";
4
4
  export function h(tag, props, ...children) {
5
5
  if (typeof tag === "function") {
6
6
  const { result, mount, destroy } = withHooks(() => tag(props || {}, ...children));
7
- // If it's a component that returns a single element, we can attach hooks to it
8
- if (result instanceof HTMLElement) {
9
- if (mount.length > 0) {
10
- // Simple trick: use MutationObserver or just run on next tick if added
11
- setTimeout(() => runHooks(mount), 0);
12
- }
13
- if (destroy.length > 0) {
14
- result._luminDestroy = destroy;
7
+ // Attach hooks for single element or Fragment(array) roots.
8
+ const roots = Array.isArray(result) ? result : [result];
9
+ for (const r of roots) {
10
+ if (r instanceof HTMLElement) {
11
+ if (mount.length > 0) {
12
+ setTimeout(() => runHooks(mount), 0);
13
+ }
14
+ if (destroy.length > 0) {
15
+ r._luminDestroy = destroy;
16
+ }
15
17
  }
16
18
  }
17
19
  return result;
@@ -131,6 +133,61 @@ function unmount(node) {
131
133
  export function hydrate(root, component, props) {
132
134
  while (root.firstChild)
133
135
  root.removeChild(root.firstChild);
134
- const el = h(component, props || {});
135
- root.appendChild(el);
136
+ const out = h(component, props || {});
137
+ const nodes = Array.isArray(out) ? out : [out];
138
+ for (const n of nodes) {
139
+ if (n === null || n === undefined)
140
+ continue;
141
+ if (n instanceof Node)
142
+ root.appendChild(n);
143
+ else
144
+ root.appendChild(document.createTextNode(String(n)));
145
+ }
146
+ }
147
+ export function mount(root, component, props) {
148
+ const start = document.createComment("lumix-root-start");
149
+ const end = document.createComment("lumix-root-end");
150
+ while (root.firstChild)
151
+ root.removeChild(root.firstChild);
152
+ root.appendChild(start);
153
+ root.appendChild(end);
154
+ let currentNodes = [];
155
+ let currentComponent = component;
156
+ let currentProps = props;
157
+ const render = () => {
158
+ for (const node of currentNodes) {
159
+ unmount(node);
160
+ if (node.parentNode)
161
+ node.parentNode.removeChild(node);
162
+ }
163
+ currentNodes = [];
164
+ const out = h(currentComponent, currentProps || {});
165
+ const nodes = Array.isArray(out) ? out : [out];
166
+ for (const n of nodes) {
167
+ if (n === null || n === undefined)
168
+ continue;
169
+ const node = n instanceof Node ? n : document.createTextNode(String(n));
170
+ root.insertBefore(node, end);
171
+ currentNodes.push(node);
172
+ }
173
+ };
174
+ render();
175
+ return {
176
+ update(nextComponent) {
177
+ currentComponent = nextComponent;
178
+ render();
179
+ },
180
+ destroy() {
181
+ for (const node of currentNodes) {
182
+ unmount(node);
183
+ if (node.parentNode)
184
+ node.parentNode.removeChild(node);
185
+ }
186
+ currentNodes = [];
187
+ if (start.parentNode)
188
+ start.parentNode.removeChild(start);
189
+ if (end.parentNode)
190
+ end.parentNode.removeChild(end);
191
+ },
192
+ };
136
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumix-js",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "The modular runtime for LumixJS",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -7,4 +7,7 @@ export default defineConfig({
7
7
  { name: "description", content: "A beautiful app built with LuminJS" },
8
8
  ],
9
9
  },
10
+ rootId: "app",
11
+ rootComponent: "/src/App.lumix",
12
+ checkTypes: false,
10
13
  });
@@ -7,4 +7,6 @@ export default defineConfig({
7
7
  { name: "description", content: "A beautiful app built with LumixJS" },
8
8
  ],
9
9
  },
10
+ rootId: "app",
11
+ rootComponent: "/src/App.lumix",
10
12
  });