nuclie 1.0.7 → 1.0.9

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 CHANGED
@@ -432,14 +432,21 @@ nuclie bootstrap --name my-app --template svelte-ts
432
432
  nuclie bootstrap --name my-app --template solid-ts
433
433
  nuclie bootstrap --name my-app --template preact-ts
434
434
  nuclie bootstrap --name my-app --template lit-ts
435
+ nuclie bootstrap --name my-app --template mithril-ts
436
+ nuclie bootstrap --name my-app --template alpine-ts
435
437
  nuclie bootstrap --name my-app --template vanilla-ts
436
438
 
437
439
  # JavaScript
438
- nuclie bootstrap --name my-app --template react-js
439
- nuclie bootstrap --name my-app --template vue-js
440
- nuclie bootstrap --name my-app --template svelte-js
441
- nuclie bootstrap --name my-app --template alpine-js
442
- nuclie bootstrap --name my-app --template vanilla-js
440
+ nuclie bootstrap --name my-app --template react
441
+ nuclie bootstrap --name my-app --template vue
442
+ nuclie bootstrap --name my-app --template svelte
443
+ nuclie bootstrap --name my-app --template solid
444
+ nuclie bootstrap --name my-app --template preact
445
+ nuclie bootstrap --name my-app --template lit
446
+ nuclie bootstrap --name my-app --template qwik
447
+ nuclie bootstrap --name my-app --template mithril
448
+ nuclie bootstrap --name my-app --template alpine
449
+ nuclie bootstrap --name my-app --template vanilla
443
450
  ```
444
451
 
445
452
  ---
@@ -454,9 +461,9 @@ nuclie bootstrap --name my-app --template vanilla-js
454
461
  | SolidJS | ✅ Stable | ✅ Signal-aware | ✅ | |
455
462
  | Preact | ✅ Stable | ✅ Fast Refresh | ✅ | React compat |
456
463
  | Lit | ✅ Verified | ✅ Web Component | ✅ | |
457
- | Alpine.js | ✅ Verified | ✅ Core Reload | | HTML-first |
464
+ | Alpine.js | ✅ Verified | ✅ Core Reload | | HTML-first |
458
465
  | Qwik | 🔶 Experimental | ✅ | ✅ | |
459
- | Mithril.js | 🔵 Legacy | ✅ | | |
466
+ | Mithril.js | Stable | ✅ | | |
460
467
  | Vanilla JS | ✅ Stable | ✅ | ✅ | |
461
468
 
462
469
  ---
package/dist/cli.js CHANGED
File without changes
@@ -4,7 +4,7 @@ export declare const BuildConfigSchema: z.ZodObject<{
4
4
  root: z.ZodOptional<z.ZodString>;
5
5
  adapter: z.ZodOptional<z.ZodString>;
6
6
  framework: z.ZodOptional<z.ZodString>;
7
- entry: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<string[], string | string[]>>>;
7
+ entry: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>, z.ZodTransform<string[], string | string[]>>>;
8
8
  mode: z.ZodDefault<z.ZodEnum<{
9
9
  development: "development";
10
10
  production: "production";
@@ -13,7 +13,7 @@ export const BuildConfigSchema = z.object({
13
13
  framework: z.string().optional(),
14
14
  entry: z.union([z.string(), z.array(z.string())])
15
15
  .transform((val) => (typeof val === 'string' ? [val] : val))
16
- .default(['src/main.tsx']),
16
+ .optional(),
17
17
  mode: z.enum(['development', 'production', 'test']).default('development'),
18
18
  outDir: z.string().default('build_output'),
19
19
  port: z.number().default(5173),
@@ -135,27 +135,9 @@ export async function loadConfig(cwd) {
135
135
  else {
136
136
  // Return default config if file not found, with auto-detection
137
137
  log.info('No config file found, using defaults...');
138
- // Auto-detect entry point
139
- const entryCandidates = [
140
- 'src/main.tsx',
141
- 'src/main.ts',
142
- 'src/main.jsx',
143
- 'src/main.js',
144
- 'src/index.tsx',
145
- 'src/index.ts',
146
- 'src/index.jsx',
147
- 'src/index.js'
148
- ];
149
- let detectedEntry = ['src/main.tsx']; // Default fallback
150
- for (const candidate of entryCandidates) {
151
- if (await fs.access(path.join(cwd, candidate)).then(() => true).catch(() => false)) {
152
- detectedEntry = [candidate];
153
- break;
154
- }
155
- }
156
138
  return {
157
139
  root: cwd,
158
- entry: detectedEntry,
140
+ entry: [], // will be auto-detected below
159
141
  mode: 'development',
160
142
  outDir: 'build_output',
161
143
  port: 5173,
@@ -176,6 +158,29 @@ export async function loadConfig(cwd) {
176
158
  const config = result.data;
177
159
  // Ensure root is set
178
160
  const root = config.root || cwd;
161
+ // Auto-detect entry point if missing
162
+ if (!config.entry || config.entry.length === 0) {
163
+ const entryCandidates = [
164
+ 'src/main.tsx',
165
+ 'src/main.ts',
166
+ 'src/main.jsx',
167
+ 'src/main.js',
168
+ 'src/index.tsx',
169
+ 'src/index.ts',
170
+ 'src/index.jsx',
171
+ 'src/index.js',
172
+ 'src/root.tsx',
173
+ 'src/root.ts',
174
+ ];
175
+ let detectedEntry = ['src/main.tsx']; // Default fallback
176
+ for (const candidate of entryCandidates) {
177
+ if (await fs.access(path.join(root, candidate)).then(() => true).catch(() => false)) {
178
+ detectedEntry = [candidate];
179
+ break;
180
+ }
181
+ }
182
+ config.entry = detectedEntry;
183
+ }
179
184
  let finalConfig = { ...config };
180
185
  if (config.preset === 'spa')
181
186
  finalConfig = { ...finalConfig, ...spaPreset.apply(finalConfig) };
@@ -2,7 +2,7 @@
2
2
  * Framework Detector
3
3
  * Automatically detects which framework(s) are being used in the project
4
4
  */
5
- export type Framework = 'react' | 'vue' | 'svelte' | 'angular' | 'solid' | 'preact' | 'qwik' | 'lit' | 'astro' | 'next' | 'nuxt' | 'remix' | 'vanilla';
5
+ export type Framework = 'react' | 'vue' | 'svelte' | 'angular' | 'solid' | 'preact' | 'qwik' | 'lit' | 'astro' | 'next' | 'nuxt' | 'remix' | 'alpine' | 'mithril' | 'vanilla';
6
6
  export interface FrameworkInfo {
7
7
  name: Framework;
8
8
  version?: string;
@@ -122,6 +122,22 @@ export class FrameworkDetector {
122
122
  confidence: 1.0
123
123
  });
124
124
  }
125
+ if (deps['alpinejs']) {
126
+ frameworks.push({
127
+ name: 'alpine',
128
+ version: deps['alpinejs'],
129
+ detected: true,
130
+ confidence: 1.0
131
+ });
132
+ }
133
+ if (deps['mithril']) {
134
+ frameworks.push({
135
+ name: 'mithril',
136
+ version: deps['mithril'],
137
+ detected: true,
138
+ confidence: 1.0
139
+ });
140
+ }
125
141
  // If no framework detected, it's vanilla JS/TS
126
142
  if (frameworks.length === 0) {
127
143
  frameworks.push({
@@ -20,16 +20,26 @@ export class FrameworkPipeline {
20
20
  // Honor explicit configuration (Phase 2/3 Alignment)
21
21
  let framework = config.framework;
22
22
  if (!framework && config.adapter) {
23
- if (config.adapter.includes('react'))
23
+ if (config.adapter === 'react' || config.adapter === 'react-typescript' || config.adapter === 'react-adapter')
24
24
  framework = 'react';
25
- else if (config.adapter.includes('vue'))
25
+ else if (config.adapter === 'vue')
26
26
  framework = 'vue';
27
- else if (config.adapter.includes('svelte'))
27
+ else if (config.adapter === 'svelte')
28
28
  framework = 'svelte';
29
- else if (config.adapter.includes('angular'))
29
+ else if (config.adapter === 'angular')
30
30
  framework = 'angular';
31
- else if (config.adapter.includes('solid'))
31
+ else if (config.adapter === 'solid')
32
32
  framework = 'solid';
33
+ else if (config.adapter === 'preact')
34
+ framework = 'preact';
35
+ else if (config.adapter === 'qwik')
36
+ framework = 'qwik';
37
+ else if (config.adapter === 'lit')
38
+ framework = 'lit';
39
+ else if (config.adapter === 'alpine')
40
+ framework = 'alpine';
41
+ else if (config.adapter === 'mithril' || config.adapter === 'mithril-ts')
42
+ framework = 'mithril';
33
43
  }
34
44
  if (!framework) {
35
45
  framework = await detectFramework(rootDir);
@@ -8,6 +8,7 @@ import fs from 'fs/promises';
8
8
  import { getFrameworkPreset } from '../presets/frameworks.js';
9
9
  import { log } from '../utils/logger.js';
10
10
  import { createRequire } from 'module';
11
+ import { fileURLToPath, pathToFileURL } from 'url';
11
12
  import * as esbuild from 'esbuild';
12
13
  import { canonicalHash } from '../core/engine/hash.js';
13
14
  const _require = createRequire(import.meta.url);
@@ -219,8 +220,11 @@ if (import.meta.hot) {
219
220
  try {
220
221
  let compiler;
221
222
  try {
222
- const compilerPath = _require.resolve('@vue/compiler-sfc', { paths: [this.root, process.cwd()] });
223
- compiler = await import(compilerPath);
223
+ // Try: user project first, then nuclie's own node_modules (nuclie ships @vue/compiler-sfc as a dep)
224
+ const searchPaths = [this.root, process.cwd(), fileURLToPath(new URL('../..', import.meta.url))];
225
+ const compilerPath = _require.resolve('@vue/compiler-sfc', { paths: searchPaths });
226
+ const compilerUrl = pathToFileURL(compilerPath).href;
227
+ compiler = await import(compilerUrl);
224
228
  }
225
229
  catch {
226
230
  log.warn('No Vue 3 compiler found, using fallback with HMR');
@@ -317,7 +321,7 @@ if (import.meta.hot) {
317
321
  ` : ''}
