@kevinmarrec/create-app 0.10.0 → 0.11.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.js +1 -1
- package/package.json +12 -12
- package/template/.docker/postgres/init.sql +5 -0
- package/template/.github/scripts/build-stats.md.ts +14 -33
- package/template/README.md +1 -0
- package/template/api/package.json +3 -3
- package/template/api/src/utils/cors.ts +1 -1
- package/template/app/.env +2 -0
- package/template/app/index.html +3 -0
- package/template/app/package.json +8 -8
- package/template/app/src/App.vue +0 -5
- package/template/app/src/env.d.ts +2 -0
- package/template/compose.yaml +45 -3
- package/template/package.json +8 -7
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevinmarrec/create-app",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"packageManager": "bun@1.3.
|
|
4
|
+
"version": "0.11.0",
|
|
5
|
+
"packageManager": "bun@1.3.3",
|
|
6
6
|
"description": "CLI that scaffolds an opinionated Bun & Vue fullstack application.",
|
|
7
7
|
"author": "Kevin Marrec <kevin@marrec.io>",
|
|
8
8
|
"license": "MIT",
|
|
@@ -53,18 +53,18 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@faker-js/faker": "^10.1.0",
|
|
56
|
-
"@kevinmarrec/eslint-config": "^1.5.
|
|
57
|
-
"@kevinmarrec/stylelint-config": "^1.5.
|
|
58
|
-
"@kevinmarrec/tsconfig": "^1.5.
|
|
59
|
-
"@types/bun": "^1.3.
|
|
60
|
-
"@vitest/coverage-v8": "^4.0.
|
|
56
|
+
"@kevinmarrec/eslint-config": "^1.5.7",
|
|
57
|
+
"@kevinmarrec/stylelint-config": "^1.5.7",
|
|
58
|
+
"@kevinmarrec/tsconfig": "^1.5.7",
|
|
59
|
+
"@types/bun": "^1.3.3",
|
|
60
|
+
"@vitest/coverage-v8": "^4.0.13",
|
|
61
61
|
"bumpp": "^10.3.1",
|
|
62
62
|
"eslint": "^9.39.1",
|
|
63
|
-
"knip": "^5.
|
|
64
|
-
"stylelint": "^16.
|
|
65
|
-
"tsdown": "^0.16.
|
|
63
|
+
"knip": "^5.70.1",
|
|
64
|
+
"stylelint": "^16.26.0",
|
|
65
|
+
"tsdown": "^0.16.6",
|
|
66
66
|
"typescript": "^5.9.3",
|
|
67
|
-
"vitest": "^4.0.
|
|
68
|
-
"vue-tsc": "^3.1.
|
|
67
|
+
"vitest": "^4.0.13",
|
|
68
|
+
"vue-tsc": "^3.1.5"
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -7,47 +7,23 @@ import { filesize } from 'filesize'
|
|
|
7
7
|
import { x } from 'tinyexec'
|
|
8
8
|
import { glob } from 'tinyglobby'
|
|
9
9
|
|
|
10
|
-
interface FileStats {
|
|
11
|
-
file: string
|
|
12
|
-
size: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
10
|
async function getFileStats(directory: string) {
|
|
16
|
-
const fileStats
|
|
17
|
-
|
|
18
|
-
for (const file of await glob(['**/*'], { cwd: directory })) {
|
|
19
|
-
const size = fs.statSync(path.join(directory, file)).size
|
|
20
|
-
fileStats.push({
|
|
11
|
+
const fileStats = await Promise.all(
|
|
12
|
+
(await glob(['**/*'], { cwd: directory })).map(async file => ({
|
|
21
13
|
file,
|
|
22
|
-
size,
|
|
23
|
-
})
|
|
24
|
-
|
|
14
|
+
size: fs.statSync(path.join(directory, file)).size,
|
|
15
|
+
})),
|
|
16
|
+
)
|
|
25
17
|
|
|
26
18
|
fileStats.sort((a, b) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// Within that, files ending with '.js' come first
|
|
32
|
-
if (a.file.endsWith('.js') && !b.file.endsWith('.js')) return -1
|
|
33
|
-
if (!a.file.endsWith('.js') && b.file.endsWith('.js')) return 1
|
|
34
|
-
|
|
35
|
-
// Otherwise sort alphabetically
|
|
36
|
-
return a.file.localeCompare(b.file)
|
|
19
|
+
const scoreA = (a.file.startsWith('assets/') ? 2 : 0) + (a.file.endsWith('.js') ? 1 : 0)
|
|
20
|
+
const scoreB = (b.file.startsWith('assets/') ? 2 : 0) + (b.file.endsWith('.js') ? 1 : 0)
|
|
21
|
+
return scoreB - scoreA || a.file.localeCompare(b.file)
|
|
37
22
|
})
|
|
38
23
|
|
|
39
24
|
return fileStats
|
|
40
25
|
}
|
|
41
26
|
|
|
42
|
-
async function generateFileStatsMarkdown(directory: string) {
|
|
43
|
-
const fileStats = await getFileStats(directory)
|
|
44
|
-
return [
|
|
45
|
-
'| File | Size |',
|
|
46
|
-
'| :--- | ---: |',
|
|
47
|
-
...fileStats.map(file => `| ${file.file} | ${filesize(file.size)} |`),
|
|
48
|
-
].join('\n')
|
|
49
|
-
}
|
|
50
|
-
|
|
51
27
|
async function main() {
|
|
52
28
|
const { positionals: [directory] } = parseArgs({
|
|
53
29
|
args: process.argv.slice(2),
|
|
@@ -61,7 +37,12 @@ async function main() {
|
|
|
61
37
|
|
|
62
38
|
await x('bun', ['run', 'build'], { nodeOptions: { cwd: directory } })
|
|
63
39
|
|
|
64
|
-
const
|
|
40
|
+
const fileStats = await getFileStats(path.join(directory, 'dist'))
|
|
41
|
+
const markdownTable = [
|
|
42
|
+
'| File | Size |',
|
|
43
|
+
'| :--- | ---: |',
|
|
44
|
+
...fileStats.map(file => `| ${file.file} | ${filesize(file.size)} |`),
|
|
45
|
+
].join('\n')
|
|
65
46
|
process.stdout.write(`${markdownTable}\n`)
|
|
66
47
|
}
|
|
67
48
|
|
package/template/README.md
CHANGED
|
@@ -199,6 +199,7 @@ bun run db:migrate
|
|
|
199
199
|
|
|
200
200
|
### Root Level Scripts
|
|
201
201
|
|
|
202
|
+
- `bun run dev` - Alias for `docker compose`
|
|
202
203
|
- `bun run check` - Run all checks (ESLint, Stylelint, unused dependencies, TypeScript)
|
|
203
204
|
- `bun run lint` - Run linting (ESLint and Stylelint)
|
|
204
205
|
- `bun run lint:inspect` - Open ESLint config inspector
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@libsql/client": "^0.15.15",
|
|
13
|
-
"@orpc/server": "^1.11.
|
|
14
|
-
"better-auth": "^1.
|
|
13
|
+
"@orpc/server": "^1.11.3",
|
|
14
|
+
"better-auth": "^1.4.1",
|
|
15
15
|
"drizzle-orm": "^0.44.7",
|
|
16
16
|
"pino": "^10.1.0",
|
|
17
17
|
"valibot": "^1.1.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@types/bun": "^1.3.
|
|
20
|
+
"@types/bun": "^1.3.3",
|
|
21
21
|
"drizzle-kit": "^0.31.7",
|
|
22
22
|
"pg": "^8.16.3",
|
|
23
23
|
"pino-pretty": "^13.1.2"
|
|
@@ -13,7 +13,7 @@ export function cors(handler: (req: Request) => Promise<Response>) {
|
|
|
13
13
|
: await handler(req)
|
|
14
14
|
|
|
15
15
|
if (req.method === 'OPTIONS') {
|
|
16
|
-
response.headers.append('Access-Control-Allow-Headers', 'Content-Type')
|
|
16
|
+
response.headers.append('Access-Control-Allow-Headers', 'Content-Type, Authorization, User-Agent')
|
|
17
17
|
response.headers.append('Access-Control-Allow-Methods', 'GET, HEAD, PUT, POST, DELETE, PATCH')
|
|
18
18
|
response.headers.append('Access-Control-Max-Age', '7200') // 2 hours https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Max-Age
|
|
19
19
|
}
|
package/template/app/.env
CHANGED
package/template/app/index.html
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<meta name="color-scheme" content="dark light" />
|
|
8
8
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
9
|
+
<link rel="preconnect" href="%VITE_API_URL%" crossorigin />
|
|
10
|
+
<link rel="dns-prefetch" href="%VITE_ANALYTICS_URL%" />
|
|
11
|
+
<script defer src="%VITE_ANALYTICS_URL%/script.js" data-website-id="%VITE_ANALYTICS_WEBSITE_ID%"></script>
|
|
9
12
|
<title>Title</title>
|
|
10
13
|
</head>
|
|
11
14
|
<body class="font-sans">
|
|
@@ -10,26 +10,26 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@kevinmarrec/vue-i18n": "^1.1.3",
|
|
13
|
-
"@orpc/client": "^1.11.
|
|
14
|
-
"@orpc/tanstack-query": "1.11.
|
|
13
|
+
"@orpc/client": "^1.11.3",
|
|
14
|
+
"@orpc/tanstack-query": "^1.11.3",
|
|
15
15
|
"@tanstack/query-core": "^5.90.10",
|
|
16
16
|
"@tanstack/vue-query": "^5.91.2",
|
|
17
17
|
"@unhead/vue": "^2.0.19",
|
|
18
18
|
"@vueuse/core": "^14.0.0",
|
|
19
|
-
"better-auth": "^1.
|
|
20
|
-
"unocss": "^66.5.
|
|
19
|
+
"better-auth": "^1.4.1",
|
|
20
|
+
"unocss": "^66.5.9",
|
|
21
21
|
"vue": "^3.5.24"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@kevinmarrec/unocss-config": "^1.5.
|
|
24
|
+
"@kevinmarrec/unocss-config": "^1.5.7",
|
|
25
25
|
"@kevinmarrec/vite-plugin-dark-mode": "^1.1.2",
|
|
26
26
|
"@modyfi/vite-plugin-yaml": "^1.1.1",
|
|
27
27
|
"@unhead/addons": "^2.0.19",
|
|
28
|
-
"@vitejs/plugin-vue": "^6.0.
|
|
28
|
+
"@vitejs/plugin-vue": "^6.0.2",
|
|
29
29
|
"beasties": "^0.3.5",
|
|
30
30
|
"rollup-plugin-visualizer": "^6.0.5",
|
|
31
|
-
"vite": "^7.2.
|
|
32
|
-
"vite-plugin-vue-devtools": "^8.0.
|
|
31
|
+
"vite": "^7.2.4",
|
|
32
|
+
"vite-plugin-vue-devtools": "^8.0.5",
|
|
33
33
|
"vite-ssg": "^28.2.2",
|
|
34
34
|
"vite-tsconfig-paths": "^5.1.4"
|
|
35
35
|
}
|
package/template/app/src/App.vue
CHANGED
|
@@ -6,11 +6,6 @@ import { useAuth, useContent, useHead, useI18n } from '~/app/composables'
|
|
|
6
6
|
const { t } = useI18n()
|
|
7
7
|
useHead({
|
|
8
8
|
title: () => t('title'),
|
|
9
|
-
link: [{
|
|
10
|
-
rel: 'preconnect',
|
|
11
|
-
href: new URL(import.meta.env.VITE_API_URL).origin,
|
|
12
|
-
crossorigin: '',
|
|
13
|
-
}],
|
|
14
9
|
})
|
|
15
10
|
|
|
16
11
|
const { user, signIn, signUp, signOut } = useAuth()
|
package/template/compose.yaml
CHANGED
|
@@ -38,7 +38,7 @@ services:
|
|
|
38
38
|
test: [CMD-SHELL, traefik healthcheck --ping]
|
|
39
39
|
interval: 1s
|
|
40
40
|
timeout: 1s
|
|
41
|
-
retries:
|
|
41
|
+
retries: 20
|
|
42
42
|
labels:
|
|
43
43
|
traefik.enable: 'true'
|
|
44
44
|
traefik.http.routers.traefik.rule: Host(`traefik.dev.localhost`)
|
|
@@ -52,16 +52,16 @@ services:
|
|
|
52
52
|
environment:
|
|
53
53
|
- POSTGRES_USER=user
|
|
54
54
|
- POSTGRES_PASSWORD=password
|
|
55
|
-
- POSTGRES_DB=app
|
|
56
55
|
ports:
|
|
57
56
|
- 5432:5432
|
|
58
57
|
volumes:
|
|
59
58
|
- postgres_data:/var/lib/postgresql/data
|
|
59
|
+
- ./.docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
|
60
60
|
healthcheck:
|
|
61
61
|
test: [CMD-SHELL, "psql postgresql://user:password@postgres:5432/app -c 'SELECT 1' 2> /dev/null"]
|
|
62
62
|
interval: 1s
|
|
63
63
|
timeout: 1s
|
|
64
|
-
retries:
|
|
64
|
+
retries: 20
|
|
65
65
|
|
|
66
66
|
metabase:
|
|
67
67
|
image: metabase/metabase:v0.57.x
|
|
@@ -121,6 +121,47 @@ services:
|
|
|
121
121
|
traefik.http.routers.app.tls: 'true'
|
|
122
122
|
traefik.http.services.app.loadbalancer.server.port: '5173'
|
|
123
123
|
|
|
124
|
+
studio:
|
|
125
|
+
depends_on:
|
|
126
|
+
traefik:
|
|
127
|
+
condition: service_healthy
|
|
128
|
+
postgres:
|
|
129
|
+
condition: service_healthy
|
|
130
|
+
container_name: studio
|
|
131
|
+
image: ghcr.io/drizzle-team/gateway:latest
|
|
132
|
+
environment:
|
|
133
|
+
- MASTERPASS=foobar
|
|
134
|
+
volumes:
|
|
135
|
+
- studio_data:/app
|
|
136
|
+
labels:
|
|
137
|
+
traefik.enable: 'true'
|
|
138
|
+
traefik.http.routers.studio.rule: Host(`studio.dev.localhost`)
|
|
139
|
+
traefik.http.routers.studio.entrypoints: websecure
|
|
140
|
+
traefik.http.routers.studio.tls: 'true'
|
|
141
|
+
traefik.http.services.studio.loadbalancer.server.port: '4983'
|
|
142
|
+
|
|
143
|
+
analytics:
|
|
144
|
+
depends_on:
|
|
145
|
+
traefik:
|
|
146
|
+
condition: service_healthy
|
|
147
|
+
postgres:
|
|
148
|
+
condition: service_healthy
|
|
149
|
+
container_name: analytics
|
|
150
|
+
image: umamisoftware/umami:3
|
|
151
|
+
environment:
|
|
152
|
+
- DATABASE_URL=postgresql://user:password@postgres:5432/analytics
|
|
153
|
+
healthcheck:
|
|
154
|
+
test: [CMD-SHELL, curl -f http://localhost:3000]
|
|
155
|
+
interval: 1s
|
|
156
|
+
timeout: 1s
|
|
157
|
+
retries: 20
|
|
158
|
+
labels:
|
|
159
|
+
traefik.enable: 'true'
|
|
160
|
+
traefik.http.routers.analytics.rule: Host(`analytics.dev.localhost`)
|
|
161
|
+
traefik.http.routers.analytics.entrypoints: websecure
|
|
162
|
+
traefik.http.routers.analytics.tls: 'true'
|
|
163
|
+
traefik.http.services.analytics.loadbalancer.server.port: '3000'
|
|
164
|
+
|
|
124
165
|
networks:
|
|
125
166
|
default:
|
|
126
167
|
name: dev
|
|
@@ -128,3 +169,4 @@ networks:
|
|
|
128
169
|
volumes:
|
|
129
170
|
postgres_data:
|
|
130
171
|
metabase_data:
|
|
172
|
+
studio_data:
|
package/template/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "project",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"private": true,
|
|
5
|
-
"packageManager": "bun@1.3.
|
|
5
|
+
"packageManager": "bun@1.3.3",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "lts/*"
|
|
8
8
|
},
|
|
@@ -16,21 +16,22 @@
|
|
|
16
16
|
"check:stylelint": "stylelint '**/*.{css,scss,vue}' --ignorePath .gitignore --cache",
|
|
17
17
|
"check:types": "vue-tsc --noEmit",
|
|
18
18
|
"check:unused": "knip -n",
|
|
19
|
+
"dev": "docker compose",
|
|
19
20
|
"lint": "bun run check:eslint && bun run check:stylelint",
|
|
20
21
|
"lint:inspect": "bunx @eslint/config-inspector",
|
|
21
22
|
"update": "bunx taze -I -rwi"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
|
-
"@kevinmarrec/eslint-config": "^1.5.
|
|
25
|
-
"@kevinmarrec/stylelint-config": "^1.5.
|
|
26
|
-
"@kevinmarrec/tsconfig": "^1.5.
|
|
25
|
+
"@kevinmarrec/eslint-config": "^1.5.7",
|
|
26
|
+
"@kevinmarrec/stylelint-config": "^1.5.7",
|
|
27
|
+
"@kevinmarrec/tsconfig": "^1.5.7",
|
|
27
28
|
"eslint": "^9.39.1",
|
|
28
29
|
"filesize": "^11.0.13",
|
|
29
|
-
"knip": "^5.
|
|
30
|
-
"stylelint": "^16.
|
|
30
|
+
"knip": "^5.70.1",
|
|
31
|
+
"stylelint": "^16.26.0",
|
|
31
32
|
"tinyexec": "^1.0.2",
|
|
32
33
|
"tinyglobby": "^0.2.15",
|
|
33
34
|
"typescript": "~5.9.3",
|
|
34
|
-
"vue-tsc": "^3.1.
|
|
35
|
+
"vue-tsc": "^3.1.5"
|
|
35
36
|
}
|
|
36
37
|
}
|