gotodev 1.0.0 → 2.0.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/cli.js +439 -401
- package/package.json +15 -3
- package/templates/base/README.md +21 -0
- package/templates/base/index.html +13 -0
- package/templates/base/vite.config.js +6 -0
- package/templates/code/default/App.vue +26 -0
- package/templates/code/typescript/App.vue +30 -0
- package/templates/code/typescript-router/App.vue +24 -0
- package/templates/config/jsx/vite.config.js +7 -0
- package/templates/config/pinia/store.js +12 -0
- package/templates/config/router/index.js +17 -0
- package/templates/config/router/views/HomeView.vue +9 -0
- package/templates/config/typescript/src/shims-vue.d.ts +5 -0
- package/templates/config/typescript/tsconfig.json +21 -0
- package/templates/config/typescript/tsconfig.node.json +10 -0
package/cli.js
CHANGED
|
@@ -2,457 +2,495 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Gotodev CLI - Lightning-fast app creator
|
|
5
|
-
*
|
|
5
|
+
* Fetches official Vite templates for latest packages
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const { Command } = require('commander');
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const chalk = require('chalk');
|
|
9
|
+
const { intro, outro, text, confirm, multiselect, select, isCancel, cancel, spinner } = require('@clack/prompts');
|
|
10
|
+
const { red, green, cyan, bold, dim } = require('picocolors');
|
|
12
11
|
const fs = require('fs-extra');
|
|
13
12
|
const path = require('path');
|
|
14
13
|
const { execSync } = require('child_process');
|
|
14
|
+
const { getViteTemplate } = require('./template-fetcher');
|
|
15
15
|
|
|
16
16
|
const program = new Command();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const container = document.getElementById('root');
|
|
43
|
-
if (container) {
|
|
44
|
-
createRoot(container).render(<App />);
|
|
45
|
-
}`,
|
|
46
|
-
'index.html': `<!DOCTYPE html>
|
|
47
|
-
<html>
|
|
48
|
-
<head>
|
|
49
|
-
<title>Gotodev React App</title>
|
|
50
|
-
<meta charset="UTF-8" />
|
|
51
|
-
</head>
|
|
52
|
-
<body>
|
|
53
|
-
<div id="root"></div>
|
|
54
|
-
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
|
55
|
-
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
|
56
|
-
<script type="module" src="/src/index.tsx"></script>
|
|
57
|
-
</body>
|
|
58
|
-
</html>`,
|
|
59
|
-
'package.json': `{
|
|
60
|
-
"name": "my-react-app",
|
|
61
|
-
"version": "1.0.0",
|
|
62
|
-
"type": "module",
|
|
63
|
-
"scripts": {
|
|
64
|
-
"dev": "gotodev dev",
|
|
65
|
-
"build": "gotodev build"
|
|
17
|
+
|
|
18
|
+
// -------------------------------------------------------------------------
|
|
19
|
+
// OFFICIAL TEMPLATE REGISTRY
|
|
20
|
+
// -------------------------------------------------------------------------
|
|
21
|
+
// Mapping from user-friendly name → GitHub repo (owner/repo). The repo must
|
|
22
|
+
// contain a `create-<framework>` directory with the scaffold files we need.
|
|
23
|
+
// Example: "next" → "vercel/next.js" (the repo that contains the `create-vite`
|
|
24
|
+
// template used by `create-next-app`).
|
|
25
|
+
// -------------------------------------------------------------------------
|
|
26
|
+
const TEMPLATE_REGISTRY = {
|
|
27
|
+
next: 'vercel/next.js',
|
|
28
|
+
nextjs: 'vercel/next.js',
|
|
29
|
+
shadcn: 'shadcn/ui',
|
|
30
|
+
tailwind: 'shadcn/ui',
|
|
31
|
+
'react-router': 'tanstack/react-router',
|
|
32
|
+
'tanstack-query': 'tanstack/query',
|
|
33
|
+
'tanstack-query-core': 'tanstack/query',
|
|
34
|
+
// add more as you like …
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Simple downloader that fetches from GitHub raw URLs
|
|
38
|
+
async function downloadTemplate(name) {
|
|
39
|
+
if (!TEMPLATE_REGISTRY[name]) {
|
|
40
|
+
console.error(`Unknown template: ${name}`);
|
|
41
|
+
process.exit(1);
|
|
66
42
|
}
|
|
67
|
-
|
|
43
|
+
const repo = TEMPLATE_REGISTRY[name];
|
|
44
|
+
|
|
45
|
+
// Use axios to fetch the repository's raw files
|
|
46
|
+
const axios = require('axios');
|
|
47
|
+
|
|
48
|
+
// For now, let's use a simple approach: fetch the create-vite template
|
|
49
|
+
// This is a placeholder - in a real implementation, you'd fetch the actual template files
|
|
50
|
+
console.log(`Downloading template: ${name} from ${repo}`);
|
|
51
|
+
|
|
52
|
+
// Create a temporary directory
|
|
53
|
+
const tmpDir = path.join(process.cwd(), `tmp/_gotodev-${Date.now()}`);
|
|
54
|
+
await fs.ensureDir(tmpDir);
|
|
55
|
+
|
|
56
|
+
// For demonstration, create a simple package.json
|
|
57
|
+
const packageJson = {
|
|
58
|
+
name: 'template-app',
|
|
59
|
+
version: '1.0.0',
|
|
60
|
+
type: 'module',
|
|
61
|
+
scripts: {
|
|
62
|
+
dev: 'vite',
|
|
63
|
+
build: 'vite build',
|
|
64
|
+
preview: 'vite preview'
|
|
65
|
+
},
|
|
66
|
+
dependencies: {
|
|
67
|
+
'react': '^18.2.0',
|
|
68
|
+
'react-dom': '^18.2.0'
|
|
69
|
+
},
|
|
70
|
+
devDependencies: {
|
|
71
|
+
'vite': '^5.0.0',
|
|
72
|
+
'@vitejs/plugin-react': '^4.2.1'
|
|
68
73
|
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
import
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
await fs.writeFile(path.join(tmpDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
77
|
+
await fs.writeFile(path.join(tmpDir, 'index.html'), '<!DOCTYPE html><html><head><title>Template</title></head><body><div id="root"></div><script type="module" src="/src/main.jsx"></script></body></html>');
|
|
78
|
+
await fs.ensureDir(path.join(tmpDir, 'src'));
|
|
79
|
+
await fs.writeFile(path.join(tmpDir, 'src/main.jsx'), `import React from 'react';
|
|
80
|
+
import ReactDOM from 'react-dom/client';
|
|
81
|
+
import App from './App.jsx';
|
|
82
|
+
|
|
83
|
+
ReactDOM.createRoot(document.getElementById('root')).render(<App />);`);
|
|
84
|
+
await fs.writeFile(path.join(tmpDir, 'src/App.jsx'), `export default function App() {
|
|
85
|
+
return <h1>Hello from ${name} template!</h1>;
|
|
86
|
+
}`);
|
|
87
|
+
await fs.writeFile(path.join(tmpDir, 'vite.config.js'), `import { defineConfig } from 'vite';
|
|
88
|
+
import react from '@vitejs/plugin-react';
|
|
89
|
+
|
|
90
|
+
export default defineConfig({
|
|
91
|
+
plugins: [react()],
|
|
92
|
+
});`);
|
|
93
|
+
|
|
94
|
+
return tmpDir;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Feature options
|
|
98
|
+
const FEATURE_OPTIONS = [
|
|
99
|
+
{ value: 'typescript', label: 'TypeScript' },
|
|
100
|
+
{ value: 'router', label: 'Vue Router' },
|
|
101
|
+
{ value: 'pinia', label: 'Pinia (State Management)' },
|
|
102
|
+
{ value: 'jsx', label: 'JSX Support' },
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
// Framework options
|
|
106
|
+
const FRAMEWORK_OPTIONS = [
|
|
107
|
+
{ value: 'vue', label: 'Vue (Official Vite template)' },
|
|
108
|
+
{ value: 'react', label: 'React (Vite + React)' },
|
|
109
|
+
{ value: 'svelte', label: 'Svelte (Vite + Svelte)' },
|
|
110
|
+
{ value: 'vanilla', label: 'Vanilla JavaScript (Vite)' },
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
// Helper functions
|
|
114
|
+
function isValidPackageName(projectName) {
|
|
115
|
+
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function toValidPackageName(projectName) {
|
|
119
|
+
return projectName
|
|
120
|
+
.trim()
|
|
121
|
+
.toLowerCase()
|
|
122
|
+
.replace(/\s+/g, '-')
|
|
123
|
+
.replace(/^[._]/, '')
|
|
124
|
+
.replace(/[^a-z0-9-~]+/g, '-');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function canSkipEmptying(dir) {
|
|
128
|
+
if (!fs.existsSync(dir)) return true;
|
|
129
|
+
const files = fs.readdirSync(dir);
|
|
130
|
+
if (files.length === 0) return true;
|
|
131
|
+
if (files.length === 1 && files[0] === '.git') return true;
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function emptyDir(dir) {
|
|
136
|
+
if (!fs.existsSync(dir)) return;
|
|
137
|
+
fs.emptyDirSync(dir);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getPackageManager() {
|
|
141
|
+
const userAgent = process.env.npm_config_user_agent || '';
|
|
142
|
+
if (userAgent.includes('pnpm')) return 'pnpm';
|
|
143
|
+
if (userAgent.includes('yarn')) return 'yarn';
|
|
144
|
+
if (userAgent.includes('bun')) return 'bun';
|
|
145
|
+
return 'npm';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getCommand(pm, script) {
|
|
149
|
+
const scripts = {
|
|
150
|
+
install: {
|
|
151
|
+
pnpm: 'pnpm install',
|
|
152
|
+
yarn: 'yarn install',
|
|
153
|
+
bun: 'bun install',
|
|
154
|
+
npm: 'npm install'
|
|
155
|
+
},
|
|
156
|
+
dev: {
|
|
157
|
+
pnpm: 'pnpm run dev',
|
|
158
|
+
yarn: 'yarn dev',
|
|
159
|
+
bun: 'bun run dev',
|
|
160
|
+
npm: 'npm run dev'
|
|
110
161
|
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
'index.html': `<!DOCTYPE html>
|
|
138
|
-
<html>
|
|
139
|
-
<head>
|
|
140
|
-
<title>Gotodev Svelte App</title>
|
|
141
|
-
<meta charset="UTF-8" />
|
|
142
|
-
</head>
|
|
143
|
-
<body>
|
|
144
|
-
<script type="module" src="/src/main.ts"></script>
|
|
145
|
-
</body>
|
|
146
|
-
</html>`,
|
|
147
|
-
'package.json': `{
|
|
148
|
-
"name": "my-svelte-app",
|
|
149
|
-
"version": "1.0.0",
|
|
150
|
-
"type": "module",
|
|
151
|
-
"scripts": {
|
|
152
|
-
"dev": "gotodev dev",
|
|
153
|
-
"build": "gotodev build"
|
|
154
|
-
}
|
|
155
|
-
}`
|
|
162
|
+
};
|
|
163
|
+
return scripts[script][pm] || scripts[script].npm;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Main init function
|
|
167
|
+
async function init() {
|
|
168
|
+
const cwd = process.cwd();
|
|
169
|
+
const args = process.argv.slice(2);
|
|
170
|
+
|
|
171
|
+
// Parse CLI arguments
|
|
172
|
+
const flags = ['typescript', 'ts', 'router', 'pinia', 'jsx', 'force', 'bare', 'help', 'version'];
|
|
173
|
+
const options = {};
|
|
174
|
+
let targetDir = null;
|
|
175
|
+
|
|
176
|
+
for (let i = 0; i < args.length; i++) {
|
|
177
|
+
const arg = args[i];
|
|
178
|
+
if (arg.startsWith('--')) {
|
|
179
|
+
const flag = arg.slice(2);
|
|
180
|
+
if (flags.includes(flag)) {
|
|
181
|
+
options[flag] = true;
|
|
182
|
+
} else if (arg.includes('=')) {
|
|
183
|
+
const [key, value] = arg.slice(2).split('=');
|
|
184
|
+
options[key] = value;
|
|
185
|
+
}
|
|
186
|
+
} else if (!arg.startsWith('-') && !targetDir) {
|
|
187
|
+
targetDir = arg;
|
|
156
188
|
}
|
|
157
|
-
},
|
|
158
|
-
vanilla: {
|
|
159
|
-
name: 'Vanilla',
|
|
160
|
-
description: 'Pure TypeScript',
|
|
161
|
-
files: {
|
|
162
|
-
'src/main.ts': `const app = document.getElementById('app');
|
|
163
|
-
if (app) {
|
|
164
|
-
app.innerHTML = \`
|
|
165
|
-
<h1>⚡ Gotodev Vanilla App</h1>
|
|
166
|
-
<p>TypeScript ready!</p>
|
|
167
|
-
\`;
|
|
168
|
-
}`,
|
|
169
|
-
'index.html': `<!DOCTYPE html>
|
|
170
|
-
<html>
|
|
171
|
-
<head>
|
|
172
|
-
<title>Gotodev Vanilla App</title>
|
|
173
|
-
<meta charset="UTF-8" />
|
|
174
|
-
</head>
|
|
175
|
-
<body>
|
|
176
|
-
<div id="app"></div>
|
|
177
|
-
<script type="module" src="/src/main.ts"></script>
|
|
178
|
-
</body>
|
|
179
|
-
</html>`,
|
|
180
|
-
'package.json': `{
|
|
181
|
-
"name": "my-vanilla-app",
|
|
182
|
-
"version": "1.0.0",
|
|
183
|
-
"type": "module",
|
|
184
|
-
"scripts": {
|
|
185
|
-
"dev": "gotodev dev",
|
|
186
|
-
"build": "gotodev build"
|
|
187
189
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
|
|
191
|
+
if (options.help) {
|
|
192
|
+
console.log(`\
|
|
193
|
+
Usage: gotodev create [DIRECTORY] [OPTIONS]
|
|
194
|
+
|
|
195
|
+
Create a new Vite-powered project using official templates.
|
|
196
|
+
|
|
197
|
+
Options:
|
|
198
|
+
--typescript, --ts Add TypeScript support
|
|
199
|
+
--router Add Vue Router (Vue only)
|
|
200
|
+
--pinia Add Pinia (Vue only)
|
|
201
|
+
--jsx Add JSX support
|
|
202
|
+
--force Force overwrite existing directory
|
|
203
|
+
--bare Minimal template without example code
|
|
204
|
+
--help Display this help message
|
|
205
|
+
--version Display version number
|
|
206
|
+
|
|
207
|
+
Feature flags can be used to skip interactive prompts.
|
|
208
|
+
|
|
209
|
+
Examples:
|
|
210
|
+
gotodev create my-app
|
|
211
|
+
gotodev create my-app --typescript --router
|
|
212
|
+
gotodev create my-app --ts --pinia --force`);
|
|
213
|
+
process.exit(0);
|
|
190
214
|
}
|
|
191
|
-
};
|
|
192
215
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
transform_jsx: true,
|
|
198
|
-
target: 'es2020'
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const result = compiler.transform(code, filename);
|
|
202
|
-
return result.code;
|
|
203
|
-
}
|
|
216
|
+
if (options.version) {
|
|
217
|
+
console.log(`gotodev v${require('./package.json').version}`);
|
|
218
|
+
process.exit(0);
|
|
219
|
+
}
|
|
204
220
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
221
|
+
const defaultProjectName = targetDir || 'my-project';
|
|
222
|
+
const forceOverwrite = options.force || false;
|
|
223
|
+
|
|
224
|
+
// Start interactive mode
|
|
225
|
+
intro(`${cyan('⚡')} gotodev - Lightning-fast app creator`);
|
|
226
|
+
|
|
227
|
+
// Get project name
|
|
228
|
+
if (!targetDir) {
|
|
229
|
+
const _result = await text({
|
|
230
|
+
message: 'Project name:',
|
|
231
|
+
placeholder: defaultProjectName,
|
|
232
|
+
defaultValue: defaultProjectName,
|
|
233
|
+
validate: (value) =>
|
|
234
|
+
value.length === 0 || value.trim().length > 0
|
|
235
|
+
? undefined
|
|
236
|
+
: 'Project name cannot be empty'
|
|
237
|
+
});
|
|
211
238
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
process.exit(1);
|
|
239
|
+
if (isCancel(_result)) {
|
|
240
|
+
cancel('Operation cancelled');
|
|
241
|
+
process.exit(0);
|
|
216
242
|
}
|
|
217
243
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
244
|
+
targetDir = _result.trim();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Check directory
|
|
248
|
+
if (!canSkipEmptying(targetDir) && !forceOverwrite) {
|
|
249
|
+
const shouldOverwrite = await confirm({
|
|
250
|
+
message: `${targetDir === '.' ? 'Current directory' : `Directory "${targetDir}"`} is not empty. Overwrite?`,
|
|
251
|
+
initialValue: false
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (isCancel(shouldOverwrite) || !shouldOverwrite) {
|
|
255
|
+
cancel('Operation cancelled');
|
|
256
|
+
process.exit(0);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Get package name
|
|
261
|
+
let packageName = targetDir;
|
|
262
|
+
if (!isValidPackageName(targetDir)) {
|
|
263
|
+
const _packageName = await text({
|
|
264
|
+
message: 'Package name:',
|
|
265
|
+
initialValue: toValidPackageName(targetDir),
|
|
266
|
+
validate: (value) =>
|
|
267
|
+
isValidPackageName(value)
|
|
268
|
+
? undefined
|
|
269
|
+
: 'Invalid package name'
|
|
270
|
+
});
|
|
222
271
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const dir = path.dirname(fullPath);
|
|
227
|
-
|
|
228
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
229
|
-
|
|
230
|
-
// Compile TypeScript files
|
|
231
|
-
if (filePath.endsWith('.tsx') || filePath.endsWith('.ts')) {
|
|
232
|
-
spinner.text = `Compiling ${filePath}...`;
|
|
233
|
-
const compiled = await compileWithGotodev(content, filePath);
|
|
234
|
-
fs.writeFileSync(fullPath.replace(/\.(tsx|ts)$/, '.js'), compiled);
|
|
235
|
-
|
|
236
|
-
// Also keep original for reference
|
|
237
|
-
fs.writeFileSync(fullPath, content);
|
|
238
|
-
} else {
|
|
239
|
-
fs.writeFileSync(fullPath, content);
|
|
240
|
-
}
|
|
272
|
+
if (isCancel(_packageName)) {
|
|
273
|
+
cancel('Operation cancelled');
|
|
274
|
+
process.exit(0);
|
|
241
275
|
}
|
|
242
276
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Generated with **Gotodev** ⚡
|
|
277
|
+
packageName = _packageName;
|
|
278
|
+
}
|
|
247
279
|
|
|
248
|
-
|
|
280
|
+
// Check if any feature flags were used
|
|
281
|
+
const isFeatureFlagsUsed = Object.keys(options).some(key =>
|
|
282
|
+
['typescript', 'ts', 'router', 'pinia', 'jsx'].includes(key)
|
|
283
|
+
);
|
|
249
284
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
npm install
|
|
285
|
+
let selectedFramework = 'vue';
|
|
286
|
+
let selectedFeatures = [];
|
|
253
287
|
|
|
254
|
-
|
|
255
|
-
|
|
288
|
+
if (!isFeatureFlagsUsed) {
|
|
289
|
+
// Interactive framework selection
|
|
290
|
+
selectedFramework = await select({
|
|
291
|
+
message: 'Select framework:',
|
|
292
|
+
options: FRAMEWORK_OPTIONS,
|
|
293
|
+
initialValue: 'vue'
|
|
294
|
+
});
|
|
256
295
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
296
|
+
if (isCancel(selectedFramework)) {
|
|
297
|
+
cancel('Operation cancelled');
|
|
298
|
+
process.exit(0);
|
|
299
|
+
}
|
|
260
300
|
|
|
261
|
-
|
|
301
|
+
// Interactive feature selection
|
|
302
|
+
selectedFeatures = await multiselect({
|
|
303
|
+
message: 'Select features (use space to toggle):',
|
|
304
|
+
options: FEATURE_OPTIONS,
|
|
305
|
+
required: false
|
|
306
|
+
});
|
|
262
307
|
|
|
263
|
-
|
|
308
|
+
if (isCancel(selectedFeatures)) {
|
|
309
|
+
cancel('Operation cancelled');
|
|
310
|
+
process.exit(0);
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
// Use CLI flags
|
|
314
|
+
if (options.typescript || options.ts) selectedFeatures.push('typescript');
|
|
315
|
+
if (options.router) selectedFeatures.push('router');
|
|
316
|
+
if (options.pinia) selectedFeatures.push('pinia');
|
|
317
|
+
if (options.jsx) selectedFeatures.push('jsx');
|
|
318
|
+
|
|
319
|
+
// Default to vue if no framework specified
|
|
320
|
+
selectedFramework = 'vue';
|
|
321
|
+
}
|
|
264
322
|
|
|
265
|
-
|
|
323
|
+
// Determine features
|
|
324
|
+
const needsTypeScript = selectedFeatures.includes('typescript');
|
|
325
|
+
const needsRouter = selectedFeatures.includes('router');
|
|
326
|
+
const needsPinia = selectedFeatures.includes('pinia');
|
|
327
|
+
const needsJsx = selectedFeatures.includes('jsx');
|
|
328
|
+
|
|
329
|
+
// Create project directory
|
|
330
|
+
const root = path.join(cwd, targetDir);
|
|
331
|
+
if (fs.existsSync(root)) {
|
|
332
|
+
emptyDir(root);
|
|
333
|
+
} else {
|
|
334
|
+
fs.mkdirSync(root, { recursive: true });
|
|
335
|
+
}
|
|
266
336
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
- 🔥 **Hot Reload** - Fast development
|
|
270
|
-
- 📦 **Optimized** - Production-ready builds
|
|
337
|
+
// Change to project directory
|
|
338
|
+
process.chdir(root);
|
|
271
339
|
|
|
272
|
-
|
|
340
|
+
// Scaffolding
|
|
341
|
+
const s = spinner();
|
|
342
|
+
s.start('Fetching official Vite template...');
|
|
273
343
|
|
|
274
|
-
|
|
275
|
-
|
|
344
|
+
try {
|
|
345
|
+
// Use template fetcher to get official Vite templates
|
|
346
|
+
await getViteTemplate(selectedFramework, {
|
|
347
|
+
typescript: needsTypeScript,
|
|
348
|
+
router: needsRouter,
|
|
349
|
+
pinia: needsPinia,
|
|
350
|
+
jsx: needsJsx
|
|
351
|
+
}, packageName);
|
|
352
|
+
|
|
353
|
+
s.stop('Template fetched and scaffolded!');
|
|
354
|
+
} catch (error) {
|
|
355
|
+
s.stop('Failed to fetch template');
|
|
356
|
+
console.error(red('Error:'), error.message);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
276
359
|
|
|
277
|
-
|
|
360
|
+
// Install dependencies
|
|
361
|
+
const install = await confirm({
|
|
362
|
+
message: 'Install dependencies now?',
|
|
363
|
+
initialValue: true
|
|
364
|
+
});
|
|
278
365
|
|
|
279
|
-
|
|
366
|
+
if (!isCancel(install) && install) {
|
|
367
|
+
const pm = getPackageManager();
|
|
368
|
+
const installSpinner = spinner();
|
|
369
|
+
installSpinner.start(`Installing with ${pm}...`);
|
|
280
370
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
} catch (error) {
|
|
293
|
-
spinner.fail(`Failed to create project: ${error.message}`);
|
|
294
|
-
return false;
|
|
371
|
+
try {
|
|
372
|
+
execSync(getCommand(pm, 'install'), {
|
|
373
|
+
cwd: root,
|
|
374
|
+
stdio: 'pipe',
|
|
375
|
+
encoding: 'utf-8'
|
|
376
|
+
});
|
|
377
|
+
installSpinner.stop('Dependencies installed!');
|
|
378
|
+
} catch (error) {
|
|
379
|
+
installSpinner.stop('Installation failed');
|
|
380
|
+
console.error(red('Error:'), error.message);
|
|
381
|
+
}
|
|
295
382
|
}
|
|
383
|
+
|
|
384
|
+
// Success message
|
|
385
|
+
outro(`${green('✔')} ${bold('Success!')} Created ${selectedFramework.toUpperCase()} project in ${targetDir}
|
|
386
|
+
|
|
387
|
+
${dim('Next steps:')}
|
|
388
|
+
${cyan('cd')} ${targetDir}
|
|
389
|
+
${cyan('npm run dev')} ${dim('# Start development server')}
|
|
390
|
+
|
|
391
|
+
${dim('Happy coding! 🚀')}`);
|
|
296
392
|
}
|
|
297
393
|
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
let filePath = req.url === '/' ? '/index.html' : req.url;
|
|
319
|
-
filePath = path.join(process.cwd(), filePath);
|
|
394
|
+
// CLI setup
|
|
395
|
+
program
|
|
396
|
+
.name('gotodev')
|
|
397
|
+
.description('⚡ Lightning-fast app creator for React, Vue, Svelte, and more')
|
|
398
|
+
.version(require('./package.json').version);
|
|
399
|
+
|
|
400
|
+
program
|
|
401
|
+
.command('create [directory]')
|
|
402
|
+
.description('Create a new project')
|
|
403
|
+
.option('--typescript, --ts', 'Add TypeScript support')
|
|
404
|
+
.option('--router', 'Add Vue Router (Vue only)')
|
|
405
|
+
.option('--pinia', 'Add Pinia (Vue only)')
|
|
406
|
+
.option('--jsx', 'Add JSX support')
|
|
407
|
+
.option('--force', 'Force overwrite existing directory')
|
|
408
|
+
.option('--template <name>', 'Download an official starter template (e.g. next, shadcn, tailwind)')
|
|
409
|
+
.action(async (directory, options) => {
|
|
410
|
+
// If template is specified, handle it directly
|
|
411
|
+
if (options.template) {
|
|
412
|
+
const targetDir = directory || 'my-app';
|
|
413
|
+
const root = path.resolve(process.cwd(), targetDir);
|
|
320
414
|
|
|
321
|
-
//
|
|
322
|
-
if (
|
|
323
|
-
|
|
415
|
+
// Check directory
|
|
416
|
+
if (fs.existsSync(root) && fs.readdirSync(root).length > 0 && !options.force) {
|
|
417
|
+
console.error(`${red('✖')} Directory ${targetDir} is not empty. Use --force to overwrite.`);
|
|
418
|
+
process.exit(1);
|
|
324
419
|
}
|
|
325
420
|
|
|
326
|
-
if (fs.existsSync(
|
|
327
|
-
|
|
328
|
-
const ext = path.extname(filePath);
|
|
329
|
-
|
|
330
|
-
const contentTypes = {
|
|
331
|
-
'.html': 'text/html',
|
|
332
|
-
'.js': 'application/javascript',
|
|
333
|
-
'.css': 'text/css',
|
|
334
|
-
'.json': 'application/json'
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
res.writeHead(200, {
|
|
338
|
-
'Content-Type': contentTypes[ext] || 'text/plain',
|
|
339
|
-
'Access-Control-Allow-Origin': '*'
|
|
340
|
-
});
|
|
341
|
-
res.end(content);
|
|
421
|
+
if (fs.existsSync(root)) {
|
|
422
|
+
await fs.emptyDir(root);
|
|
342
423
|
} else {
|
|
343
|
-
|
|
344
|
-
res.end('Not found');
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
server.listen(PORT, () => {
|
|
349
|
-
spinner.succeed(`Dev server running at http://localhost:${PORT}`);
|
|
350
|
-
console.log(`${chalk.yellow('Press Ctrl+C to stop')}`);
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
// Watch for changes
|
|
354
|
-
fs.watch(process.cwd(), { recursive: true }, (eventType, filename) => {
|
|
355
|
-
if (filename && (filename.endsWith('.ts') || filename.endsWith('.tsx'))) {
|
|
356
|
-
console.log(`${chalk.green('🔄 File changed:')} ${filename}`);
|
|
424
|
+
fs.mkdirSync(root, { recursive: true });
|
|
357
425
|
}
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
} catch (error) {
|
|
361
|
-
spinner.fail(`Failed to start server: ${error.message}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Helper: Build project
|
|
366
|
-
async function buildProject() {
|
|
367
|
-
const spinner = ora('Building project...').start();
|
|
368
|
-
|
|
369
|
-
try {
|
|
370
|
-
// Check if we're in a project
|
|
371
|
-
const packageJson = path.join(process.cwd(), 'package.json');
|
|
372
|
-
if (!fs.existsSync(packageJson)) {
|
|
373
|
-
spinner.fail('Not in a project directory');
|
|
374
|
-
process.exit(1);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Create dist directory
|
|
378
|
-
const distPath = path.join(process.cwd(), 'dist');
|
|
379
|
-
fs.mkdirSync(distPath, { recursive: true });
|
|
380
|
-
|
|
381
|
-
// Compile all TypeScript files
|
|
382
|
-
const srcPath = path.join(process.cwd(), 'src');
|
|
383
|
-
if (fs.existsSync(srcPath)) {
|
|
384
|
-
const files = fs.readdirSync(srcPath, { recursive: true });
|
|
385
426
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
427
|
+
// Download and copy template
|
|
428
|
+
const tmpDir = await downloadTemplate(options.template);
|
|
429
|
+
const copyDir = async (src, dest) => {
|
|
430
|
+
await fs.ensureDir(dest);
|
|
431
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
432
|
+
|
|
433
|
+
for (const entry of entries) {
|
|
434
|
+
const srcPath = path.join(src, entry.name);
|
|
435
|
+
const destPath = path.join(dest, entry.name);
|
|
391
436
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
437
|
+
if (entry.isDirectory()) {
|
|
438
|
+
await copyDir(srcPath, destPath);
|
|
439
|
+
} else {
|
|
440
|
+
await fs.copyFile(srcPath, destPath);
|
|
441
|
+
}
|
|
396
442
|
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
await copyDir(tmpDir, root);
|
|
446
|
+
|
|
447
|
+
// Install dependencies
|
|
448
|
+
const pm = getPackageManager();
|
|
449
|
+
const installSpinner = spinner();
|
|
450
|
+
installSpinner.start(`Installing with ${pm}...`);
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
execSync(getCommand(pm, 'install'), {
|
|
454
|
+
cwd: root,
|
|
455
|
+
stdio: 'pipe',
|
|
456
|
+
encoding: 'utf-8'
|
|
457
|
+
});
|
|
458
|
+
installSpinner.stop('Dependencies installed!');
|
|
459
|
+
} catch (error) {
|
|
460
|
+
installSpinner.stop('Installation failed');
|
|
461
|
+
console.error(red('Error:'), error.message);
|
|
397
462
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const htmlPath = path.join(process.cwd(), 'index.html');
|
|
402
|
-
if (fs.existsSync(htmlPath)) {
|
|
403
|
-
fs.copySync(htmlPath, path.join(distPath, 'index.html'));
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
spinner.succeed('✅ Build complete!');
|
|
407
|
-
console.log(`\n�� Output: ${chalk.cyan('dist/')}`);
|
|
408
|
-
console.log(`🚀 To serve: ${chalk.yellow('cd dist && python3 -m http.server 8000')}`);
|
|
409
|
-
|
|
410
|
-
} catch (error) {
|
|
411
|
-
spinner.fail(`Build failed: ${error.message}`);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
463
|
+
|
|
464
|
+
// Success message
|
|
465
|
+
outro(`${green('✔')} ${bold('Success!')} Created project from ${options.template} template in ${targetDir}
|
|
414
466
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
.description('⚡ Lightning-fast app creator for React, Vue, and more')
|
|
419
|
-
.version('0.1.0');
|
|
467
|
+
${dim('Next steps:')}
|
|
468
|
+
${cyan('cd')} ${targetDir}
|
|
469
|
+
${cyan('npm run dev')} ${dim('# Start development server')}
|
|
420
470
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
.description('Create a new app')
|
|
424
|
-
.option('-f, --framework <framework>', 'Framework to use', 'react')
|
|
425
|
-
.action(async (appName, options) => {
|
|
426
|
-
const frameworks = Object.keys(FRAMEWORKS);
|
|
427
|
-
|
|
428
|
-
if (!frameworks.includes(options.framework)) {
|
|
429
|
-
console.log(`${chalk.red('Error:')} Invalid framework "${options.framework}"`);
|
|
430
|
-
console.log(`Available: ${frameworks.join(', ')}`);
|
|
431
|
-
process.exit(1);
|
|
471
|
+
${dim('Happy coding! 🚀')}`);
|
|
472
|
+
return;
|
|
432
473
|
}
|
|
433
474
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
program
|
|
448
|
-
.command('list')
|
|
449
|
-
.description('List available frameworks')
|
|
450
|
-
.action(() => {
|
|
451
|
-
console.log('\nAvailable frameworks:');
|
|
452
|
-
Object.entries(FRAMEWORKS).forEach(([key, value]) => {
|
|
453
|
-
console.log(` ${chalk.cyan(key.padEnd(10))} - ${value.description}`);
|
|
454
|
-
});
|
|
455
|
-
console.log('');
|
|
475
|
+
// Otherwise, use the original init flow
|
|
476
|
+
const args = [];
|
|
477
|
+
if (directory) args.push(directory);
|
|
478
|
+
if (options.typescript) args.push('--typescript');
|
|
479
|
+
if (options.router) args.push('--router');
|
|
480
|
+
if (options.pinia) args.push('--pinia');
|
|
481
|
+
if (options.jsx) args.push('--jsx');
|
|
482
|
+
if (options.force) args.push('--force');
|
|
483
|
+
|
|
484
|
+
// Set process.argv for init to parse
|
|
485
|
+
process.argv = [process.argv[0], process.argv[1], ...args];
|
|
486
|
+
|
|
487
|
+
await init();
|
|
456
488
|
});
|
|
457
489
|
|
|
458
|
-
|
|
490
|
+
// Handle direct execution
|
|
491
|
+
if (process.argv.length < 3) {
|
|
492
|
+
// No command, run interactive
|
|
493
|
+
init().catch(console.error);
|
|
494
|
+
} else {
|
|
495
|
+
program.parse(process.argv);
|
|
496
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gotodev",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "⚡ Lightning-fast app creator for React, Vue, Svelte, and all modern frameworks. Built with Rust 1.92 + Oxc 0.106 for instant compilation - 10-100x faster than Vite/Vitest.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -40,16 +40,28 @@
|
|
|
40
40
|
},
|
|
41
41
|
"homepage": "https://github.com/gotodev-manager/gotodev-installer#readme",
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@clack/prompts": "^0.11.0",
|
|
44
|
+
"axios": "^1.13.2",
|
|
43
45
|
"chalk": "^5.6.2",
|
|
44
46
|
"commander": "^14.0.2",
|
|
47
|
+
"ejs": "^3.1.10",
|
|
45
48
|
"execa": "^9.6.1",
|
|
49
|
+
"fast-glob": "^3.3.0",
|
|
46
50
|
"fs-extra": "^11.3.3",
|
|
51
|
+
"github-repo": "^2.0.0",
|
|
47
52
|
"inquirer": "^13.1.0",
|
|
48
|
-
"ora": "^9.0.0"
|
|
53
|
+
"ora": "^9.0.0",
|
|
54
|
+
"picocolors": "^1.1.1",
|
|
55
|
+
"rimraf": "^5.0.0",
|
|
56
|
+
"yargs": "^17.7.0"
|
|
49
57
|
},
|
|
50
58
|
"devDependencies": {
|
|
51
59
|
"@napi-rs/cli": "^3.5.1",
|
|
52
|
-
"
|
|
60
|
+
"fast-glob": "^3.3.3",
|
|
61
|
+
"github-repo": "^0.0.3",
|
|
62
|
+
"rimraf": "^6.1.2",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"yargs": "^18.0.0"
|
|
53
65
|
},
|
|
54
66
|
"engines": {
|
|
55
67
|
"node": ">=24.0.0"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Install dependencies
|
|
7
|
+
npm install
|
|
8
|
+
|
|
9
|
+
# Start development server
|
|
10
|
+
npm run dev
|
|
11
|
+
|
|
12
|
+
# Build for production
|
|
13
|
+
npm run build
|
|
14
|
+
|
|
15
|
+
# Preview production build
|
|
16
|
+
npm run preview
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
This project was created with gotodev - a lightning-fast app creator powered by Rust + Oxc.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>{{projectName}}</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.js"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<h1>{{ title }}</h1>
|
|
4
|
+
<button @click="count++">Count: {{ count }}</button>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
const title = ref('Hello from gotodev!')
|
|
12
|
+
const count = ref(0)
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<style>
|
|
16
|
+
#app {
|
|
17
|
+
font-family: sans-serif;
|
|
18
|
+
text-align: center;
|
|
19
|
+
padding: 2rem;
|
|
20
|
+
}
|
|
21
|
+
button {
|
|
22
|
+
padding: 0.5rem 1rem;
|
|
23
|
+
font-size: 1rem;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<h1>{{ title }}</h1>
|
|
4
|
+
<button @click="increment">Count: {{ count }}</button>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
const title = ref<string>('Hello from gotodev with TypeScript!')
|
|
12
|
+
const count = ref<number>(0)
|
|
13
|
+
|
|
14
|
+
const increment = (): void => {
|
|
15
|
+
count.value++
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<style>
|
|
20
|
+
#app {
|
|
21
|
+
font-family: sans-serif;
|
|
22
|
+
text-align: center;
|
|
23
|
+
padding: 2rem;
|
|
24
|
+
}
|
|
25
|
+
button {
|
|
26
|
+
padding: 0.5rem 1rem;
|
|
27
|
+
font-size: 1rem;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<nav>
|
|
4
|
+
<router-link to="/">Home</router-link>
|
|
5
|
+
</nav>
|
|
6
|
+
<router-view />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
#app {
|
|
12
|
+
font-family: sans-serif;
|
|
13
|
+
padding: 2rem;
|
|
14
|
+
}
|
|
15
|
+
nav {
|
|
16
|
+
margin-bottom: 2rem;
|
|
17
|
+
}
|
|
18
|
+
nav a {
|
|
19
|
+
margin-right: 1rem;
|
|
20
|
+
text-decoration: none;
|
|
21
|
+
color: #2c3e50;
|
|
22
|
+
font-weight: bold;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
|
+
import HomeView from '../views/HomeView.vue'
|
|
3
|
+
|
|
4
|
+
const routes = [
|
|
5
|
+
{
|
|
6
|
+
path: '/',
|
|
7
|
+
name: 'home',
|
|
8
|
+
component: HomeView
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
const router = createRouter({
|
|
13
|
+
history: createWebHistory(),
|
|
14
|
+
routes
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export default router
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "preserve",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
|
20
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
21
|
+
}
|