318
322
 
319
323
  ${descriptor.styles.some((s) => s.scoped) ? `_sfc_main.__scopeId = "${scopeId}";` : ''}
320
- _sfc_main.__file = "${filePath}";
324
+ _sfc_main.__file = "${filePath.replace(/\\/g, '/')}";
321
325
 
322
326
  export default _sfc_main;
323
327
  `;
@@ -360,7 +364,8 @@ if (import.meta.hot) {
360
364
  let svelte;
361
365
  try {
362
366
  const compilerPath = _require.resolve('svelte/compiler', { paths: [this.root, process.cwd()] });
363
- const mod = await import(compilerPath);
367
+ const compilerUrl = pathToFileURL(compilerPath).href;
368
+ const mod = await import(compilerUrl);
364
369
  svelte = typeof mod.compile === 'function' ? mod : (mod.default || mod);
365
370
  }
366
371
  catch {
@@ -533,7 +538,8 @@ if (import.meta.hot) {
533
538
  if (dispose) dispose();
534
539
  const NewComponent = newModule.default || newModule[component];
535
540
  if (NewComponent && container) {
536
- import('solid-js/web').then(({ render }) => {
541
+ // Use server-relative path so the dev server resolves via exports field
542
+ import('/node_modules/solid-js/web').then(({ render }) => {
537
543
  render(() => NewComponent({}), container);
538
544
  });
539
545
  }
@@ -592,14 +598,19 @@ if (import.meta.hot) {
592
598
  * Qwik Transformer - Works with all Qwik versions
593
599
  */
594
600
  async transformQwik(code, filePath, isDev) {
601
+ const ext = path.extname(filePath);
602
+ if (ext !== '.tsx' && ext !== '.ts' && ext !== '.jsx' && ext !== '.js') {
603
+ return this.transformVanilla(code, filePath, isDev);
604
+ }
595
605
  try {
596
606
  let qwik;
597
607
  try {
598
608
  const compilerPath = _require.resolve('@builder.io/qwik/optimizer', { paths: [this.root, process.cwd()] });
599
- const mod = await import(compilerPath);
609
+ const mod = await import(pathToFileURL(compilerPath).href);
600
610
  qwik = typeof mod.createOptimizer === 'function' ? mod : (mod.default || mod);
601
611
  }
602
- catch {
612
+ catch (e) {
613
+ console.error("[Qwik Optimizer] Original import failed:", e);
603
614
  const fallbackQwikOptimizer = '@builder.io/qwik/optimizer';
604
615
  const mod = await import(fallbackQwikOptimizer);
605
616
  qwik = typeof mod.createOptimizer === 'function' ? mod : (mod.default || mod);
@@ -608,9 +619,11 @@ if (import.meta.hot) {
608
619
  const result = await optimizer.transformModules({
609
620
  input: [{ code, path: filePath }],
610
621
  srcDir: path.join(this.root, 'src'),
611
- entryStrategy: { type: 'single' },
622
+ rootDir: this.root,
623
+ entryStrategy: { type: 'inline' },
612
624
  minify: isDev ? 'none' : 'simplify',
613
625
  sourceMaps: isDev,
626
+ mode: isDev ? 'dev' : 'lib',
614
627
  transpile: true,
615
628
  });
616
629
  const output = result.modules[0];
@@ -618,15 +631,34 @@ if (import.meta.hot) {
618
631
  const final = await transform(output.code, {
619
632
  loader: 'tsx',
620
633
  format: 'esm',
621
- target: 'es2022',
634
+ target: 'es2020',
622
635
  jsx: 'automatic',
623
636
  jsxImportSource: '@builder.io/qwik'
624
637
  });
625
- return { code: final.code, map: final.map ? JSON.stringify(final.map) : undefined };
638
+ const finalCode = final.code;
639
+ return { code: finalCode, map: final.map ? JSON.stringify(final.map) : undefined };
626
640
  }
627
641
  catch (error) {
628
- log.error(`Qwik transform failed for ${filePath}: ${error.stack || error.message}`);
629
- return this.transformVanilla(code, filePath, isDev);
642
+ // Fallback: use esbuild directly with Qwik JSX classic mode
643
+ log.warn(`Qwik optimizer failed, using esbuild fallback: ${error.message}`);
644
+ try {
645
+ const final = await esbuild.transform(code, {
646
+ loader: (path.extname(filePath) === '.tsx' || path.extname(filePath) === '.jsx') ? 'tsx' : 'ts',
647
+ format: 'esm',
648
+ target: 'es2020',
649
+ jsx: 'transform',
650
+ jsxFactory: 'h',
651
+ jsxFragment: 'Fragment',
652
+ jsxImportSource: undefined,
653
+ });
654
+ // Inject h/Fragment imports from qwik
655
+ const imports = `import { h, Fragment } from '@builder.io/qwik';\n`;
656
+ return { code: imports + final.code };
657
+ }
658
+ catch (fallbackErr) {
659
+ log.error(`Qwik fallback also failed for ${filePath}: ${fallbackErr.message}`);
660
+ return this.transformVanilla(code, filePath, isDev);
661
+ }
630
662
  }
631
663
  }
632
664
  /**
@@ -5,8 +5,21 @@
5
5
  */
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
- import { TEMPLATES } from './templates.js';
8
+ import { fileURLToPath } from 'url';
9
+ import { TEMPLATES } from '../utils/templates.js';
9
10
  import { red, green, blue, bold } from 'kleur/colors';
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ // Read real nuclie version from its own package.json
13
+ function getNuclieVersion() {
14
+ try {
15
+ const pkgPath = path.resolve(__dirname, '../../package.json');
16
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
17
+ return `^${pkg.version}`;
18
+ }
19
+ catch {
20
+ return 'latest';
21
+ }
22
+ }
10
23
  async function main() {
11
24
  const args = process.argv.slice(2);
12
25
  let projectName = args[0];
@@ -43,29 +56,18 @@ async function main() {
43
56
  console.log(blue(`\n🚀 Scaffolding ${bold(template.name)} project in ${bold(projectName)}...`));
44
57
  // 1. Create Dir
45
58
  fs.mkdirSync(targetDir, { recursive: true });
46
- // 2. Create Files
59
+ // 2. Create Files (replace version placeholder with real version)
60
+ const nuclieVersion = getNuclieVersion();
61
+ const versionLabel = nuclieVersion.replace('^', '');
47
62
  for (const file of template.files) {
48
63
  const filePath = path.join(targetDir, file.path);
49
64
  const dir = path.dirname(filePath);
50
65
  if (!fs.existsSync(dir))
51
66
  fs.mkdirSync(dir, { recursive: true });
52
- fs.writeFileSync(filePath, file.content);
67
+ const content = file.content.replace(/\{\{NUCLIE_VERSION\}\}/g, versionLabel);
68
+ fs.writeFileSync(filePath, content);
53
69
  }
54
70
  // 3. Create package.json
55
- let nuclieVersion = 'latest';
56
- try {
57
- const pkgjsonPath = path.resolve(process.cwd(), 'node_modules/nuclie/package.json');
58
- if (fs.existsSync(pkgjsonPath)) {
59
- nuclieVersion = '^' + JSON.parse(fs.readFileSync(pkgjsonPath, 'utf8')).version;
60
- }
61
- else {
62
- const localPkgPath = new URL('../../package.json', import.meta.url);
63
- if (fs.existsSync(localPkgPath)) {
64
- nuclieVersion = '^' + JSON.parse(fs.readFileSync(localPkgPath, 'utf8')).version;
65
- }
66
- }
67
- }
68
- catch (e) { }
69
71
  const pkg = {
70
72
  name: projectName,
71
73
  version: '0.0.0',
File without changes