@thelacanians/vue-native-cli 0.1.2 → 0.3.0
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/cli.js +498 -112
- package/dist/config.d.ts +46 -0
- package/dist/config.js +72 -0
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -9,10 +9,15 @@ import { Command } from "commander";
|
|
|
9
9
|
import { mkdir, writeFile } from "fs/promises";
|
|
10
10
|
import { join } from "path";
|
|
11
11
|
import pc from "picocolors";
|
|
12
|
-
var createCommand = new Command("create").description("Create a new Vue Native project").argument("<name>", "project name").action(async (name) => {
|
|
12
|
+
var createCommand = new Command("create").description("Create a new Vue Native project").argument("<name>", "project name").option("-t, --template <template>", "project template (blank, tabs, drawer)", "blank").action(async (name, options) => {
|
|
13
|
+
const template = options.template;
|
|
14
|
+
if (!["blank", "tabs", "drawer"].includes(template)) {
|
|
15
|
+
console.error(pc.red(`Invalid template "${template}". Choose: blank, tabs, drawer`));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
13
18
|
const dir = join(process.cwd(), name);
|
|
14
19
|
console.log(pc.cyan(`
|
|
15
|
-
Creating Vue Native project: ${pc.bold(name)}
|
|
20
|
+
Creating Vue Native project: ${pc.bold(name)} (template: ${template})
|
|
16
21
|
`));
|
|
17
22
|
try {
|
|
18
23
|
await mkdir(dir, { recursive: true });
|
|
@@ -29,12 +34,12 @@ Creating Vue Native project: ${pc.bold(name)}
|
|
|
29
34
|
typecheck: "tsc --noEmit"
|
|
30
35
|
},
|
|
31
36
|
dependencies: {
|
|
32
|
-
"@thelacanians/vue-native-runtime": "^0.
|
|
33
|
-
"@thelacanians/vue-native-navigation": "^0.
|
|
37
|
+
"@thelacanians/vue-native-runtime": "^0.3.0",
|
|
38
|
+
"@thelacanians/vue-native-navigation": "^0.3.0",
|
|
34
39
|
"vue": "^3.5.0"
|
|
35
40
|
},
|
|
36
41
|
devDependencies: {
|
|
37
|
-
"@thelacanians/vue-native-vite-plugin": "^0.
|
|
42
|
+
"@thelacanians/vue-native-vite-plugin": "^0.3.0",
|
|
38
43
|
"@vitejs/plugin-vue": "^5.0.0",
|
|
39
44
|
"vite": "^6.1.0",
|
|
40
45
|
"typescript": "^5.7.0"
|
|
@@ -60,79 +65,7 @@ export default defineConfig({
|
|
|
60
65
|
},
|
|
61
66
|
include: ["app/**/*"]
|
|
62
67
|
}, null, 2));
|
|
63
|
-
await
|
|
64
|
-
import { createRouter } from '@thelacanians/vue-native-navigation'
|
|
65
|
-
import App from './App.vue'
|
|
66
|
-
import Home from './pages/Home.vue'
|
|
67
|
-
|
|
68
|
-
const router = createRouter([
|
|
69
|
-
{ name: 'Home', component: Home },
|
|
70
|
-
])
|
|
71
|
-
|
|
72
|
-
const app = createApp(App)
|
|
73
|
-
app.use(router)
|
|
74
|
-
app.start()
|
|
75
|
-
`);
|
|
76
|
-
await writeFile(join(dir, "app", "App.vue"), `<template>
|
|
77
|
-
<VSafeArea :style="{ flex: 1, backgroundColor: '#ffffff' }">
|
|
78
|
-
<RouterView />
|
|
79
|
-
</VSafeArea>
|
|
80
|
-
</template>
|
|
81
|
-
|
|
82
|
-
<script setup lang="ts">
|
|
83
|
-
import { RouterView } from '@thelacanians/vue-native-navigation'
|
|
84
|
-
</script>
|
|
85
|
-
`);
|
|
86
|
-
await writeFile(join(dir, "app", "pages", "Home.vue"), `<template>
|
|
87
|
-
<VView :style="styles.container">
|
|
88
|
-
<VText :style="styles.title">Hello, Vue Native! \u{1F389}</VText>
|
|
89
|
-
<VText :style="styles.subtitle">Edit app/pages/Home.vue to get started.</VText>
|
|
90
|
-
<VButton :style="styles.button" @press="count++">
|
|
91
|
-
<VText :style="styles.buttonText">Count: {{ count }}</VText>
|
|
92
|
-
</VButton>
|
|
93
|
-
</VView>
|
|
94
|
-
</template>
|
|
95
|
-
|
|
96
|
-
<script setup lang="ts">
|
|
97
|
-
import { ref } from 'vue'
|
|
98
|
-
import { createStyleSheet } from 'vue'
|
|
99
|
-
|
|
100
|
-
const count = ref(0)
|
|
101
|
-
|
|
102
|
-
const styles = createStyleSheet({
|
|
103
|
-
container: {
|
|
104
|
-
flex: 1,
|
|
105
|
-
justifyContent: 'center',
|
|
106
|
-
alignItems: 'center',
|
|
107
|
-
padding: 24,
|
|
108
|
-
},
|
|
109
|
-
title: {
|
|
110
|
-
fontSize: 28,
|
|
111
|
-
fontWeight: 'bold',
|
|
112
|
-
color: '#1a1a1a',
|
|
113
|
-
marginBottom: 8,
|
|
114
|
-
textAlign: 'center',
|
|
115
|
-
},
|
|
116
|
-
subtitle: {
|
|
117
|
-
fontSize: 16,
|
|
118
|
-
color: '#666',
|
|
119
|
-
textAlign: 'center',
|
|
120
|
-
marginBottom: 32,
|
|
121
|
-
},
|
|
122
|
-
button: {
|
|
123
|
-
backgroundColor: '#4f46e5',
|
|
124
|
-
paddingHorizontal: 32,
|
|
125
|
-
paddingVertical: 14,
|
|
126
|
-
borderRadius: 12,
|
|
127
|
-
},
|
|
128
|
-
buttonText: {
|
|
129
|
-
color: '#ffffff',
|
|
130
|
-
fontSize: 18,
|
|
131
|
-
fontWeight: '600',
|
|
132
|
-
},
|
|
133
|
-
})
|
|
134
|
-
</script>
|
|
135
|
-
`);
|
|
68
|
+
await generateTemplateFiles(dir, name, template);
|
|
136
69
|
const iosDir = join(dir, "ios");
|
|
137
70
|
const iosSrcDir = join(iosDir, "Sources");
|
|
138
71
|
await mkdir(iosSrcDir, { recursive: true });
|
|
@@ -388,42 +321,487 @@ android.useAndroidX=true
|
|
|
388
321
|
kotlin.code.style=official
|
|
389
322
|
android.nonTransitiveRClass=true
|
|
390
323
|
`);
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
324
|
+
await writeFile(join(dir, "vue-native.config.ts"), `import { defineConfig } from '@thelacanians/vue-native-cli'
|
|
325
|
+
|
|
326
|
+
export default defineConfig({
|
|
327
|
+
name: '${name}',
|
|
328
|
+
bundleId: '${bundleId}',
|
|
329
|
+
version: '1.0.0',
|
|
330
|
+
ios: {
|
|
331
|
+
deploymentTarget: '16.0',
|
|
332
|
+
},
|
|
333
|
+
android: {
|
|
334
|
+
minSdk: 21,
|
|
335
|
+
targetSdk: 34,
|
|
336
|
+
},
|
|
337
|
+
})
|
|
338
|
+
`);
|
|
339
|
+
await writeFile(join(dir, "env.d.ts"), `/// <reference types="vite/client" />
|
|
340
|
+
declare module '*.vue' {
|
|
341
|
+
import type { DefineComponent } from 'vue'
|
|
342
|
+
const component: DefineComponent<{}, {}, any>
|
|
343
|
+
export default component
|
|
344
|
+
}
|
|
345
|
+
declare const __DEV__: boolean
|
|
346
|
+
`);
|
|
347
|
+
await writeFile(join(dir, ".gitignore"), `node_modules/
|
|
348
|
+
dist/
|
|
349
|
+
*.xcuserstate
|
|
350
|
+
*.xcuserdatad/
|
|
351
|
+
DerivedData/
|
|
352
|
+
.build/
|
|
353
|
+
build/
|
|
354
|
+
.gradle/
|
|
355
|
+
local.properties
|
|
356
|
+
*.apk
|
|
357
|
+
*.aab
|
|
358
|
+
.DS_Store
|
|
359
|
+
`);
|
|
360
|
+
console.log(pc.green(" Project created successfully!\n"));
|
|
361
|
+
console.log(pc.white(" Next steps:\n"));
|
|
362
|
+
console.log(pc.white(` cd ${name}`));
|
|
363
|
+
console.log(pc.white(" bun install"));
|
|
364
|
+
console.log(pc.white(" vue-native dev\n"));
|
|
365
|
+
console.log(pc.white(" To run on iOS:"));
|
|
366
|
+
console.log(pc.white(" vue-native run ios\n"));
|
|
367
|
+
console.log(pc.white(" To run on Android:"));
|
|
368
|
+
console.log(pc.white(" vue-native run android\n"));
|
|
400
369
|
} catch (err) {
|
|
401
370
|
console.error(pc.red(`Error creating project: ${err.message}`));
|
|
402
371
|
process.exit(1);
|
|
403
372
|
}
|
|
404
373
|
});
|
|
374
|
+
async function generateTemplateFiles(dir, name, template) {
|
|
375
|
+
const pagesDir = join(dir, "app", "pages");
|
|
376
|
+
if (template === "blank") {
|
|
377
|
+
await generateBlankTemplate(dir, pagesDir);
|
|
378
|
+
} else if (template === "tabs") {
|
|
379
|
+
await generateTabsTemplate(dir, pagesDir);
|
|
380
|
+
} else if (template === "drawer") {
|
|
381
|
+
await generateDrawerTemplate(dir, pagesDir);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async function generateBlankTemplate(dir, pagesDir) {
|
|
385
|
+
await writeFile(join(dir, "app", "main.ts"), `import { createApp } from 'vue'
|
|
386
|
+
import { createRouter } from '@thelacanians/vue-native-navigation'
|
|
387
|
+
import App from './App.vue'
|
|
388
|
+
import Home from './pages/Home.vue'
|
|
389
|
+
|
|
390
|
+
const router = createRouter([
|
|
391
|
+
{ name: 'Home', component: Home },
|
|
392
|
+
])
|
|
393
|
+
|
|
394
|
+
const app = createApp(App)
|
|
395
|
+
app.use(router)
|
|
396
|
+
app.start()
|
|
397
|
+
`);
|
|
398
|
+
await writeFile(join(dir, "app", "App.vue"), `<template>
|
|
399
|
+
<VSafeArea :style="{ flex: 1, backgroundColor: '#ffffff' }">
|
|
400
|
+
<RouterView />
|
|
401
|
+
</VSafeArea>
|
|
402
|
+
</template>
|
|
403
|
+
|
|
404
|
+
<script setup lang="ts">
|
|
405
|
+
import { RouterView } from '@thelacanians/vue-native-navigation'
|
|
406
|
+
</script>
|
|
407
|
+
`);
|
|
408
|
+
await writeFile(join(pagesDir, "Home.vue"), `<script setup lang="ts">
|
|
409
|
+
import { ref } from 'vue'
|
|
410
|
+
import { createStyleSheet } from '@thelacanians/vue-native-runtime'
|
|
411
|
+
|
|
412
|
+
const count = ref(0)
|
|
413
|
+
|
|
414
|
+
const styles = createStyleSheet({
|
|
415
|
+
container: {
|
|
416
|
+
flex: 1,
|
|
417
|
+
justifyContent: 'center',
|
|
418
|
+
alignItems: 'center',
|
|
419
|
+
padding: 24,
|
|
420
|
+
},
|
|
421
|
+
title: {
|
|
422
|
+
fontSize: 28,
|
|
423
|
+
fontWeight: 'bold',
|
|
424
|
+
color: '#1a1a1a',
|
|
425
|
+
marginBottom: 8,
|
|
426
|
+
textAlign: 'center',
|
|
427
|
+
},
|
|
428
|
+
subtitle: {
|
|
429
|
+
fontSize: 16,
|
|
430
|
+
color: '#666',
|
|
431
|
+
textAlign: 'center',
|
|
432
|
+
marginBottom: 32,
|
|
433
|
+
},
|
|
434
|
+
button: {
|
|
435
|
+
backgroundColor: '#4f46e5',
|
|
436
|
+
paddingHorizontal: 32,
|
|
437
|
+
paddingVertical: 14,
|
|
438
|
+
borderRadius: 12,
|
|
439
|
+
},
|
|
440
|
+
buttonText: {
|
|
441
|
+
color: '#ffffff',
|
|
442
|
+
fontSize: 18,
|
|
443
|
+
fontWeight: '600',
|
|
444
|
+
},
|
|
445
|
+
})
|
|
446
|
+
</script>
|
|
447
|
+
|
|
448
|
+
<template>
|
|
449
|
+
<VView :style="styles.container">
|
|
450
|
+
<VText :style="styles.title">Hello, Vue Native!</VText>
|
|
451
|
+
<VText :style="styles.subtitle">Edit app/pages/Home.vue to get started.</VText>
|
|
452
|
+
<VButton :style="styles.button" :onPress="() => count++">
|
|
453
|
+
<VText :style="styles.buttonText">Count: {{ count }}</VText>
|
|
454
|
+
</VButton>
|
|
455
|
+
</VView>
|
|
456
|
+
</template>
|
|
457
|
+
`);
|
|
458
|
+
}
|
|
459
|
+
async function generateTabsTemplate(dir, pagesDir) {
|
|
460
|
+
await writeFile(join(dir, "app", "main.ts"), `import { createApp } from 'vue'
|
|
461
|
+
import App from './App.vue'
|
|
462
|
+
|
|
463
|
+
const app = createApp(App)
|
|
464
|
+
app.start()
|
|
465
|
+
`);
|
|
466
|
+
await writeFile(join(dir, "app", "App.vue"), `<script setup lang="ts">
|
|
467
|
+
import { createTabNavigator } from '@thelacanians/vue-native-navigation'
|
|
468
|
+
import Home from './pages/Home.vue'
|
|
469
|
+
import Settings from './pages/Settings.vue'
|
|
470
|
+
|
|
471
|
+
const { TabNavigator } = createTabNavigator()
|
|
472
|
+
</script>
|
|
473
|
+
|
|
474
|
+
<template>
|
|
475
|
+
<VSafeArea :style="{ flex: 1, backgroundColor: '#ffffff' }">
|
|
476
|
+
<TabNavigator
|
|
477
|
+
:screens="[
|
|
478
|
+
{ name: 'home', label: 'Home', icon: 'H', component: Home },
|
|
479
|
+
{ name: 'settings', label: 'Settings', icon: 'S', component: Settings },
|
|
480
|
+
]"
|
|
481
|
+
/>
|
|
482
|
+
</VSafeArea>
|
|
483
|
+
</template>
|
|
484
|
+
`);
|
|
485
|
+
await writeFile(join(pagesDir, "Home.vue"), `<script setup lang="ts">
|
|
486
|
+
import { ref } from 'vue'
|
|
487
|
+
import { createStyleSheet } from '@thelacanians/vue-native-runtime'
|
|
488
|
+
|
|
489
|
+
const count = ref(0)
|
|
490
|
+
|
|
491
|
+
const styles = createStyleSheet({
|
|
492
|
+
container: {
|
|
493
|
+
flex: 1,
|
|
494
|
+
justifyContent: 'center',
|
|
495
|
+
alignItems: 'center',
|
|
496
|
+
padding: 24,
|
|
497
|
+
},
|
|
498
|
+
title: {
|
|
499
|
+
fontSize: 28,
|
|
500
|
+
fontWeight: 'bold',
|
|
501
|
+
color: '#1a1a1a',
|
|
502
|
+
marginBottom: 16,
|
|
503
|
+
},
|
|
504
|
+
button: {
|
|
505
|
+
backgroundColor: '#4f46e5',
|
|
506
|
+
paddingHorizontal: 32,
|
|
507
|
+
paddingVertical: 14,
|
|
508
|
+
borderRadius: 12,
|
|
509
|
+
marginTop: 16,
|
|
510
|
+
},
|
|
511
|
+
buttonText: {
|
|
512
|
+
color: '#ffffff',
|
|
513
|
+
fontSize: 18,
|
|
514
|
+
fontWeight: '600',
|
|
515
|
+
},
|
|
516
|
+
})
|
|
517
|
+
</script>
|
|
518
|
+
|
|
519
|
+
<template>
|
|
520
|
+
<VView :style="styles.container">
|
|
521
|
+
<VText :style="styles.title">Home</VText>
|
|
522
|
+
<VText>Count: {{ count }}</VText>
|
|
523
|
+
<VButton :style="styles.button" :onPress="() => count++">
|
|
524
|
+
<VText :style="styles.buttonText">Increment</VText>
|
|
525
|
+
</VButton>
|
|
526
|
+
</VView>
|
|
527
|
+
</template>
|
|
528
|
+
`);
|
|
529
|
+
await writeFile(join(pagesDir, "Settings.vue"), `<script setup lang="ts">
|
|
530
|
+
import { ref } from 'vue'
|
|
531
|
+
import { createStyleSheet } from '@thelacanians/vue-native-runtime'
|
|
532
|
+
|
|
533
|
+
const darkMode = ref(false)
|
|
534
|
+
|
|
535
|
+
const styles = createStyleSheet({
|
|
536
|
+
container: {
|
|
537
|
+
flex: 1,
|
|
538
|
+
padding: 24,
|
|
539
|
+
},
|
|
540
|
+
title: {
|
|
541
|
+
fontSize: 28,
|
|
542
|
+
fontWeight: 'bold',
|
|
543
|
+
color: '#1a1a1a',
|
|
544
|
+
marginBottom: 24,
|
|
545
|
+
},
|
|
546
|
+
row: {
|
|
547
|
+
flexDirection: 'row',
|
|
548
|
+
justifyContent: 'space-between',
|
|
549
|
+
alignItems: 'center',
|
|
550
|
+
paddingVertical: 12,
|
|
551
|
+
borderBottomWidth: 1,
|
|
552
|
+
borderBottomColor: '#e0e0e0',
|
|
553
|
+
},
|
|
554
|
+
label: {
|
|
555
|
+
fontSize: 16,
|
|
556
|
+
color: '#333',
|
|
557
|
+
},
|
|
558
|
+
})
|
|
559
|
+
</script>
|
|
560
|
+
|
|
561
|
+
<template>
|
|
562
|
+
<VView :style="styles.container">
|
|
563
|
+
<VText :style="styles.title">Settings</VText>
|
|
564
|
+
<VView :style="styles.row">
|
|
565
|
+
<VText :style="styles.label">Dark Mode</VText>
|
|
566
|
+
<VSwitch v-model="darkMode" />
|
|
567
|
+
</VView>
|
|
568
|
+
</VView>
|
|
569
|
+
</template>
|
|
570
|
+
`);
|
|
571
|
+
}
|
|
572
|
+
async function generateDrawerTemplate(dir, pagesDir) {
|
|
573
|
+
await writeFile(join(dir, "app", "main.ts"), `import { createApp } from 'vue'
|
|
574
|
+
import App from './App.vue'
|
|
575
|
+
|
|
576
|
+
const app = createApp(App)
|
|
577
|
+
app.start()
|
|
578
|
+
`);
|
|
579
|
+
await writeFile(join(dir, "app", "App.vue"), `<script setup lang="ts">
|
|
580
|
+
import { createDrawerNavigator } from '@thelacanians/vue-native-navigation'
|
|
581
|
+
import Home from './pages/Home.vue'
|
|
582
|
+
import About from './pages/About.vue'
|
|
583
|
+
|
|
584
|
+
const { DrawerNavigator } = createDrawerNavigator()
|
|
585
|
+
</script>
|
|
586
|
+
|
|
587
|
+
<template>
|
|
588
|
+
<VSafeArea :style="{ flex: 1, backgroundColor: '#ffffff' }">
|
|
589
|
+
<DrawerNavigator
|
|
590
|
+
:screens="[
|
|
591
|
+
{ name: 'home', label: 'Home', icon: 'H', component: Home },
|
|
592
|
+
{ name: 'about', label: 'About', icon: 'A', component: About },
|
|
593
|
+
]"
|
|
594
|
+
/>
|
|
595
|
+
</VSafeArea>
|
|
596
|
+
</template>
|
|
597
|
+
`);
|
|
598
|
+
await writeFile(join(pagesDir, "Home.vue"), `<script setup lang="ts">
|
|
599
|
+
import { createStyleSheet } from '@thelacanians/vue-native-runtime'
|
|
600
|
+
import { useDrawer } from '@thelacanians/vue-native-navigation'
|
|
601
|
+
|
|
602
|
+
const { toggleDrawer } = useDrawer()
|
|
603
|
+
|
|
604
|
+
const styles = createStyleSheet({
|
|
605
|
+
container: {
|
|
606
|
+
flex: 1,
|
|
607
|
+
padding: 24,
|
|
608
|
+
},
|
|
609
|
+
header: {
|
|
610
|
+
flexDirection: 'row',
|
|
611
|
+
alignItems: 'center',
|
|
612
|
+
marginBottom: 24,
|
|
613
|
+
},
|
|
614
|
+
menuButton: {
|
|
615
|
+
backgroundColor: '#f0f0f0',
|
|
616
|
+
paddingHorizontal: 12,
|
|
617
|
+
paddingVertical: 8,
|
|
618
|
+
borderRadius: 8,
|
|
619
|
+
marginRight: 16,
|
|
620
|
+
},
|
|
621
|
+
menuText: {
|
|
622
|
+
fontSize: 18,
|
|
623
|
+
},
|
|
624
|
+
title: {
|
|
625
|
+
fontSize: 24,
|
|
626
|
+
fontWeight: 'bold',
|
|
627
|
+
color: '#1a1a1a',
|
|
628
|
+
},
|
|
629
|
+
body: {
|
|
630
|
+
fontSize: 16,
|
|
631
|
+
color: '#666',
|
|
632
|
+
lineHeight: 24,
|
|
633
|
+
},
|
|
634
|
+
})
|
|
635
|
+
</script>
|
|
636
|
+
|
|
637
|
+
<template>
|
|
638
|
+
<VView :style="styles.container">
|
|
639
|
+
<VView :style="styles.header">
|
|
640
|
+
<VButton :style="styles.menuButton" :onPress="toggleDrawer">
|
|
641
|
+
<VText :style="styles.menuText">Menu</VText>
|
|
642
|
+
</VButton>
|
|
643
|
+
<VText :style="styles.title">Home</VText>
|
|
644
|
+
</VView>
|
|
645
|
+
<VText :style="styles.body">
|
|
646
|
+
Swipe from the left or tap Menu to open the drawer.
|
|
647
|
+
</VText>
|
|
648
|
+
</VView>
|
|
649
|
+
</template>
|
|
650
|
+
`);
|
|
651
|
+
await writeFile(join(pagesDir, "About.vue"), `<script setup lang="ts">
|
|
652
|
+
import { createStyleSheet } from '@thelacanians/vue-native-runtime'
|
|
653
|
+
import { useDrawer } from '@thelacanians/vue-native-navigation'
|
|
654
|
+
|
|
655
|
+
const { toggleDrawer } = useDrawer()
|
|
656
|
+
|
|
657
|
+
const styles = createStyleSheet({
|
|
658
|
+
container: {
|
|
659
|
+
flex: 1,
|
|
660
|
+
padding: 24,
|
|
661
|
+
},
|
|
662
|
+
header: {
|
|
663
|
+
flexDirection: 'row',
|
|
664
|
+
alignItems: 'center',
|
|
665
|
+
marginBottom: 24,
|
|
666
|
+
},
|
|
667
|
+
menuButton: {
|
|
668
|
+
backgroundColor: '#f0f0f0',
|
|
669
|
+
paddingHorizontal: 12,
|
|
670
|
+
paddingVertical: 8,
|
|
671
|
+
borderRadius: 8,
|
|
672
|
+
marginRight: 16,
|
|
673
|
+
},
|
|
674
|
+
menuText: {
|
|
675
|
+
fontSize: 18,
|
|
676
|
+
},
|
|
677
|
+
title: {
|
|
678
|
+
fontSize: 24,
|
|
679
|
+
fontWeight: 'bold',
|
|
680
|
+
color: '#1a1a1a',
|
|
681
|
+
},
|
|
682
|
+
body: {
|
|
683
|
+
fontSize: 16,
|
|
684
|
+
color: '#666',
|
|
685
|
+
lineHeight: 24,
|
|
686
|
+
},
|
|
687
|
+
})
|
|
688
|
+
</script>
|
|
689
|
+
|
|
690
|
+
<template>
|
|
691
|
+
<VView :style="styles.container">
|
|
692
|
+
<VView :style="styles.header">
|
|
693
|
+
<VButton :style="styles.menuButton" :onPress="toggleDrawer">
|
|
694
|
+
<VText :style="styles.menuText">Menu</VText>
|
|
695
|
+
</VButton>
|
|
696
|
+
<VText :style="styles.title">About</VText>
|
|
697
|
+
</VView>
|
|
698
|
+
<VText :style="styles.body">
|
|
699
|
+
Built with Vue Native.
|
|
700
|
+
</VText>
|
|
701
|
+
</VView>
|
|
702
|
+
</template>
|
|
703
|
+
`);
|
|
704
|
+
}
|
|
405
705
|
|
|
406
706
|
// src/commands/dev.ts
|
|
407
707
|
import { Command as Command2 } from "commander";
|
|
408
|
-
import { spawn } from "child_process";
|
|
708
|
+
import { spawn, execSync } from "child_process";
|
|
409
709
|
import { readFile } from "fs/promises";
|
|
710
|
+
import { existsSync } from "fs";
|
|
410
711
|
import { join as join2 } from "path";
|
|
411
712
|
import { watch } from "chokidar";
|
|
412
713
|
import { WebSocketServer, WebSocket } from "ws";
|
|
413
714
|
import pc2 from "picocolors";
|
|
414
715
|
var DEFAULT_PORT = 8174;
|
|
415
716
|
var BUNDLE_FILE = "dist/vue-native-bundle.js";
|
|
416
|
-
|
|
717
|
+
function detectIOSSimulators() {
|
|
718
|
+
try {
|
|
719
|
+
const output = execSync("xcrun simctl list devices available -j", {
|
|
720
|
+
stdio: "pipe",
|
|
721
|
+
encoding: "utf8"
|
|
722
|
+
});
|
|
723
|
+
const data = JSON.parse(output);
|
|
724
|
+
const simulators = [];
|
|
725
|
+
for (const [runtime, devices] of Object.entries(data.devices ?? {})) {
|
|
726
|
+
if (!runtime.includes("iOS")) continue;
|
|
727
|
+
for (const device of devices) {
|
|
728
|
+
if (device.isAvailable !== false) {
|
|
729
|
+
simulators.push({
|
|
730
|
+
name: device.name,
|
|
731
|
+
udid: device.udid,
|
|
732
|
+
state: device.state
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return simulators;
|
|
738
|
+
} catch {
|
|
739
|
+
return [];
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function bootSimulator(udid) {
|
|
743
|
+
try {
|
|
744
|
+
execSync(`xcrun simctl boot "${udid}"`, { stdio: "pipe" });
|
|
745
|
+
} catch {
|
|
746
|
+
}
|
|
747
|
+
try {
|
|
748
|
+
execSync("open -a Simulator", { stdio: "pipe" });
|
|
749
|
+
} catch {
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
function detectAndroidEmulators() {
|
|
753
|
+
try {
|
|
754
|
+
const output = execSync("adb devices", { stdio: "pipe", encoding: "utf8" });
|
|
755
|
+
const lines = output.split("\n").filter((l) => l.includes("device") && !l.startsWith("List"));
|
|
756
|
+
return lines.map((l) => l.split(" ")[0]).filter(Boolean);
|
|
757
|
+
} catch {
|
|
758
|
+
return [];
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
var devCommand = new Command2("dev").description("Start the Vue Native dev server with hot reload").option("-p, --port <port>", "WebSocket port for hot reload", String(DEFAULT_PORT)).option("--ios", "auto-detect and launch iOS Simulator").option("--android", "auto-detect Android emulator").option("--simulator <name>", "specify iOS Simulator name").action(async (options) => {
|
|
417
762
|
const port = parseInt(options.port, 10);
|
|
418
763
|
const cwd = process.cwd();
|
|
419
764
|
const bundlePath = join2(cwd, BUNDLE_FILE);
|
|
420
|
-
console.log(pc2.cyan("\n
|
|
765
|
+
console.log(pc2.cyan("\n Vue Native Dev Server\n"));
|
|
766
|
+
if (options.ios) {
|
|
767
|
+
console.log(pc2.white(" Detecting iOS Simulators..."));
|
|
768
|
+
const simulators = detectIOSSimulators();
|
|
769
|
+
if (simulators.length === 0) {
|
|
770
|
+
console.log(pc2.yellow(" No iOS Simulators found. Install Xcode and create a simulator."));
|
|
771
|
+
} else {
|
|
772
|
+
let target = simulators.find((s) => s.state === "Booted");
|
|
773
|
+
if (!target && options.simulator) {
|
|
774
|
+
target = simulators.find((s) => s.name === options.simulator);
|
|
775
|
+
}
|
|
776
|
+
if (!target) {
|
|
777
|
+
target = simulators.find((s) => s.name.includes("iPhone")) ?? simulators[0];
|
|
778
|
+
}
|
|
779
|
+
if (target) {
|
|
780
|
+
if (target.state !== "Booted") {
|
|
781
|
+
console.log(pc2.white(` Booting ${target.name}...`));
|
|
782
|
+
bootSimulator(target.udid);
|
|
783
|
+
}
|
|
784
|
+
console.log(pc2.green(` iOS Simulator ready: ${target.name}`));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
console.log();
|
|
788
|
+
}
|
|
789
|
+
if (options.android) {
|
|
790
|
+
console.log(pc2.white(" Detecting Android emulators..."));
|
|
791
|
+
const emulators = detectAndroidEmulators();
|
|
792
|
+
if (emulators.length === 0) {
|
|
793
|
+
console.log(pc2.yellow(" No Android emulators detected. Start one via Android Studio or `emulator -avd <name>`."));
|
|
794
|
+
} else {
|
|
795
|
+
console.log(pc2.green(` Android emulator(s) connected: ${emulators.join(", ")}`));
|
|
796
|
+
}
|
|
797
|
+
console.log();
|
|
798
|
+
}
|
|
421
799
|
const wss = new WebSocketServer({ port });
|
|
422
800
|
const clients = /* @__PURE__ */ new Set();
|
|
423
801
|
wss.on("connection", (ws) => {
|
|
424
802
|
clients.add(ws);
|
|
425
803
|
ws.send(JSON.stringify({ type: "connected" }));
|
|
426
|
-
console.log(pc2.green(`
|
|
804
|
+
console.log(pc2.green(` Client connected (${clients.size} total)`));
|
|
427
805
|
readFile(bundlePath, "utf8").then((bundle) => {
|
|
428
806
|
if (ws.readyState === WebSocket.OPEN) {
|
|
429
807
|
ws.send(JSON.stringify({ type: "bundle", bundle }));
|
|
@@ -433,7 +811,7 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
|
|
|
433
811
|
});
|
|
434
812
|
ws.on("close", () => {
|
|
435
813
|
clients.delete(ws);
|
|
436
|
-
console.log(pc2.dim(`
|
|
814
|
+
console.log(pc2.dim(` Client disconnected (${clients.size} remaining)`));
|
|
437
815
|
});
|
|
438
816
|
ws.on("message", (data) => {
|
|
439
817
|
try {
|
|
@@ -447,7 +825,15 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
|
|
|
447
825
|
console.error(pc2.red(`WebSocket server error: ${err.message}`));
|
|
448
826
|
});
|
|
449
827
|
console.log(pc2.white(` Hot reload server: ${pc2.bold(`ws://localhost:${port}`)}`));
|
|
450
|
-
|
|
828
|
+
const iosDir = join2(cwd, "ios");
|
|
829
|
+
const androidDir = join2(cwd, "android");
|
|
830
|
+
if (existsSync(iosDir)) {
|
|
831
|
+
console.log(pc2.dim(` iOS app should connect to ws://localhost:${port}`));
|
|
832
|
+
}
|
|
833
|
+
if (existsSync(androidDir)) {
|
|
834
|
+
console.log(pc2.dim(` Android emulator should connect to ws://10.0.2.2:${port}`));
|
|
835
|
+
}
|
|
836
|
+
console.log(pc2.dim(" Waiting for app to connect...\n"));
|
|
451
837
|
console.log(pc2.white(" Starting Vite build watcher...\n"));
|
|
452
838
|
const vite = spawn(
|
|
453
839
|
"bun",
|
|
@@ -483,8 +869,8 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
|
|
|
483
869
|
sent++;
|
|
484
870
|
}
|
|
485
871
|
}
|
|
486
|
-
console.log(pc2.green(`
|
|
487
|
-
} catch
|
|
872
|
+
console.log(pc2.green(` Bundle updated (${Math.round(bundle.length / 1024)}KB) -> sent to ${sent} client(s)`));
|
|
873
|
+
} catch {
|
|
488
874
|
}
|
|
489
875
|
}
|
|
490
876
|
setInterval(() => {
|
|
@@ -504,16 +890,16 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
|
|
|
504
890
|
|
|
505
891
|
// src/commands/run.ts
|
|
506
892
|
import { Command as Command3 } from "commander";
|
|
507
|
-
import { spawn as spawn2, execSync } from "child_process";
|
|
508
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
893
|
+
import { spawn as spawn2, execSync as execSync2 } from "child_process";
|
|
894
|
+
import { existsSync as existsSync2, readdirSync, readFileSync } from "fs";
|
|
509
895
|
import { join as join3 } from "path";
|
|
510
896
|
import pc3 from "picocolors";
|
|
511
|
-
function findAppPath(
|
|
897
|
+
function findAppPath(_buildDir) {
|
|
512
898
|
const derivedDataBase = join3(
|
|
513
899
|
process.env.HOME || "~",
|
|
514
900
|
"Library/Developer/Xcode/DerivedData"
|
|
515
901
|
);
|
|
516
|
-
if (
|
|
902
|
+
if (existsSync2(derivedDataBase)) {
|
|
517
903
|
try {
|
|
518
904
|
const projects = readdirSync(derivedDataBase);
|
|
519
905
|
for (const project of projects.reverse()) {
|
|
@@ -522,7 +908,7 @@ function findAppPath(buildDir) {
|
|
|
522
908
|
project,
|
|
523
909
|
"Build/Products/Debug-iphonesimulator"
|
|
524
910
|
);
|
|
525
|
-
if (
|
|
911
|
+
if (existsSync2(productsDir)) {
|
|
526
912
|
const entries = readdirSync(productsDir);
|
|
527
913
|
const app = entries.find((e) => e.endsWith(".app"));
|
|
528
914
|
if (app) {
|
|
@@ -537,7 +923,7 @@ function findAppPath(buildDir) {
|
|
|
537
923
|
}
|
|
538
924
|
function readBundleId(iosDir) {
|
|
539
925
|
const plistPath = join3(iosDir, "Sources", "Info.plist");
|
|
540
|
-
if (
|
|
926
|
+
if (existsSync2(plistPath)) {
|
|
541
927
|
try {
|
|
542
928
|
const content = readFileSync(plistPath, "utf8");
|
|
543
929
|
const match = content.match(
|
|
@@ -553,7 +939,7 @@ function readBundleId(iosDir) {
|
|
|
553
939
|
}
|
|
554
940
|
function findApkPath(androidDir) {
|
|
555
941
|
const apkDir = join3(androidDir, "app", "build", "outputs", "apk", "debug");
|
|
556
|
-
if (
|
|
942
|
+
if (existsSync2(apkDir)) {
|
|
557
943
|
try {
|
|
558
944
|
const entries = readdirSync(apkDir);
|
|
559
945
|
const apk = entries.find((e) => e.endsWith(".apk") && !e.includes("androidTest"));
|
|
@@ -576,7 +962,7 @@ var runCommand = new Command3("run").description("Build and run the app").argume
|
|
|
576
962
|
`));
|
|
577
963
|
console.log(pc3.white(" Building JS bundle..."));
|
|
578
964
|
try {
|
|
579
|
-
|
|
965
|
+
execSync2("bun run vite build", { cwd, stdio: "inherit" });
|
|
580
966
|
console.log(pc3.green(" \u2713 Bundle built\n"));
|
|
581
967
|
} catch {
|
|
582
968
|
console.error(pc3.red(" \u2717 Bundle build failed"));
|
|
@@ -591,7 +977,7 @@ var runCommand = new Command3("run").description("Build and run the app").argume
|
|
|
591
977
|
function runIOS(cwd, options) {
|
|
592
978
|
let xcodeProject = null;
|
|
593
979
|
const iosDir = join3(cwd, "ios");
|
|
594
|
-
if (
|
|
980
|
+
if (existsSync2(iosDir)) {
|
|
595
981
|
for (const ext of [".xcworkspace", ".xcodeproj"]) {
|
|
596
982
|
try {
|
|
597
983
|
const entries = readdirSync(iosDir);
|
|
@@ -644,18 +1030,18 @@ function runIOS(cwd, options) {
|
|
|
644
1030
|
const bundleId = options.bundleId || readBundleId(join3(cwd, "ios"));
|
|
645
1031
|
console.log(pc3.white(` Booting simulator "${simulatorName}"...`));
|
|
646
1032
|
try {
|
|
647
|
-
|
|
1033
|
+
execSync2(`xcrun simctl boot "${simulatorName}"`, { stdio: "pipe" });
|
|
648
1034
|
} catch {
|
|
649
1035
|
}
|
|
650
1036
|
try {
|
|
651
|
-
|
|
1037
|
+
execSync2("open -a Simulator", { stdio: "pipe" });
|
|
652
1038
|
} catch {
|
|
653
1039
|
}
|
|
654
1040
|
const appPath = findAppPath(join3(cwd, "ios"));
|
|
655
1041
|
if (appPath) {
|
|
656
1042
|
console.log(pc3.white(` Installing app on simulator...`));
|
|
657
1043
|
try {
|
|
658
|
-
|
|
1044
|
+
execSync2(`xcrun simctl install booted "${appPath}"`, { stdio: "pipe" });
|
|
659
1045
|
console.log(pc3.green(" \u2713 App installed"));
|
|
660
1046
|
} catch (err) {
|
|
661
1047
|
console.error(pc3.red(` \u2717 Failed to install app: ${err.message}`));
|
|
@@ -663,7 +1049,7 @@ function runIOS(cwd, options) {
|
|
|
663
1049
|
}
|
|
664
1050
|
console.log(pc3.white(` Launching ${bundleId}...`));
|
|
665
1051
|
try {
|
|
666
|
-
|
|
1052
|
+
execSync2(`xcrun simctl launch booted "${bundleId}"`, { stdio: "pipe" });
|
|
667
1053
|
console.log(pc3.green(` \u2713 App launched on ${simulatorName}
|
|
668
1054
|
`));
|
|
669
1055
|
} catch (err) {
|
|
@@ -678,14 +1064,14 @@ function runIOS(cwd, options) {
|
|
|
678
1064
|
}
|
|
679
1065
|
function runAndroid(cwd, options) {
|
|
680
1066
|
const androidDir = join3(cwd, "android");
|
|
681
|
-
if (!
|
|
1067
|
+
if (!existsSync2(androidDir)) {
|
|
682
1068
|
console.log(pc3.yellow(" No android/ directory found."));
|
|
683
1069
|
console.log(pc3.dim(" To add Android support, create an Android project in the android/ directory."));
|
|
684
1070
|
console.log(pc3.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
|
|
685
1071
|
return;
|
|
686
1072
|
}
|
|
687
1073
|
const gradlew = join3(androidDir, "gradlew");
|
|
688
|
-
if (!
|
|
1074
|
+
if (!existsSync2(gradlew)) {
|
|
689
1075
|
console.error(pc3.red(" \u2717 gradlew not found in android/ directory"));
|
|
690
1076
|
console.log(pc3.dim(" Make sure your Android project has the Gradle wrapper.\n"));
|
|
691
1077
|
process.exit(1);
|
|
@@ -726,7 +1112,7 @@ function runAndroid(cwd, options) {
|
|
|
726
1112
|
}
|
|
727
1113
|
console.log(pc3.white(" Installing APK on device/emulator..."));
|
|
728
1114
|
try {
|
|
729
|
-
|
|
1115
|
+
execSync2(`adb install -r "${apkPath}"`, { stdio: "pipe" });
|
|
730
1116
|
console.log(pc3.green(" \u2713 APK installed"));
|
|
731
1117
|
} catch (err) {
|
|
732
1118
|
console.error(pc3.red(` \u2717 Failed to install APK: ${err.message}`));
|
|
@@ -736,7 +1122,7 @@ function runAndroid(cwd, options) {
|
|
|
736
1122
|
const componentName = `${options.package}/${options.activity}`;
|
|
737
1123
|
console.log(pc3.white(` Launching ${componentName}...`));
|
|
738
1124
|
try {
|
|
739
|
-
|
|
1125
|
+
execSync2(`adb shell am start -n "${componentName}"`, { stdio: "pipe" });
|
|
740
1126
|
console.log(pc3.green(` \u2713 App launched
|
|
741
1127
|
`));
|
|
742
1128
|
} catch (err) {
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
interface VueNativeConfig {
|
|
2
|
+
/** Display name for the app. */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Bundle identifier (e.g. com.example.myapp). */
|
|
5
|
+
bundleId: string;
|
|
6
|
+
/** App version string (semver). */
|
|
7
|
+
version: string;
|
|
8
|
+
/** iOS-specific configuration. */
|
|
9
|
+
ios?: {
|
|
10
|
+
/** Minimum iOS deployment target. Default: "16.0". */
|
|
11
|
+
deploymentTarget?: string;
|
|
12
|
+
/** Xcode scheme name (auto-derived from name if omitted). */
|
|
13
|
+
scheme?: string;
|
|
14
|
+
};
|
|
15
|
+
/** Android-specific configuration. */
|
|
16
|
+
android?: {
|
|
17
|
+
/** Minimum Android SDK version. Default: 21. */
|
|
18
|
+
minSdk?: number;
|
|
19
|
+
/** Target Android SDK version. Default: 34. */
|
|
20
|
+
targetSdk?: number;
|
|
21
|
+
/** Android package name (defaults to bundleId). */
|
|
22
|
+
packageName?: string;
|
|
23
|
+
};
|
|
24
|
+
/** List of Vue Native plugins to include. */
|
|
25
|
+
plugins?: string[];
|
|
26
|
+
}
|
|
27
|
+
interface ResolvedConfig extends VueNativeConfig {
|
|
28
|
+
ios: {
|
|
29
|
+
deploymentTarget: string;
|
|
30
|
+
scheme: string;
|
|
31
|
+
};
|
|
32
|
+
android: {
|
|
33
|
+
minSdk: number;
|
|
34
|
+
targetSdk: number;
|
|
35
|
+
packageName: string;
|
|
36
|
+
};
|
|
37
|
+
plugins: string[];
|
|
38
|
+
}
|
|
39
|
+
declare function defineConfig(config: VueNativeConfig): VueNativeConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Load and resolve the vue-native.config.{ts,js,mjs} file from the project root.
|
|
42
|
+
* Returns null if no config file is found.
|
|
43
|
+
*/
|
|
44
|
+
declare function loadConfig(cwd: string): Promise<ResolvedConfig | null>;
|
|
45
|
+
|
|
46
|
+
export { type ResolvedConfig, type VueNativeConfig, defineConfig, loadConfig };
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { pathToFileURL } from "url";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
function defineConfig(config) {
|
|
7
|
+
return config;
|
|
8
|
+
}
|
|
9
|
+
function validateConfig(config) {
|
|
10
|
+
if (typeof config !== "object" || config === null) return false;
|
|
11
|
+
const c = config;
|
|
12
|
+
if (typeof c.name !== "string" || c.name.length === 0) {
|
|
13
|
+
console.error(pc.red(' Config error: "name" is required and must be a non-empty string.'));
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (typeof c.bundleId !== "string" || !/^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$/i.test(c.bundleId)) {
|
|
17
|
+
console.error(pc.red(' Config error: "bundleId" must be a valid reverse-domain identifier (e.g. com.example.myapp).'));
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (typeof c.version !== "string" || c.version.length === 0) {
|
|
21
|
+
console.error(pc.red(' Config error: "version" is required (e.g. "1.0.0").'));
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
var CONFIG_FILES = [
|
|
27
|
+
"vue-native.config.ts",
|
|
28
|
+
"vue-native.config.js",
|
|
29
|
+
"vue-native.config.mjs"
|
|
30
|
+
];
|
|
31
|
+
async function loadConfig(cwd) {
|
|
32
|
+
let configPath = null;
|
|
33
|
+
for (const filename of CONFIG_FILES) {
|
|
34
|
+
const candidate = join(cwd, filename);
|
|
35
|
+
if (existsSync(candidate)) {
|
|
36
|
+
configPath = candidate;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!configPath) return null;
|
|
41
|
+
try {
|
|
42
|
+
const mod = await import(pathToFileURL(configPath).href);
|
|
43
|
+
const raw = mod.default ?? mod;
|
|
44
|
+
if (!validateConfig(raw)) {
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const config = raw;
|
|
48
|
+
const safeName = config.name.replace(/[^a-zA-Z0-9]/g, "");
|
|
49
|
+
const resolved = {
|
|
50
|
+
...config,
|
|
51
|
+
ios: {
|
|
52
|
+
deploymentTarget: config.ios?.deploymentTarget ?? "16.0",
|
|
53
|
+
scheme: config.ios?.scheme ?? safeName
|
|
54
|
+
},
|
|
55
|
+
android: {
|
|
56
|
+
minSdk: config.android?.minSdk ?? 21,
|
|
57
|
+
targetSdk: config.android?.targetSdk ?? 34,
|
|
58
|
+
packageName: config.android?.packageName ?? config.bundleId
|
|
59
|
+
},
|
|
60
|
+
plugins: config.plugins ?? []
|
|
61
|
+
};
|
|
62
|
+
return resolved;
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(pc.red(` Failed to load config from ${configPath}:`));
|
|
65
|
+
console.error(pc.red(` ${err.message}`));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
defineConfig,
|
|
71
|
+
loadConfig
|
|
72
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thelacanians/vue-native-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI for creating and running Vue Native apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vue Native Contributors",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"vue-native": "./dist/cli.js"
|
|
18
18
|
},
|
|
19
19
|
"exports": {
|
|
20
|
-
".": "./dist/
|
|
20
|
+
".": "./dist/config.js",
|
|
21
|
+
"./cli": "./dist/cli.js"
|
|
21
22
|
},
|
|
22
23
|
"files": ["dist", "README.md"],
|
|
23
24
|
"scripts": {
|