create-vue3-enterprise 1.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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +216 -0
- package/package.json +31 -0
- package/template/.editorconfig +13 -0
- package/template/.eslintrc.cjs +21 -0
- package/template/.github/workflows/ci.yml +70 -0
- package/template/.prettierrc +8 -0
- package/template/index.html +13 -0
- package/template/playwright.config.ts +33 -0
- package/template/public/vite.svg +1 -0
- package/template/src/App.vue +34 -0
- package/template/src/assets/vue.svg +1 -0
- package/template/src/components/HelloWorld.vue +35 -0
- package/template/src/main.ts +5 -0
- package/template/src/style.css +80 -0
- package/template/tests/e2e/app.spec.ts +23 -0
- package/template/tests/unit/HelloWorld.spec.ts +10 -0
- package/template/tsconfig.json +21 -0
- package/template/tsconfig.node.json +10 -0
- package/template/vite.config.ts +9 -0
- package/template/vitest.config.ts +17 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import minimist from 'minimist';
|
|
6
|
+
import prompts from 'prompts';
|
|
7
|
+
import { red, green, cyan } from 'kolorist';
|
|
8
|
+
const argv = minimist(process.argv.slice(2), {
|
|
9
|
+
string: ['_'],
|
|
10
|
+
boolean: ['help', 'template', 'force'],
|
|
11
|
+
alias: {
|
|
12
|
+
h: 'help',
|
|
13
|
+
t: 'template',
|
|
14
|
+
f: 'force'
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
20
|
+
function printHelp() {
|
|
21
|
+
console.log(`
|
|
22
|
+
${cyan('create-vue3-enterprise')}
|
|
23
|
+
|
|
24
|
+
${green('Usage:')}
|
|
25
|
+
npm create vue3-enterprise <project-name> [options]
|
|
26
|
+
|
|
27
|
+
${green('Options:')}
|
|
28
|
+
-h, --help Show help
|
|
29
|
+
-f, --force Force overwrite
|
|
30
|
+
|
|
31
|
+
${green('Examples:')}
|
|
32
|
+
npm create vue3-enterprise my-project
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
function isValidPackageName(projectName) {
|
|
36
|
+
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName);
|
|
37
|
+
}
|
|
38
|
+
function toValidPackageName(projectName) {
|
|
39
|
+
return projectName.trim().toLowerCase().replace(/\s+/g, '-').replace(/^[._]/, '').replace(/[^a-z0-9-~]+/g, '-');
|
|
40
|
+
}
|
|
41
|
+
function emptyDir(dir) {
|
|
42
|
+
if (!fs.existsSync(dir))
|
|
43
|
+
return;
|
|
44
|
+
for (const file of fs.readdirSync(dir)) {
|
|
45
|
+
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function copyDir(srcDir, destDir) {
|
|
49
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
50
|
+
for (const file of fs.readdirSync(srcDir)) {
|
|
51
|
+
const srcFile = path.resolve(srcDir, file);
|
|
52
|
+
const destFile = path.resolve(destDir, file);
|
|
53
|
+
const stat = fs.statSync(srcFile);
|
|
54
|
+
if (stat.isDirectory())
|
|
55
|
+
copyDir(srcFile, destFile);
|
|
56
|
+
else
|
|
57
|
+
fs.copyFileSync(srcFile, destFile);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function makePkg(targetDir, features, needRouter, needPinia) {
|
|
61
|
+
const name = isValidPackageName(targetDir) ? targetDir : toValidPackageName(targetDir);
|
|
62
|
+
const pkg = {
|
|
63
|
+
name,
|
|
64
|
+
version: '0.0.0',
|
|
65
|
+
private: true,
|
|
66
|
+
type: 'module',
|
|
67
|
+
scripts: {
|
|
68
|
+
dev: 'vite',
|
|
69
|
+
build: 'vue-tsc && vite build',
|
|
70
|
+
preview: 'vite preview',
|
|
71
|
+
test: 'vitest',
|
|
72
|
+
'test:e2e': 'playwright test',
|
|
73
|
+
'test:perf': 'playwright test --config=playwright.config.perf.ts',
|
|
74
|
+
lint: 'eslint . --ext .vue,.ts,.tsx --fix',
|
|
75
|
+
format: 'prettier --write .',
|
|
76
|
+
'type-check': 'vue-tsc --noEmit'
|
|
77
|
+
},
|
|
78
|
+
dependencies: { vue: '^3.4.0' },
|
|
79
|
+
devDependencies: {
|
|
80
|
+
'@vitejs/plugin-vue': '^5.0.0',
|
|
81
|
+
typescript: '^5.3.0',
|
|
82
|
+
vite: '^5.0.0',
|
|
83
|
+
'vue-tsc': '^1.8.0'
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
if (needRouter)
|
|
87
|
+
pkg.dependencies['vue-router'] = '^4.2.0';
|
|
88
|
+
if (needPinia)
|
|
89
|
+
pkg.dependencies['pinia'] = '^2.1.0';
|
|
90
|
+
if (features.includes('lint')) {
|
|
91
|
+
Object.assign(pkg.devDependencies, {
|
|
92
|
+
'@typescript-eslint/eslint-plugin': '^6.21.0',
|
|
93
|
+
'@typescript-eslint/parser': '^6.21.0',
|
|
94
|
+
'@vue/eslint-config-prettier': '^9.0.0',
|
|
95
|
+
'@vue/eslint-config-typescript': '^12.0.0',
|
|
96
|
+
eslint: '^8.57.0',
|
|
97
|
+
'eslint-plugin-vue': '^9.21.0',
|
|
98
|
+
prettier: '^3.2.0'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (features.includes('vitest')) {
|
|
102
|
+
Object.assign(pkg.devDependencies, {
|
|
103
|
+
'@vue/test-utils': '^2.4.0',
|
|
104
|
+
'happy-dom': '^13.0.0',
|
|
105
|
+
vitest: '^1.2.0'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (features.includes('playwright')) {
|
|
109
|
+
pkg.devDependencies['@playwright/test'] = '^1.41.0';
|
|
110
|
+
}
|
|
111
|
+
if (features.includes('mcp')) {
|
|
112
|
+
pkg.devDependencies['vue3-enterprise-mcp'] = '^1.0.0';
|
|
113
|
+
}
|
|
114
|
+
if (features.includes('ci')) {
|
|
115
|
+
pkg.devDependencies['vue3-enterprise-ci'] = '^1.0.0';
|
|
116
|
+
}
|
|
117
|
+
return pkg;
|
|
118
|
+
}
|
|
119
|
+
async function main() {
|
|
120
|
+
console.log(`\n${cyan('Vue3 Enterprise Toolchain')}\n`);
|
|
121
|
+
if (argv.help) {
|
|
122
|
+
printHelp();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let targetDir = argv._[0];
|
|
126
|
+
const response = await prompts([
|
|
127
|
+
{
|
|
128
|
+
type: targetDir ? null : 'text',
|
|
129
|
+
name: 'name',
|
|
130
|
+
message: 'Project name:',
|
|
131
|
+
initial: 'vue3-enterprise-project',
|
|
132
|
+
onState: (s) => { targetDir = String(s.value).trim() || 'vue3-enterprise-project'; }
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'select', name: 'template', message: 'Select template:',
|
|
136
|
+
choices: [
|
|
137
|
+
{ title: 'Vue3 + TypeScript + Vite', value: 'vue3-ts' },
|
|
138
|
+
{ title: 'Vue3 + TS + Vite + Pinia', value: 'vue3-ts-pinia' },
|
|
139
|
+
{ title: 'Vue3 + TS + Vite + Pinia + Router', value: 'vue3-ts-full' }
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
type: 'multiselect', name: 'features', message: 'Select features:',
|
|
144
|
+
choices: [
|
|
145
|
+
{ title: 'ESLint + Prettier', value: 'lint', selected: true },
|
|
146
|
+
{ title: 'Vitest', value: 'vitest', selected: true },
|
|
147
|
+
{ title: 'Playwright', value: 'playwright', selected: true },
|
|
148
|
+
{ title: 'Vue3 Enterprise MCP', value: 'mcp', selected: true },
|
|
149
|
+
{ title: 'CI/CD Workflow', value: 'ci', selected: true },
|
|
150
|
+
{ title: 'Performance Benchmark', value: 'perf', selected: true }
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: 'confirm', name: 'router', message: 'Add Vue Router?', initial: true
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
type: 'confirm', name: 'pinia', message: 'Add Pinia?', initial: true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
type: 'confirm', name: 'overwrite',
|
|
161
|
+
message: targetDir && fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0
|
|
162
|
+
? `Dir "${targetDir}" exists. Overwrite?` : 'Overwrite existing?',
|
|
163
|
+
initial: false
|
|
164
|
+
}
|
|
165
|
+
], { onCancel: () => { console.log(red('✖ Cancelled')); process.exit(1); } });
|
|
166
|
+
if (!response.overwrite) {
|
|
167
|
+
console.log(red('✖ Cancelled'));
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const root = path.join(cwd, targetDir);
|
|
171
|
+
if (fs.existsSync(root)) {
|
|
172
|
+
if (argv.force || response.overwrite)
|
|
173
|
+
emptyDir(root);
|
|
174
|
+
else {
|
|
175
|
+
console.log(red(`✖ Dir "${targetDir}" exists`));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else
|
|
180
|
+
fs.mkdirSync(root, { recursive: true });
|
|
181
|
+
console.log(`\n${cyan('Creating project...')}\n`);
|
|
182
|
+
copyDir(path.resolve(__dirname, '../template'), root);
|
|
183
|
+
const pkg = makePkg(targetDir, response.features || [], response.router, response.pinia);
|
|
184
|
+
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(pkg, null, 2));
|
|
185
|
+
const desc = {
|
|
186
|
+
lint: '- 🧹 ESLint + Prettier',
|
|
187
|
+
vitest: '- 🧪 Vitest Unit Tests',
|
|
188
|
+
playwright: '- 🎭 Playwright E2E',
|
|
189
|
+
mcp: '- 🔍 Vue3 Enterprise MCP',
|
|
190
|
+
ci: '- ⚡ CI/CD',
|
|
191
|
+
perf: '- 📊 Performance'
|
|
192
|
+
};
|
|
193
|
+
const readme = `# ${pkg.name}
|
|
194
|
+
|
|
195
|
+
Created with Vue3 Enterprise Toolchain
|
|
196
|
+
|
|
197
|
+
## Features
|
|
198
|
+
${(response.features || []).map((f) => desc[f]).filter(Boolean).join('\n')}
|
|
199
|
+
|
|
200
|
+
## Quick Start
|
|
201
|
+
\`\`\`bash
|
|
202
|
+
npm install
|
|
203
|
+
npm run dev
|
|
204
|
+
\`\`\`
|
|
205
|
+
|
|
206
|
+
## Scripts
|
|
207
|
+
- \`npm run dev\` - Start dev server
|
|
208
|
+
- \`npm run build\` - Build
|
|
209
|
+
- \`npm test\` - Run tests
|
|
210
|
+
`;
|
|
211
|
+
fs.writeFileSync(path.join(root, 'README.md'), readme);
|
|
212
|
+
const gitignore = `node_modules\ndist\n*.local\n.vscode\ncoverage\ntest-results\nplaywright-report\n.perf-baseline.json`;
|
|
213
|
+
fs.writeFileSync(path.join(root, '.gitignore'), gitignore);
|
|
214
|
+
console.log(`${green('✔')} Created!\n cd ${cyan(targetDir)}\n npm install\n npm run dev\n`);
|
|
215
|
+
}
|
|
216
|
+
main().catch((e) => { console.error(e); process.exit(1); });
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-vue3-enterprise",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vue3 + TypeScript + Vite 企业级项目脚手架",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-vue3-enterprise": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"template"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"test": "node ./dist/index.js --help",
|
|
18
|
+
"test:create": "node ./dist/index.js test-project --force"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"kolorist": "^1.8.0",
|
|
22
|
+
"minimist": "^1.2.8",
|
|
23
|
+
"prompts": "^2.4.2"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/minimist": "^1.2.5",
|
|
27
|
+
"@types/node": "^20.0.0",
|
|
28
|
+
"@types/prompts": "^2.4.9",
|
|
29
|
+
"typescript": "^5.3.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-env node */
|
|
2
|
+
require('@rushstack/eslint-patch/modern-module-resolution')
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
root: true,
|
|
6
|
+
'extends': [
|
|
7
|
+
'plugin:vue/vue3-essential',
|
|
8
|
+
'eslint:recommended',
|
|
9
|
+
'@vue/eslint-config-typescript',
|
|
10
|
+
'@vue/eslint-config-prettier/skip-formatting'
|
|
11
|
+
],
|
|
12
|
+
parserOptions: {
|
|
13
|
+
ecmaVersion: 'latest'
|
|
14
|
+
},
|
|
15
|
+
rules: {
|
|
16
|
+
'vue/multi-word-component-names': 'off',
|
|
17
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
18
|
+
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|
19
|
+
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: '20'
|
|
17
|
+
cache: 'npm'
|
|
18
|
+
- run: npm ci
|
|
19
|
+
- run: npm run lint
|
|
20
|
+
- run: npm run type-check
|
|
21
|
+
|
|
22
|
+
test:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: '20'
|
|
29
|
+
cache: 'npm'
|
|
30
|
+
- run: npm ci
|
|
31
|
+
- run: npm test -- --run
|
|
32
|
+
|
|
33
|
+
e2e:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
- uses: actions/setup-node@v4
|
|
38
|
+
with:
|
|
39
|
+
node-version: '20'
|
|
40
|
+
cache: 'npm'
|
|
41
|
+
- run: npm ci
|
|
42
|
+
- run: npx playwright install --with-deps
|
|
43
|
+
- run: npm run test:e2e
|
|
44
|
+
- uses: actions/upload-artifact@v4
|
|
45
|
+
if: always()
|
|
46
|
+
with:
|
|
47
|
+
name: playwright-report
|
|
48
|
+
path: playwright-report/
|
|
49
|
+
retention-days: 30
|
|
50
|
+
|
|
51
|
+
performance:
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
needs: [lint, test]
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v4
|
|
56
|
+
- uses: actions/setup-node@v4
|
|
57
|
+
with:
|
|
58
|
+
node-version: '20'
|
|
59
|
+
cache: 'npm'
|
|
60
|
+
- run: npm ci
|
|
61
|
+
- name: Run Performance Tests
|
|
62
|
+
run: npx vue3-enterprise-ci run-perf
|
|
63
|
+
env:
|
|
64
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
65
|
+
- name: Upload Performance Report
|
|
66
|
+
uses: actions/upload-artifact@v4
|
|
67
|
+
with:
|
|
68
|
+
name: performance-report
|
|
69
|
+
path: perf-report/
|
|
70
|
+
retention-days: 30
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
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>Vue3 Enterprise</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
testDir: './tests/e2e',
|
|
5
|
+
fullyParallel: true,
|
|
6
|
+
forbidOnly: !!process.env.CI,
|
|
7
|
+
retries: process.env.CI ? 2 : 0,
|
|
8
|
+
workers: process.env.CI ? 1 : undefined,
|
|
9
|
+
reporter: 'html',
|
|
10
|
+
use: {
|
|
11
|
+
baseURL: 'http://localhost:5173',
|
|
12
|
+
trace: 'on-first-retry',
|
|
13
|
+
},
|
|
14
|
+
projects: [
|
|
15
|
+
{
|
|
16
|
+
name: 'chromium',
|
|
17
|
+
use: { ...devices['Desktop Chrome'] },
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'firefox',
|
|
21
|
+
use: { ...devices['Desktop Firefox'] },
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'webkit',
|
|
25
|
+
use: { ...devices['Desktop Safari'] },
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
webServer: {
|
|
29
|
+
command: 'npm run dev',
|
|
30
|
+
url: 'http://localhost:5173',
|
|
31
|
+
reuseExistingServer: !process.env.CI,
|
|
32
|
+
},
|
|
33
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.906-4.828c2.372-.72 4.746 1.449 4.151 3.828l-12.127 58.781c-.856 4.156 4.64 6.425 6.936 3.038l.066-.085L186.05 74.64c1.301-1.828-.225-4.303-2.356-3.87l-25.563 5.13c-2.418.484-4.487-1.77-3.808-4.154l16.862-60.374c.68-2.44-1.474-4.667-3.941-4.155L185.432.063Z"></path></svg>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import HelloWorld from './components/HelloWorld.vue'
|
|
4
|
+
|
|
5
|
+
const count = ref(0)
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div>
|
|
10
|
+
<a href="https://vitejs.dev" target="_blank">
|
|
11
|
+
<img src="/vite.svg" class="logo" alt="Vite logo" />
|
|
12
|
+
</a>
|
|
13
|
+
<a href="https://vuejs.org/" target="_blank">
|
|
14
|
+
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
|
|
15
|
+
</a>
|
|
16
|
+
</div>
|
|
17
|
+
<HelloWorld msg="Vue3 Enterprise" />
|
|
18
|
+
<button type="button" @click="count++">count is {{ count }}</button>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<style scoped>
|
|
22
|
+
.logo {
|
|
23
|
+
height: 6em;
|
|
24
|
+
padding: 1.5em;
|
|
25
|
+
will-change: filter;
|
|
26
|
+
transition: filter 300ms;
|
|
27
|
+
}
|
|
28
|
+
.logo:hover {
|
|
29
|
+
filter: drop-shadow(0 0 2em #646cffaa);
|
|
30
|
+
}
|
|
31
|
+
.logo.vue:hover {
|
|
32
|
+
filter: drop-shadow(0 0 2em #42b883aa);
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{
|
|
3
|
+
msg: string
|
|
4
|
+
}>()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<h1>{{ msg }}</h1>
|
|
9
|
+
|
|
10
|
+
<p>
|
|
11
|
+
Recommended IDE setup:
|
|
12
|
+
<a href="https://code.visualstudio.com/" target="_blank">VSCode</a>
|
|
13
|
+
+
|
|
14
|
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p>
|
|
18
|
+
<a href="https://vitejs.dev/guide/features.html" target="_blank">
|
|
19
|
+
Vite Documentation
|
|
20
|
+
</a>
|
|
21
|
+
|
|
|
22
|
+
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p>
|
|
26
|
+
Edit
|
|
27
|
+
<code>components/HelloWorld.vue</code> to test hot module replacement.
|
|
28
|
+
</p>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<style scoped>
|
|
32
|
+
a {
|
|
33
|
+
color: #42b883;
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
color: rgba(255, 255, 255, 0.87);
|
|
8
|
+
background-color: #242424;
|
|
9
|
+
|
|
10
|
+
font-synthesis: none;
|
|
11
|
+
text-rendering: optimizeLegibility;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
-webkit-text-size-adjust: 100%;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
a {
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
color: #646cff;
|
|
20
|
+
text-decoration: inherit;
|
|
21
|
+
}
|
|
22
|
+
a:hover {
|
|
23
|
+
color: #535bf2;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
body {
|
|
27
|
+
margin: 0;
|
|
28
|
+
display: flex;
|
|
29
|
+
place-items: center;
|
|
30
|
+
min-width: 320px;
|
|
31
|
+
min-height: 100vh;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
h1 {
|
|
35
|
+
font-size: 3.2em;
|
|
36
|
+
line-height: 1.1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
button {
|
|
40
|
+
border-radius: 8px;
|
|
41
|
+
border: 1px solid transparent;
|
|
42
|
+
padding: 0.6em 1.2em;
|
|
43
|
+
font-size: 1em;
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
font-family: inherit;
|
|
46
|
+
background-color: #1a1a1a;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
transition: border-color 0.25s;
|
|
49
|
+
}
|
|
50
|
+
button:hover {
|
|
51
|
+
border-color: #646cff;
|
|
52
|
+
}
|
|
53
|
+
button:focus,
|
|
54
|
+
button:focus-visible {
|
|
55
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.card {
|
|
59
|
+
padding: 2em;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#app {
|
|
63
|
+
max-width: 1280px;
|
|
64
|
+
margin: 0 auto;
|
|
65
|
+
padding: 2rem;
|
|
66
|
+
text-align: center;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@media (prefers-color-scheme: light) {
|
|
70
|
+
:root {
|
|
71
|
+
color: #213547;
|
|
72
|
+
background-color: #ffffff;
|
|
73
|
+
}
|
|
74
|
+
a:hover {
|
|
75
|
+
color: #747bff;
|
|
76
|
+
}
|
|
77
|
+
button {
|
|
78
|
+
background-color: #f9f9f9;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test('homepage has title and links', async ({ page }) => {
|
|
4
|
+
await page.goto('/')
|
|
5
|
+
|
|
6
|
+
await expect(page).toHaveTitle(/Vue3/)
|
|
7
|
+
|
|
8
|
+
const viteLink = page.locator('a[href="https://vitejs.dev"]')
|
|
9
|
+
await expect(viteLink).toBeVisible()
|
|
10
|
+
|
|
11
|
+
const vueLink = page.locator('a[href="https://vuejs.org/"]')
|
|
12
|
+
await expect(vueLink).toBeVisible()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('counter increments on click', async ({ page }) => {
|
|
16
|
+
await page.goto('/')
|
|
17
|
+
|
|
18
|
+
const button = page.locator('button')
|
|
19
|
+
await expect(button).toHaveText('count is 0')
|
|
20
|
+
|
|
21
|
+
await button.click()
|
|
22
|
+
await expect(button).toHaveText('count is 1')
|
|
23
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import HelloWorld from '../../src/components/HelloWorld.vue'
|
|
4
|
+
|
|
5
|
+
describe('HelloWorld', () => {
|
|
6
|
+
it('renders properly', () => {
|
|
7
|
+
const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
|
|
8
|
+
expect(wrapper.text()).toContain('Hello Vitest')
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config'
|
|
2
|
+
import vue from '@vitejs/plugin-vue'
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [vue()],
|
|
6
|
+
test: {
|
|
7
|
+
globals: true,
|
|
8
|
+
environment: 'happy-dom',
|
|
9
|
+
include: ['tests/unit/**/*.spec.ts'],
|
|
10
|
+
coverage: {
|
|
11
|
+
provider: 'v8',
|
|
12
|
+
reporter: ['text', 'json', 'html'],
|
|
13
|
+
include: ['src/**/*'],
|
|
14
|
+
exclude: ['src/**/*.d.ts', 'src/main.ts']
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
})
|