@kevinmarrec/create-app 0.17.0 → 0.18.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/README.md +24 -0
- package/dist/index.mjs +66 -10
- package/package.json +10 -10
- package/template/.docker/mailpit/service.yml +1 -1
- package/template/.docker/metabase/service.yml +1 -1
- package/template/.docker/postgres/service.yml +1 -1
- package/template/.docker/traefik/service.yml +1 -1
- package/template/.github/renovate.json +9 -3
- package/template/.github/workflows/ci.yml +3 -3
- package/template/.node-version +1 -1
- package/template/.vscode/settings.json +7 -0
- package/template/README.md +1 -1
- package/template/api/Dockerfile +1 -1
- package/template/api/package.json +6 -5
- package/template/api/src/auth/index.ts +2 -2
- package/template/app/Dockerfile +1 -1
- package/template/app/package.json +14 -14
- package/template/app/vite.config.ts +1 -1
- package/template/compose.yml +2 -2
- package/template/package.json +8 -8
- package/template/tsconfig.json +7 -1
package/README.md
CHANGED
|
@@ -38,6 +38,8 @@ CLI that scaffolds an opinionated [Bun](https://bun.sh/) & [Vue](https://vuejs.o
|
|
|
38
38
|
|
|
39
39
|
> Requires [Bun](https://bun.sh/) v1.3 _or later_.
|
|
40
40
|
|
|
41
|
+
By default, the CLI scaffolds from its built-in opinionated template:
|
|
42
|
+
|
|
41
43
|
```sh
|
|
42
44
|
bun create @kevinmarrec/app
|
|
43
45
|
# OR
|
|
@@ -45,3 +47,25 @@ bunx @kevinmarrec/create-app
|
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
After scaffolding, see the generated `README.md` in your project root for detailed setup instructions, including environment configuration, Docker setup, and development workflows.
|
|
50
|
+
|
|
51
|
+
### Custom Template
|
|
52
|
+
|
|
53
|
+
You can use the `--template` (`-t`) option to scaffold from any external git repository instead of the default template:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
# GitHub shorthand
|
|
57
|
+
bun create @kevinmarrec/app -t user/repo
|
|
58
|
+
|
|
59
|
+
# HTTPS URL
|
|
60
|
+
bun create @kevinmarrec/app -t https://github.com/user/repo.git
|
|
61
|
+
|
|
62
|
+
# SSH URL
|
|
63
|
+
bun create @kevinmarrec/app -t git@github.com:user/repo.git
|
|
64
|
+
|
|
65
|
+
# Subdirectory of a repository
|
|
66
|
+
bun create @kevinmarrec/app -t user/repo#path/to/template
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The repository is cloned with `--depth 1` (shallow clone) and its contents are copied into the target directory.
|
|
70
|
+
|
|
71
|
+
Use `#subdir` to scaffold from a specific subdirectory within the repository.
|
package/dist/index.mjs
CHANGED
|
@@ -3,12 +3,13 @@ import process from "node:process";
|
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { cancel, confirm, intro, isCancel, log, note, outro, tasks, text } from "@clack/prompts";
|
|
5
5
|
import c from "ansis";
|
|
6
|
-
import { join, resolve } from "pathe";
|
|
6
|
+
import { basename, join, resolve } from "pathe";
|
|
7
7
|
import { x } from "tinyexec";
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
|
+
import os from "node:os";
|
|
9
10
|
|
|
10
11
|
//#region package.json
|
|
11
|
-
var version = "0.
|
|
12
|
+
var version = "0.18.0";
|
|
12
13
|
|
|
13
14
|
//#endregion
|
|
14
15
|
//#region src/utils/fs.ts
|
|
@@ -31,11 +32,62 @@ var fs_default = {
|
|
|
31
32
|
exists
|
|
32
33
|
};
|
|
33
34
|
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/utils/template.ts
|
|
37
|
+
function resolveTemplate(template) {
|
|
38
|
+
const [repo, ...rest] = template.split("#");
|
|
39
|
+
const subdir = rest.join("#") || void 0;
|
|
40
|
+
return {
|
|
41
|
+
url: resolveTemplateUrl(repo),
|
|
42
|
+
subdir
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function resolveTemplateUrl(repo) {
|
|
46
|
+
if (repo.startsWith("https://")) return repo;
|
|
47
|
+
if (repo.startsWith("git@")) return repo;
|
|
48
|
+
if (/^[^/\s]+\/[^/\s]+$/.test(repo)) return `https://github.com/${repo}.git`;
|
|
49
|
+
throw new Error(`Invalid template format: "${repo}"`);
|
|
50
|
+
}
|
|
51
|
+
async function cloneTemplate(url) {
|
|
52
|
+
const tempDir = await fs_default.mkdtemp(join(os.tmpdir(), "create-app-template-"));
|
|
53
|
+
try {
|
|
54
|
+
await x("git", [
|
|
55
|
+
"clone",
|
|
56
|
+
"--depth",
|
|
57
|
+
"1",
|
|
58
|
+
url,
|
|
59
|
+
tempDir
|
|
60
|
+
]);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
await fs_default.rm(tempDir, {
|
|
63
|
+
recursive: true,
|
|
64
|
+
force: true
|
|
65
|
+
});
|
|
66
|
+
throw new Error(`Failed to clone template from "${url}"`, { cause: error });
|
|
67
|
+
}
|
|
68
|
+
return tempDir;
|
|
69
|
+
}
|
|
70
|
+
|
|
34
71
|
//#endregion
|
|
35
72
|
//#region src/scaffold.ts
|
|
36
|
-
async function scaffold(root) {
|
|
73
|
+
async function scaffold(root, template) {
|
|
37
74
|
await fs_default.exists(root) ? await fs_default.empty(root) : await fs_default.mkdir(root, { recursive: true });
|
|
38
|
-
|
|
75
|
+
if (template) {
|
|
76
|
+
const { url, subdir } = resolveTemplate(template);
|
|
77
|
+
const tempDir = await cloneTemplate(url);
|
|
78
|
+
try {
|
|
79
|
+
const sourceDir = subdir ? join(tempDir, subdir) : tempDir;
|
|
80
|
+
await fs_default.cp(sourceDir, root, {
|
|
81
|
+
recursive: true,
|
|
82
|
+
filter: (src) => !ignorePredicate(basename(src))
|
|
83
|
+
});
|
|
84
|
+
} finally {
|
|
85
|
+
await fs_default.rm(tempDir, {
|
|
86
|
+
recursive: true,
|
|
87
|
+
force: true
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
} else await fs_default.cp(join(import.meta.dirname, "../template"), root, { recursive: true });
|
|
39
91
|
}
|
|
40
92
|
|
|
41
93
|
//#endregion
|
|
@@ -59,6 +111,10 @@ async function run() {
|
|
|
59
111
|
type: "boolean",
|
|
60
112
|
short: "h"
|
|
61
113
|
},
|
|
114
|
+
template: {
|
|
115
|
+
type: "string",
|
|
116
|
+
short: "t"
|
|
117
|
+
},
|
|
62
118
|
version: {
|
|
63
119
|
type: "boolean",
|
|
64
120
|
short: "v"
|
|
@@ -66,7 +122,7 @@ async function run() {
|
|
|
66
122
|
}
|
|
67
123
|
});
|
|
68
124
|
if (options.help) {
|
|
69
|
-
process.stdout.write("Usage: create-app [OPTIONS...] [DIRECTORY]\n\nOptions:\n -f, --force
|
|
125
|
+
process.stdout.write("Usage: create-app [OPTIONS...] [DIRECTORY]\n\nOptions:\n -f, --force Create the project even if the directory is not empty.\n -h, --help Display this help message.\n -t, --template <repo> Use a custom template from a git repository (supports #subdir).\n -v, --version Display the version number of this CLI.\n");
|
|
70
126
|
process.exit(0);
|
|
71
127
|
}
|
|
72
128
|
if (options.version) {
|
|
@@ -96,10 +152,10 @@ async function run() {
|
|
|
96
152
|
}), { strict: true });
|
|
97
153
|
}
|
|
98
154
|
await tasks([{
|
|
99
|
-
title: `Scaffolding project in ${c.blue(targetDir)}`,
|
|
155
|
+
title: options.template ? `Cloning ${c.blue(options.template)} into ${c.blue(targetDir)}` : `Scaffolding project in ${c.blue(targetDir)}`,
|
|
100
156
|
task: async () => {
|
|
101
|
-
await scaffold(targetDir);
|
|
102
|
-
return `Scaffolded project in ${c.blue(targetDir)}`;
|
|
157
|
+
await scaffold(targetDir, options.template);
|
|
158
|
+
return options.template ? `Cloned ${c.blue(options.template)} and scaffolded project in ${c.blue(targetDir)}` : `Scaffolded project in ${c.blue(targetDir)}`;
|
|
103
159
|
}
|
|
104
160
|
}]);
|
|
105
161
|
const shouldInstall = await confirm({
|
|
@@ -110,7 +166,7 @@ async function run() {
|
|
|
110
166
|
});
|
|
111
167
|
maybeCancel(shouldInstall);
|
|
112
168
|
await tasks([{
|
|
113
|
-
title: "Installing
|
|
169
|
+
title: "Installing dependencies",
|
|
114
170
|
enabled: shouldInstall,
|
|
115
171
|
task: async () => {
|
|
116
172
|
await x("bun", [
|
|
@@ -119,7 +175,7 @@ async function run() {
|
|
|
119
175
|
targetDir,
|
|
120
176
|
"--force"
|
|
121
177
|
]);
|
|
122
|
-
return "Installed
|
|
178
|
+
return "Installed dependencies";
|
|
123
179
|
}
|
|
124
180
|
}]);
|
|
125
181
|
await note([targetDir !== cwd && `cd ${c.reset.blue(projectName)}`, `bun run dev`].filter(Boolean).join("\n"), "Next steps");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevinmarrec/create-app",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.18.0",
|
|
5
5
|
"packageManager": "bun@1.3.9",
|
|
6
6
|
"description": "CLI that scaffolds an opinionated Bun & Vue fullstack application.",
|
|
7
7
|
"author": "Kevin Marrec <kevin@marrec.io>",
|
|
@@ -44,25 +44,25 @@
|
|
|
44
44
|
"test:coverage": "vitest --coverage"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@clack/prompts": "^1.0
|
|
47
|
+
"@clack/prompts": "^1.1.0",
|
|
48
48
|
"ansis": "^4.2.0",
|
|
49
49
|
"pathe": "^2.0.3",
|
|
50
50
|
"tinyexec": "^1.0.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@faker-js/faker": "^10.3.0",
|
|
54
|
-
"@kevinmarrec/eslint-config": "^1.
|
|
55
|
-
"@kevinmarrec/stylelint-config": "^1.
|
|
56
|
-
"@kevinmarrec/tsconfig": "^1.
|
|
57
|
-
"@types/bun": "^1.3.
|
|
54
|
+
"@kevinmarrec/eslint-config": "^1.12.1",
|
|
55
|
+
"@kevinmarrec/stylelint-config": "^1.12.1",
|
|
56
|
+
"@kevinmarrec/tsconfig": "^1.12.1",
|
|
57
|
+
"@types/bun": "^1.3.10",
|
|
58
58
|
"@vitest/coverage-v8": "^4.0.18",
|
|
59
59
|
"bumpp": "^10.4.1",
|
|
60
|
-
"eslint": "^9.39.
|
|
61
|
-
"knip": "^5.
|
|
62
|
-
"stylelint": "^17.
|
|
60
|
+
"eslint": "^9.39.3",
|
|
61
|
+
"knip": "^5.85.0",
|
|
62
|
+
"stylelint": "^17.4.0",
|
|
63
63
|
"tsdown": "^0.20.3",
|
|
64
64
|
"typescript": "^5.9.3",
|
|
65
65
|
"vitest": "^4.0.18",
|
|
66
|
-
"vue-tsc": "^3.2.
|
|
66
|
+
"vue-tsc": "^3.2.5"
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"extends": ["github>kevinmarrec/renovate-config"],
|
|
2
|
+
"extends": ["github>kevinmarrec/config//packages/renovate/default"],
|
|
4
3
|
"docker-compose": {
|
|
5
4
|
"managerFilePatterns": [
|
|
6
5
|
"/^\\.docker\\/[^/]*\\/service\\.ya?ml$/"
|
|
7
6
|
]
|
|
8
|
-
}
|
|
7
|
+
},
|
|
8
|
+
"packageRules": [
|
|
9
|
+
{
|
|
10
|
+
"matchDatasources": ["docker"],
|
|
11
|
+
"matchPackageNames": ["imbios/bun-node"],
|
|
12
|
+
"versioning": "regex:^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)-(?<compatibility>\\d+)\\.(?<build>\\d+\\.\\d+)-alpine$"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
9
15
|
}
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
16
|
- name: Setup Bun
|
|
17
|
-
uses: kevinmarrec/workflows/setup-bun@
|
|
17
|
+
uses: kevinmarrec/workflows/setup-bun@e2dafbacb91d9e74b79980f8f5a63dd20bf96619 # main
|
|
18
18
|
|
|
19
19
|
- name: Lint
|
|
20
20
|
run: bun run lint
|
|
@@ -32,12 +32,12 @@ jobs:
|
|
|
32
32
|
pull-requests: write
|
|
33
33
|
steps:
|
|
34
34
|
- name: Setup Bun
|
|
35
|
-
uses: kevinmarrec/workflows/setup-bun@
|
|
35
|
+
uses: kevinmarrec/workflows/setup-bun@e2dafbacb91d9e74b79980f8f5a63dd20bf96619 # main
|
|
36
36
|
|
|
37
37
|
- name: Build project
|
|
38
38
|
run: bun run build
|
|
39
39
|
|
|
40
40
|
- name: Analyze project build size differences
|
|
41
|
-
uses: kevinmarrec/workflows/filesize-diff@
|
|
41
|
+
uses: kevinmarrec/workflows/filesize-diff@e2dafbacb91d9e74b79980f8f5a63dd20bf96619 # main
|
|
42
42
|
with:
|
|
43
43
|
directories: app/dist,api/dist
|
package/template/.node-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
24.
|
|
1
|
+
24.14.0
|
|
@@ -69,6 +69,13 @@
|
|
|
69
69
|
"orpc": "context"
|
|
70
70
|
},
|
|
71
71
|
|
|
72
|
+
"json.schemas": [
|
|
73
|
+
{
|
|
74
|
+
"fileMatch": ["renovate.json"],
|
|
75
|
+
"url": "https://docs.renovatebot.com/renovate-schema.json"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
|
|
72
79
|
// i18n Ally
|
|
73
80
|
"i18n-ally.enabledFrameworks": ["vue"],
|
|
74
81
|
"i18n-ally.keystyle": "nested",
|
package/template/README.md
CHANGED
package/template/api/Dockerfile
CHANGED
|
@@ -9,18 +9,19 @@
|
|
|
9
9
|
"db:migrate": "bun --bun run drizzle-kit migrate --config src/database/drizzle/config.ts"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"@better-auth/drizzle-adapter": "^1.5.2",
|
|
12
13
|
"@libsql/client": "^0.17.0",
|
|
13
|
-
"@orpc/server": "^1.13.
|
|
14
|
-
"better-auth": "^1.
|
|
14
|
+
"@orpc/server": "^1.13.6",
|
|
15
|
+
"better-auth": "^1.5.2",
|
|
15
16
|
"drizzle-orm": "^0.45.1",
|
|
16
17
|
"pino": "^10.3.1",
|
|
17
18
|
"valibot": "^1.2.0"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
|
-
"@kevinmarrec/tsconfig": "^1.
|
|
21
|
-
"@types/bun": "^1.3.
|
|
21
|
+
"@kevinmarrec/tsconfig": "^1.12.1",
|
|
22
|
+
"@types/bun": "^1.3.10",
|
|
22
23
|
"drizzle-kit": "^0.31.9",
|
|
23
|
-
"pg": "^8.
|
|
24
|
+
"pg": "^8.19.0",
|
|
24
25
|
"pino-pretty": "^13.1.3",
|
|
25
26
|
"typescript": "~5.9.3"
|
|
26
27
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { type DB, drizzleAdapter } from '@better-auth/drizzle-adapter'
|
|
2
|
+
import { betterAuth } from 'better-auth/minimal'
|
|
3
3
|
import type { Logger } from 'pino'
|
|
4
4
|
|
|
5
5
|
import { env } from '../env'
|
package/template/app/Dockerfile
CHANGED
|
@@ -9,31 +9,31 @@
|
|
|
9
9
|
"preview": "vite preview --open"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@kevinmarrec/vue-i18n": "^1.2.
|
|
13
|
-
"@orpc/client": "^1.13.
|
|
14
|
-
"@orpc/vue-colada": "^1.13.
|
|
15
|
-
"@pinia/colada": "^0.21.
|
|
16
|
-
"@unhead/vue": "^2.1.
|
|
12
|
+
"@kevinmarrec/vue-i18n": "^1.2.2",
|
|
13
|
+
"@orpc/client": "^1.13.6",
|
|
14
|
+
"@orpc/vue-colada": "^1.13.6",
|
|
15
|
+
"@pinia/colada": "^0.21.7",
|
|
16
|
+
"@unhead/vue": "^2.1.10",
|
|
17
17
|
"@vueuse/core": "^14.2.1",
|
|
18
|
-
"better-auth": "^1.
|
|
18
|
+
"better-auth": "^1.5.2",
|
|
19
19
|
"pinia": "^3.0.4",
|
|
20
|
-
"unocss": "^66.6.
|
|
21
|
-
"vue": "^3.5.
|
|
20
|
+
"unocss": "^66.6.4",
|
|
21
|
+
"vue": "^3.5.29"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@kevinmarrec/tsconfig": "^1.
|
|
25
|
-
"@kevinmarrec/unocss-config": "^1.
|
|
26
|
-
"@kevinmarrec/vite-plugin-dark-mode": "^1.2.
|
|
24
|
+
"@kevinmarrec/tsconfig": "^1.12.1",
|
|
25
|
+
"@kevinmarrec/unocss-config": "^1.12.1",
|
|
26
|
+
"@kevinmarrec/vite-plugin-dark-mode": "^1.2.2",
|
|
27
27
|
"@modyfi/vite-plugin-yaml": "^1.1.1",
|
|
28
|
-
"@unhead/addons": "^2.1.
|
|
28
|
+
"@unhead/addons": "^2.1.10",
|
|
29
29
|
"@vitejs/plugin-vue": "^6.0.4",
|
|
30
30
|
"beasties": "^0.4.1",
|
|
31
|
-
"rollup-plugin-visualizer": "^
|
|
31
|
+
"rollup-plugin-visualizer": "^7.0.1",
|
|
32
32
|
"typescript": "~5.9.3",
|
|
33
33
|
"valibot": "^1.2.0",
|
|
34
34
|
"vite": "^7.3.1",
|
|
35
35
|
"vite-plugin-valibot-env": "^1.0.1",
|
|
36
|
-
"vite-plugin-vue-devtools": "^8.0.
|
|
36
|
+
"vite-plugin-vue-devtools": "^8.0.7",
|
|
37
37
|
"vite-ssg": "^28.3.0",
|
|
38
38
|
"vite-tsconfig-paths": "^6.1.1"
|
|
39
39
|
}
|
package/template/compose.yml
CHANGED
|
@@ -16,7 +16,7 @@ services:
|
|
|
16
16
|
|
|
17
17
|
api:
|
|
18
18
|
<<: *common
|
|
19
|
-
image: oven/bun:1.3.
|
|
19
|
+
image: oven/bun:1.3.10-alpine
|
|
20
20
|
container_name: api
|
|
21
21
|
init: true
|
|
22
22
|
depends_on:
|
|
@@ -36,7 +36,7 @@ services:
|
|
|
36
36
|
|
|
37
37
|
app:
|
|
38
38
|
<<: *common
|
|
39
|
-
image: imbios/bun-node:1.3.
|
|
39
|
+
image: imbios/bun-node:1.3.10-24.14.0-alpine
|
|
40
40
|
container_name: app
|
|
41
41
|
init: true
|
|
42
42
|
depends_on:
|
package/template/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"packageManager": "bun@1.3.9",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=24.
|
|
7
|
+
"node": ">=24.14.0"
|
|
8
8
|
},
|
|
9
9
|
"workspaces": [
|
|
10
10
|
"api",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"update": "bunx taze -I -rwi"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@kevinmarrec/eslint-config": "^1.
|
|
27
|
-
"@kevinmarrec/stylelint-config": "^1.
|
|
28
|
-
"@kevinmarrec/tsconfig": "^1.
|
|
29
|
-
"eslint": "^9.39.
|
|
30
|
-
"knip": "^5.
|
|
31
|
-
"stylelint": "^17.
|
|
26
|
+
"@kevinmarrec/eslint-config": "^1.12.1",
|
|
27
|
+
"@kevinmarrec/stylelint-config": "^1.12.1",
|
|
28
|
+
"@kevinmarrec/tsconfig": "^1.12.1",
|
|
29
|
+
"eslint": "^9.39.3",
|
|
30
|
+
"knip": "^5.85.0",
|
|
31
|
+
"stylelint": "^17.4.0",
|
|
32
32
|
"typescript": "~5.9.3",
|
|
33
|
-
"vue-tsc": "^3.2.
|
|
33
|
+
"vue-tsc": "^3.2.5"
|
|
34
34
|
}
|
|
35
35
|
}
|