create-lve 0.2.4 → 0.2.6
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/index.js +272 -116
- package/package.json +23 -4
- package/template-react/.vscode/extensions.json +1 -1
- package/template-react/.vscode/settings.json +70 -2
- package/template-react/package.json +3 -4
- package/template-react/src/App.tsx +29 -12
- package/template-react/vite.config.ts +8 -9
- package/template-vue/package.json +1 -1
- package/template-vue/vite.config.ts +4 -1
package/index.js
CHANGED
|
@@ -1,166 +1,322 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import * as p from
|
|
4
|
-
import pc from
|
|
5
|
-
import fs from
|
|
6
|
-
import path from
|
|
7
|
-
import { fileURLToPath } from
|
|
3
|
+
import * as p from '@clack/prompts'
|
|
4
|
+
import pc from 'picocolors'
|
|
5
|
+
import fs from 'fs-extra'
|
|
6
|
+
import path from 'node:path'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
8
|
+
import { execSync, spawn } from 'node:child_process'
|
|
8
9
|
|
|
9
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
|
|
12
|
+
const getReactAppTemplate = (isUno) => {
|
|
13
|
+
const logoClass = isUno
|
|
14
|
+
? 'animate-spin animate-duration-20s animate-linear animate-infinite'
|
|
15
|
+
: 'animate-[spin_20s_linear_infinite]'
|
|
16
|
+
|
|
17
|
+
return `
|
|
18
|
+
import { useState } from 'react'
|
|
19
|
+
import reactLogo from './assets/react.svg'
|
|
20
|
+
|
|
21
|
+
export function App() {
|
|
22
|
+
const [count, setCount] = useState(0)
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="max-w-7xl mx-auto p-8 text-center font-sans antialiased text-[#213547] dark:text-zinc-200 min-h-dvh flex flex-col justify-center items-center">
|
|
26
|
+
<div className="flex justify-center gap-12 mb-12">
|
|
27
|
+
<a
|
|
28
|
+
href="https://viteplus.dev"
|
|
29
|
+
target="_blank"
|
|
30
|
+
rel="noreferrer"
|
|
31
|
+
className="transition-all duration-300 hover:drop-shadow-[0_0_2em_#646cffaa]"
|
|
32
|
+
>
|
|
33
|
+
<img src="/favicon.svg" className="h-24 p-6" alt="VitePlus logo" />
|
|
34
|
+
</a>
|
|
35
|
+
<a
|
|
36
|
+
href="https://react.dev"
|
|
37
|
+
target="_blank"
|
|
38
|
+
rel="noreferrer"
|
|
39
|
+
className="transition-all duration-300 hover:drop-shadow-[0_0_2em_#61dafbaa]"
|
|
40
|
+
>
|
|
41
|
+
<img
|
|
42
|
+
src={reactLogo}
|
|
43
|
+
className="h-24 p-6 ${logoClass}"
|
|
44
|
+
alt="React logo"
|
|
45
|
+
/>
|
|
46
|
+
</a>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<h1 className="text-5xl font-bold leading-[1.1] mb-8">VitePlus + React</h1>
|
|
50
|
+
|
|
51
|
+
<div className="p-8 space-y-4 flex flex-col items-center">
|
|
52
|
+
<button
|
|
53
|
+
onClick={() => setCount((count) => count + 1)}
|
|
54
|
+
className="rounded-lg border border-transparent px-5 py-2.5 text-base font-medium bg-[#f9f9f9] dark:bg-zinc-800 cursor-pointer transition-colors hover:border-[#646cff] outline-none"
|
|
55
|
+
>
|
|
56
|
+
count is {count}
|
|
57
|
+
</button>
|
|
58
|
+
<p className="text-zinc-500">
|
|
59
|
+
Edit{' '}
|
|
60
|
+
<code className="bg-[#f1f1f1] dark:bg-zinc-800 px-1.5 py-0.5 rounded font-mono">
|
|
61
|
+
src/App.tsx
|
|
62
|
+
</code>{' '}
|
|
63
|
+
to test HMR
|
|
64
|
+
</p>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<p className="text-[#888] mt-8">
|
|
68
|
+
Check out{' '}
|
|
69
|
+
<a
|
|
70
|
+
href="https://github.com/voidzero-dev/vite-plus"
|
|
71
|
+
target="_blank"
|
|
72
|
+
rel="noreferrer"
|
|
73
|
+
className="font-medium text-[#646cff] hover:text-[#535bf2]"
|
|
74
|
+
>
|
|
75
|
+
VitePlus
|
|
76
|
+
</a>
|
|
77
|
+
, the unified toolchain for the web.
|
|
78
|
+
</p>
|
|
79
|
+
|
|
80
|
+
<p className="text-[#888] mt-4 text-sm">
|
|
81
|
+
Click on the VitePlus and React logos to learn more
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
`.trim()
|
|
87
|
+
}
|
|
10
88
|
|
|
11
89
|
async function main() {
|
|
12
|
-
console.clear()
|
|
90
|
+
console.clear()
|
|
13
91
|
const logo = `
|
|
14
|
-
${pc.cyan(
|
|
15
|
-
${pc.cyan(
|
|
16
|
-
${pc.cyan(
|
|
17
|
-
|
|
92
|
+
${pc.cyan('█ █ █ █▀▀▀')}
|
|
93
|
+
${pc.cyan('█ █ █ █▀▀ ')}
|
|
94
|
+
${pc.cyan('█▄▄▄ ▀▄▀ █▄▄▄')} ${pc.gray('THE ULTRA-FAST FRONTEND STACK')}
|
|
95
|
+
`
|
|
18
96
|
|
|
19
|
-
console.log(logo)
|
|
20
|
-
p.intro(`${pc.bgCyan(pc.black(
|
|
97
|
+
console.log(logo)
|
|
98
|
+
p.intro(`${pc.bgCyan(pc.black(' LVE-CLI '))}`)
|
|
21
99
|
|
|
22
100
|
const project = await p.group(
|
|
23
101
|
{
|
|
24
|
-
path: () =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
102
|
+
path: () =>
|
|
103
|
+
p.text({
|
|
104
|
+
message: '项目名称',
|
|
105
|
+
placeholder: 'react-app',
|
|
106
|
+
defaultValue: 'react-app',
|
|
107
|
+
validate: (value) => {
|
|
108
|
+
if (!value || value.length === 0) return
|
|
109
|
+
if (value.match(/[<>:"|?*]/)) return '路径包含非法字符'
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
33
112
|
shouldOverwrite: ({ results }) => {
|
|
34
|
-
const targetDir = path.resolve(process.cwd(), results.path)
|
|
113
|
+
const targetDir = path.resolve(process.cwd(), results.path)
|
|
35
114
|
if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
|
|
36
|
-
return p.confirm({ message: `目录已存在,是否清空?`, initialValue: false })
|
|
115
|
+
return p.confirm({ message: `目录已存在,是否清空?`, initialValue: false })
|
|
37
116
|
}
|
|
38
117
|
},
|
|
39
|
-
framework: () =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
118
|
+
framework: () =>
|
|
119
|
+
p.select({
|
|
120
|
+
message: '选择框架',
|
|
121
|
+
options: [
|
|
122
|
+
{ value: 'react', label: 'React 19', hint: 'VitePlus + Compiler' },
|
|
123
|
+
{ value: 'vue', label: 'Vue 3', hint: 'VitePlus + Optimized' },
|
|
124
|
+
],
|
|
125
|
+
}),
|
|
126
|
+
cssEngine: () =>
|
|
127
|
+
p.select({
|
|
128
|
+
message: '选择 CSS 引擎',
|
|
129
|
+
options: [
|
|
130
|
+
{
|
|
131
|
+
value: 'unocss',
|
|
132
|
+
label: 'UnoCSS',
|
|
133
|
+
hint: '⚡️ 战机级性能:动态代码注入,实现源码级‘无感’混淆',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
value: 'tailwind',
|
|
137
|
+
label: 'Tailwind v4',
|
|
138
|
+
hint: '🛡️ 装甲级稳定:v4 引擎重构,完美适配所有主流 UI 库',
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
}),
|
|
142
|
+
install: () =>
|
|
143
|
+
p.confirm({
|
|
144
|
+
message: '是否现在自动安装依赖?',
|
|
145
|
+
initialValue: true,
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
onCancel: () => {
|
|
150
|
+
p.cancel('操作取消')
|
|
151
|
+
process.exit(0)
|
|
152
|
+
},
|
|
53
153
|
},
|
|
54
|
-
|
|
55
|
-
);
|
|
154
|
+
)
|
|
56
155
|
|
|
57
|
-
|
|
58
|
-
const templateDir = path.resolve(__dirname, `template-${project.framework}`);
|
|
59
|
-
const isUno = project.cssEngine === "unocss";
|
|
60
|
-
const s = p.spinner();
|
|
156
|
+
if (!project) process.exit(0)
|
|
61
157
|
|
|
62
|
-
|
|
158
|
+
const targetDir = path.resolve(process.cwd(), project.path)
|
|
159
|
+
const templateDir = path.resolve(__dirname, `template-${project.framework}`)
|
|
160
|
+
const isUno = project.cssEngine === 'unocss'
|
|
161
|
+
const s = p.spinner()
|
|
63
162
|
|
|
64
163
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
164
|
+
execSync('vp --version', { stdio: 'ignore' })
|
|
165
|
+
} catch {
|
|
166
|
+
p.log.error(pc.red('未检测到 VitePlus (vp) 环境'))
|
|
167
|
+
p.note(
|
|
168
|
+
pc.white(
|
|
169
|
+
`请先安装 vp 工具链:\n${pc.cyan('npm install -g @voidzero-dev/vite-plus')}\n\n详情请参考: ${pc.underline('https://viteplus.dev/guide/')}`,
|
|
170
|
+
),
|
|
171
|
+
'环境缺失',
|
|
172
|
+
)
|
|
173
|
+
process.exit(1)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
s.start('🛠️ 正在按需装配架构...')
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
if (project.shouldOverwrite) await fs.emptyDir(targetDir)
|
|
180
|
+
else await fs.ensureDir(targetDir)
|
|
181
|
+
|
|
182
|
+
await fs.copy(templateDir, targetDir)
|
|
67
183
|
|
|
68
|
-
|
|
184
|
+
try {
|
|
185
|
+
execSync('git init', { cwd: targetDir, stdio: 'ignore' })
|
|
186
|
+
} catch {}
|
|
69
187
|
|
|
70
|
-
const oldGit = path.join(targetDir,
|
|
71
|
-
if (fs.existsSync(oldGit)) await fs.move(oldGit, path.join(targetDir,
|
|
188
|
+
const oldGit = path.join(targetDir, '_gitignore')
|
|
189
|
+
if (fs.existsSync(oldGit)) await fs.move(oldGit, path.join(targetDir, '.gitignore'))
|
|
72
190
|
|
|
73
|
-
const pkgPath = path.join(targetDir,
|
|
74
|
-
const pkg = await fs.readJson(pkgPath)
|
|
75
|
-
pkg.name = path.basename(targetDir)
|
|
191
|
+
const pkgPath = path.join(targetDir, 'package.json')
|
|
192
|
+
const pkg = await fs.readJson(pkgPath)
|
|
193
|
+
pkg.name = path.basename(targetDir)
|
|
76
194
|
|
|
77
195
|
if (isUno) {
|
|
78
|
-
pkg.devDependencies[
|
|
196
|
+
pkg.devDependencies['unocss'] = 'latest'
|
|
79
197
|
} else {
|
|
80
|
-
pkg.devDependencies[
|
|
81
|
-
pkg.devDependencies[
|
|
198
|
+
pkg.devDependencies['tailwindcss'] = 'latest'
|
|
199
|
+
pkg.devDependencies['@tailwindcss/vite'] = 'latest'
|
|
82
200
|
}
|
|
83
201
|
|
|
84
202
|
pkg.pnpm = {
|
|
85
203
|
...pkg.pnpm,
|
|
86
204
|
overrides: {
|
|
87
205
|
...pkg.pnpm?.overrides,
|
|
88
|
-
vite:
|
|
89
|
-
vitest:
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 })
|
|
206
|
+
vite: 'npm:@voidzero-dev/vite-plus-core@latest',
|
|
207
|
+
vitest: 'npm:@voidzero-dev/vite-plus-test@latest',
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 })
|
|
211
|
+
|
|
212
|
+
const mainFile = project.framework === 'vue' ? 'src/main.ts' : 'src/main.tsx'
|
|
213
|
+
const mainPath = path.join(targetDir, mainFile)
|
|
214
|
+
const viteConfigPath = path.join(targetDir, 'vite.config.ts')
|
|
215
|
+
const stylePath = path.join(targetDir, 'src/style.css')
|
|
93
216
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
217
|
+
let mainContent = await fs.readFile(mainPath, 'utf-8')
|
|
218
|
+
let viteContent = await fs.readFile(viteConfigPath, 'utf-8')
|
|
219
|
+
|
|
220
|
+
const appFile = project.framework === 'vue' ? 'src/App.vue' : 'src/App.tsx'
|
|
221
|
+
const appPath = path.join(targetDir, appFile)
|
|
222
|
+
|
|
223
|
+
if (project.framework === 'react') {
|
|
224
|
+
await fs.writeFile(appPath, getReactAppTemplate(isUno))
|
|
225
|
+
}
|
|
98
226
|
|
|
99
|
-
|
|
100
|
-
|
|
227
|
+
const pluginCode = isUno ? 'UnoCSS()' : 'tailwindcss()'
|
|
228
|
+
const pluginImport = isUno
|
|
229
|
+
? "import UnoCSS from 'unocss/vite'\n"
|
|
230
|
+
: "import tailwindcss from '@tailwindcss/vite'\n"
|
|
231
|
+
|
|
232
|
+
viteContent = pluginImport + viteContent
|
|
233
|
+
viteContent = viteContent.replace('/* VITE_PLUS_PLUGINS */', `${pluginCode}, `)
|
|
101
234
|
|
|
102
235
|
if (isUno) {
|
|
103
236
|
const unoConfig = `import { defineConfig, presetWind3, transformerCompileClass } from 'unocss'
|
|
104
237
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
238
|
+
export default defineConfig({
|
|
239
|
+
presets: [presetWind3()],
|
|
240
|
+
transformers: [
|
|
241
|
+
{
|
|
242
|
+
name: 'auto-uno-injector',
|
|
243
|
+
enforce: 'pre',
|
|
244
|
+
idFilter(id) { return /\\.[tj]sx$|\\.vue$/.test(id) },
|
|
245
|
+
async transform(code) {
|
|
246
|
+
const classRegex = /(?:class|className)=["']([^"']+)["']/g
|
|
247
|
+
let match
|
|
248
|
+
while ((match = classRegex.exec(code.original))) {
|
|
249
|
+
const content = match[1]
|
|
250
|
+
if (content.trim() && !content.includes(':uno:')) {
|
|
251
|
+
const insertPos = match.index + match[0].indexOf(content)
|
|
252
|
+
code.appendLeft(insertPos, ':uno: ')
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
transformerCompileClass({
|
|
258
|
+
classPrefix: 'kfc-',
|
|
259
|
+
}),
|
|
260
|
+
],
|
|
261
|
+
})\n`
|
|
262
|
+
await fs.writeFile(path.join(targetDir, 'uno.config.ts'), unoConfig)
|
|
263
|
+
|
|
264
|
+
mainContent = `import 'virtual:uno.css'\n` + mainContent
|
|
265
|
+
if (fs.existsSync(stylePath)) await fs.remove(stylePath)
|
|
266
|
+
} else {
|
|
267
|
+
await fs.writeFile(stylePath, `@import "tailwindcss";`)
|
|
268
|
+
mainContent = `import './style.css'\n` + mainContent
|
|
269
|
+
}
|
|
132
270
|
|
|
133
|
-
|
|
271
|
+
await fs.writeFile(mainPath, mainContent)
|
|
272
|
+
await fs.writeFile(viteConfigPath, viteContent)
|
|
134
273
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
viteContent = viteContent.replace(/plugins:\s*\[/, "plugins: [UnoCSS(), ");
|
|
274
|
+
const toRemove = ['pnpm-lock.yaml', 'node_modules', 'dist']
|
|
275
|
+
await Promise.all(toRemove.map((file) => fs.remove(path.join(targetDir, file))))
|
|
138
276
|
|
|
139
|
-
|
|
140
|
-
} else {
|
|
141
|
-
await fs.writeFile(stylePath, `@import "tailwindcss";`);
|
|
277
|
+
s.message(pc.green('架构装配完成,正在执行 vp install'))
|
|
142
278
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
279
|
+
try {
|
|
280
|
+
await new Promise((resolve, reject) => {
|
|
281
|
+
const child = spawn('vp', ['install'], {
|
|
282
|
+
cwd: targetDir,
|
|
283
|
+
stdio: 'pipe',
|
|
284
|
+
shell: process.platform === 'win32',
|
|
285
|
+
})
|
|
147
286
|
|
|
148
|
-
|
|
149
|
-
|
|
287
|
+
child.on('close', (code) => {
|
|
288
|
+
if (code === 0) resolve()
|
|
289
|
+
else reject(new Error(`Exit code: ${code}`))
|
|
290
|
+
})
|
|
291
|
+
})
|
|
150
292
|
|
|
151
|
-
|
|
152
|
-
|
|
293
|
+
s.message(pc.green('正在执行 vp fmt 优化代码结构'))
|
|
294
|
+
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
153
295
|
|
|
154
|
-
|
|
296
|
+
try {
|
|
297
|
+
execSync('vp fmt', { cwd: targetDir, stdio: 'ignore' })
|
|
298
|
+
} catch {}
|
|
299
|
+
|
|
300
|
+
s.stop(pc.green('全套环境装配就绪'))
|
|
301
|
+
} catch {
|
|
302
|
+
s.stop(pc.red('自动安装失败'))
|
|
303
|
+
p.log.warn('请进入目录后手动尝试执行 vp install')
|
|
304
|
+
}
|
|
155
305
|
|
|
156
|
-
|
|
157
|
-
|
|
306
|
+
const nextSteps = project.install
|
|
307
|
+
? `cd ${project.path}\nvp dev`
|
|
308
|
+
: `cd ${project.path}\nvp install\nvp dev`
|
|
158
309
|
|
|
310
|
+
p.note(pc.cyan(nextSteps), '快速开始')
|
|
311
|
+
p.outro(
|
|
312
|
+
`${pc.magenta('✨ 已经为你准备好了极致的开发环境!')}\n` +
|
|
313
|
+
`${pc.gray(`==== ${project.framework} + ${project.cssEngine} ====`)}`,
|
|
314
|
+
)
|
|
159
315
|
} catch (err) {
|
|
160
|
-
s.stop(pc.red(
|
|
161
|
-
console.error(err)
|
|
162
|
-
process.exit(1)
|
|
316
|
+
s.stop(pc.red('手术失败'))
|
|
317
|
+
console.error(err)
|
|
318
|
+
process.exit(1)
|
|
163
319
|
}
|
|
164
320
|
}
|
|
165
321
|
|
|
166
|
-
main()
|
|
322
|
+
main()
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-lve",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "0.2.6",
|
|
5
4
|
"bin": {
|
|
6
5
|
"create-lve": "index.js"
|
|
7
6
|
},
|
|
@@ -10,9 +9,29 @@
|
|
|
10
9
|
"template-react",
|
|
11
10
|
"template-vue"
|
|
12
11
|
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"fmt": "oxfmt",
|
|
15
|
+
"fmt:check": "oxfmt --check",
|
|
16
|
+
"lint": "oxlint",
|
|
17
|
+
"lint:fix": "oxlint --fix"
|
|
18
|
+
},
|
|
13
19
|
"dependencies": {
|
|
14
20
|
"@clack/prompts": "^1.1.0",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
21
|
+
"fs-extra": "^11.2.0",
|
|
22
|
+
"picocolors": "^1.1.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"husky": "^9.1.7",
|
|
26
|
+
"lint-staged": "^16.4.0",
|
|
27
|
+
"oxfmt": "^0.46.0",
|
|
28
|
+
"oxlint": "^1.61.0"
|
|
29
|
+
},
|
|
30
|
+
"lint-staged": {
|
|
31
|
+
"*.{js,jsx,ts,tsx,mjs,cjs}": [
|
|
32
|
+
"oxfmt --write",
|
|
33
|
+
"oxlint --fix"
|
|
34
|
+
],
|
|
35
|
+
"*.json": "oxfmt --write"
|
|
17
36
|
}
|
|
18
37
|
}
|
|
@@ -1,8 +1,76 @@
|
|
|
1
1
|
{
|
|
2
|
+
// ==================== Formatter (OXC) ====================
|
|
2
3
|
"editor.defaultFormatter": "oxc.oxc-vscode",
|
|
3
4
|
"editor.formatOnSave": true,
|
|
4
5
|
"editor.formatOnSaveMode": "file",
|
|
6
|
+
"oxc.enable.oxfmt": true,
|
|
7
|
+
|
|
8
|
+
// 语言特定 Formatter
|
|
9
|
+
"[javascript]": {
|
|
10
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
11
|
+
},
|
|
12
|
+
"[typescript]": {
|
|
13
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
14
|
+
},
|
|
15
|
+
"[typescriptreact]": {
|
|
16
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
17
|
+
},
|
|
18
|
+
"[javascriptreact]": {
|
|
19
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
20
|
+
},
|
|
21
|
+
"[css]": {
|
|
22
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
23
|
+
},
|
|
24
|
+
"[tailwindcss]": {
|
|
25
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
26
|
+
},
|
|
27
|
+
"[json]": {
|
|
28
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
29
|
+
},
|
|
30
|
+
"[jsonc]": {
|
|
31
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
32
|
+
},
|
|
33
|
+
"[html]": {
|
|
34
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
35
|
+
},
|
|
36
|
+
"[vue]": {
|
|
37
|
+
"editor.defaultFormatter": "oxc.oxc-vscode"
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// ==================== Next.js 专用 ====================
|
|
41
|
+
"workbench.editor.customLabels.patterns": {
|
|
42
|
+
"**/app/**/layout.{js,jsx,ts,tsx}": "${dirname}/layout",
|
|
43
|
+
"**/app/**/page.{js,jsx,ts,tsx}": "${dirname}/page",
|
|
44
|
+
"**/app/**/route.{js,jsx,ts,tsx}": "${dirname}/route",
|
|
45
|
+
"**/app/**/loading.{js,jsx,ts,tsx}": "${dirname}/loading",
|
|
46
|
+
"**/app/**/template.{js,jsx,ts,tsx}": "${dirname}/template",
|
|
47
|
+
"**/app/**/default.{js,jsx,ts,tsx}": "${dirname}/default",
|
|
48
|
+
"**/app/**/error.{js,jsx,ts,tsx}": "${dirname}/error",
|
|
49
|
+
"**/app/**/not-found.{js,jsx,ts,tsx}": "${dirname}/not-found"
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// ==================== TypeScript(解决 Next.js TS 问题)===================
|
|
53
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
54
|
+
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
55
|
+
|
|
56
|
+
// ==================== Tailwind + shadcn/ui(强烈推荐)===================
|
|
57
|
+
"tailwindCSS.experimental.classRegex": [["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]],
|
|
58
|
+
"tailwindCSS.includeLanguages": {
|
|
59
|
+
"typescript": "html",
|
|
60
|
+
"typescriptreact": "html"
|
|
61
|
+
},
|
|
62
|
+
"editor.quickSuggestions": {
|
|
63
|
+
"strings": "on"
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// ==================== 其他项目通用 ====================
|
|
67
|
+
"git.openRepositoryInParentFolders": "always",
|
|
68
|
+
"js/ts.updateImportsOnFileMove.enabled": "always",
|
|
69
|
+
"diffEditor.ignoreTrimWhitespace": true,
|
|
70
|
+
"diffEditor.hideUnchangedRegions.enabled": true,
|
|
71
|
+
|
|
5
72
|
"editor.codeActionsOnSave": {
|
|
6
|
-
"source.
|
|
7
|
-
}
|
|
73
|
+
"source.format.oxc": "always"
|
|
74
|
+
},
|
|
75
|
+
"editor.inlayHints.enabled": "on"
|
|
8
76
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "react-
|
|
2
|
+
"name": "react-app",
|
|
3
3
|
"version": "0.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "vp dev",
|
|
8
8
|
"build": "tsc -b && vp build",
|
|
9
|
-
"lint": "eslint .",
|
|
10
9
|
"preview": "vp preview",
|
|
11
10
|
"prepare": "vp config"
|
|
12
11
|
},
|
|
@@ -24,8 +23,8 @@
|
|
|
24
23
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
|
25
24
|
"vite-plus": "latest"
|
|
26
25
|
},
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
"packageManager": "pnpm@10.32.1",
|
|
27
|
+
"pnpm": {
|
|
29
28
|
"overrides": {
|
|
30
29
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
|
31
30
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
@@ -7,45 +7,62 @@ export function App() {
|
|
|
7
7
|
return (
|
|
8
8
|
<div className="max-w-7xl mx-auto p-8 text-center font-sans antialiased text-[#213547] dark:text-zinc-200 min-h-dvh flex flex-col justify-center items-center">
|
|
9
9
|
<div className="flex justify-center gap-12 mb-12">
|
|
10
|
-
<a
|
|
11
|
-
href="https://viteplus.dev"
|
|
12
|
-
target="_blank"
|
|
10
|
+
<a
|
|
11
|
+
href="https://viteplus.dev"
|
|
12
|
+
target="_blank"
|
|
13
13
|
rel="noreferrer"
|
|
14
14
|
className="transition-all duration-300 hover:drop-shadow-[0_0_2em_#646cffaa]"
|
|
15
15
|
>
|
|
16
16
|
<img src="/favicon.svg" className="h-24 p-6" alt="VitePlus logo" />
|
|
17
17
|
</a>
|
|
18
|
-
<a
|
|
19
|
-
href="https://react.dev"
|
|
20
|
-
target="_blank"
|
|
18
|
+
<a
|
|
19
|
+
href="https://react.dev"
|
|
20
|
+
target="_blank"
|
|
21
21
|
rel="noreferrer"
|
|
22
22
|
className="transition-all duration-300 hover:drop-shadow-[0_0_2em_#61dafbaa]"
|
|
23
23
|
>
|
|
24
|
-
<img
|
|
24
|
+
<img
|
|
25
|
+
src={reactLogo}
|
|
26
|
+
className="h-24 p-6 animate-[spin_20s_linear_infinite]"
|
|
27
|
+
alt="React logo"
|
|
28
|
+
/>
|
|
25
29
|
</a>
|
|
26
30
|
</div>
|
|
27
31
|
|
|
28
32
|
<h1 className="text-5xl font-bold leading-[1.1] mb-8">VitePlus + React</h1>
|
|
29
33
|
|
|
30
34
|
<div className="p-8 space-y-4 flex flex-col items-center">
|
|
31
|
-
<button
|
|
35
|
+
<button
|
|
32
36
|
onClick={() => setCount((count) => count + 1)}
|
|
33
37
|
className="rounded-lg border border-transparent px-5 py-2.5 text-base font-medium bg-[#f9f9f9] dark:bg-zinc-800 cursor-pointer transition-colors hover:border-[#646cff] outline-none"
|
|
34
38
|
>
|
|
35
39
|
count is {count}
|
|
36
40
|
</button>
|
|
37
41
|
<p className="text-zinc-500">
|
|
38
|
-
Edit
|
|
42
|
+
Edit{' '}
|
|
43
|
+
<code className="bg-[#f1f1f1] dark:bg-zinc-800 px-1.5 py-0.5 rounded font-mono">
|
|
44
|
+
src/App.tsx
|
|
45
|
+
</code>{' '}
|
|
46
|
+
to test HMR
|
|
39
47
|
</p>
|
|
40
48
|
</div>
|
|
41
49
|
|
|
42
50
|
<p className="text-[#888] mt-8">
|
|
43
|
-
Check out
|
|
51
|
+
Check out{' '}
|
|
52
|
+
<a
|
|
53
|
+
href="https://github.com/voidzero-dev/vite-plus"
|
|
54
|
+
target="_blank"
|
|
55
|
+
rel="noreferrer"
|
|
56
|
+
className="font-medium text-[#646cff] hover:text-[#535bf2]"
|
|
57
|
+
>
|
|
58
|
+
VitePlus
|
|
59
|
+
</a>
|
|
60
|
+
, the unified toolchain for the web.
|
|
44
61
|
</p>
|
|
45
|
-
|
|
62
|
+
|
|
46
63
|
<p className="text-[#888] mt-4 text-sm">
|
|
47
64
|
Click on the VitePlus and React logos to learn more
|
|
48
65
|
</p>
|
|
49
66
|
</div>
|
|
50
67
|
)
|
|
51
|
-
}
|
|
68
|
+
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { defineConfig } from
|
|
2
|
-
import react from
|
|
1
|
+
import { defineConfig } from 'vite-plus'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
3
|
|
|
4
4
|
// https://vite.dev/config/
|
|
5
5
|
export default defineConfig({
|
|
6
|
-
fmt: { semi: false, singleQuote: true},
|
|
6
|
+
fmt: { semi: false, singleQuote: true },
|
|
7
7
|
staged: {
|
|
8
|
-
|
|
8
|
+
'*': 'vp check --fix',
|
|
9
9
|
},
|
|
10
10
|
lint: { options: { typeAware: true, typeCheck: true } },
|
|
11
11
|
plugins: [
|
|
12
12
|
react({
|
|
13
13
|
babel: {
|
|
14
|
-
plugins: [
|
|
15
|
-
["babel-plugin-react-compiler", { target: "19" }]
|
|
16
|
-
],
|
|
14
|
+
plugins: [['babel-plugin-react-compiler', { target: '19' }]],
|
|
17
15
|
},
|
|
18
|
-
}
|
|
16
|
+
}),
|
|
17
|
+
/* VITE_PLUS_PLUGINS */
|
|
19
18
|
],
|
|
20
|
-
})
|
|
19
|
+
})
|