create-bcp-app 0.1.3 → 0.1.5
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 +37 -3
- package/package.json +3 -3
- package/src/project-options.mjs +199 -31
- package/template/tsconfig.json +8 -2
package/README.md
CHANGED
|
@@ -20,6 +20,20 @@ Select a database:
|
|
|
20
20
|
5) MongoDB
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## Generated application defaults
|
|
24
|
+
|
|
25
|
+
Generated applications include the project-root `@/` alias:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import {
|
|
29
|
+
db,
|
|
30
|
+
} from "@/lib/database";
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The generated TypeScript configuration uses `module: "ESNext"` and `moduleResolution: "Bundler"` so extensionless application aliases match BCP's bundler and development runtime resolution.
|
|
34
|
+
|
|
35
|
+
Modules that use React client hooks such as `useState` or `useEffect` must declare `"use client"` at the top of the module.
|
|
36
|
+
|
|
23
37
|
## Generated optional setup
|
|
24
38
|
|
|
25
39
|
### Tailwind CSS
|
|
@@ -27,9 +41,21 @@ Select a database:
|
|
|
27
41
|
When Tailwind is enabled, the project includes:
|
|
28
42
|
|
|
29
43
|
- `tailwindcss`
|
|
30
|
-
- `@tailwindcss/
|
|
31
|
-
- `
|
|
44
|
+
- `@tailwindcss/cli`
|
|
45
|
+
- `concurrently`
|
|
32
46
|
- `app/globals.css`
|
|
47
|
+
- a stylesheet link to `/bcp.css` in `app/layout.tsx`
|
|
48
|
+
- starter Tailwind utility classes in `app/page.tsx`
|
|
49
|
+
|
|
50
|
+
The generated npm scripts compile Tailwind directly to `public/bcp.css` before starting BCP and keep Tailwind running in watch mode during development:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
npm run css:build
|
|
54
|
+
npm run css:watch
|
|
55
|
+
npm run css:build:prod
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`npm run dev` performs an initial CSS build, then runs the Tailwind watcher and `bcp dev` together. BCP serves `/bcp.css` as a normal static asset from `public/`, avoiding an extra API route in the critical request chain. `npm run build` creates a minified stylesheet before the BCP production build.
|
|
33
59
|
|
|
34
60
|
### Database
|
|
35
61
|
|
|
@@ -41,6 +67,14 @@ The database choice adds a starter `lib/database.ts`, updates `.env.example`, an
|
|
|
41
67
|
- MongoDB: `mongodb`
|
|
42
68
|
- None: no database dependency
|
|
43
69
|
|
|
70
|
+
The generated database helper starts with:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import "bcp/server-only";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This prevents database code from being used in a page/client module graph. Query the database from an API route and call that API from client components.
|
|
77
|
+
|
|
44
78
|
The generator intentionally installs database drivers directly and does not force an ORM.
|
|
45
79
|
|
|
46
80
|
## Options
|
|
@@ -66,5 +100,5 @@ npx create-bcp-app my-app --yes
|
|
|
66
100
|
The `--bcp` option is primarily useful for prerelease and local package testing, for example:
|
|
67
101
|
|
|
68
102
|
```bash
|
|
69
|
-
npx create-bcp-app my-app --bcp file:../bcp-0.1.
|
|
103
|
+
npx create-bcp-app my-app --bcp file:../bcp-0.1.5.tgz
|
|
70
104
|
```
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-bcp-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Create a new BCP Framework application.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"bcpFrameworkPackage": "@chidchanun/bcp",
|
|
7
8
|
"bin": {
|
|
8
9
|
"create-bcp-app": "bin/create-bcp-app.mjs"
|
|
9
10
|
},
|
|
@@ -24,6 +25,5 @@
|
|
|
24
25
|
},
|
|
25
26
|
"publishConfig": {
|
|
26
27
|
"access": "public"
|
|
27
|
-
}
|
|
28
|
-
"bcpFrameworkPackage": "@chidchanun/bcp"
|
|
28
|
+
}
|
|
29
29
|
}
|
package/src/project-options.mjs
CHANGED
|
@@ -18,7 +18,9 @@ const DATABASE_PRESETS = {
|
|
|
18
18
|
env: [
|
|
19
19
|
"DATABASE_URL=mysql://root:password@localhost:3306/bcp_app",
|
|
20
20
|
],
|
|
21
|
-
source: `import
|
|
21
|
+
source: `import "bcp/server-only";
|
|
22
|
+
|
|
23
|
+
import mysql from "mysql2/promise";
|
|
22
24
|
|
|
23
25
|
const connectionString =
|
|
24
26
|
process.env.DATABASE_URL;
|
|
@@ -45,7 +47,9 @@ export const db =
|
|
|
45
47
|
env: [
|
|
46
48
|
"DATABASE_URL=postgresql://postgres:password@localhost:5432/bcp_app",
|
|
47
49
|
],
|
|
48
|
-
source: `import
|
|
50
|
+
source: `import "bcp/server-only";
|
|
51
|
+
|
|
52
|
+
import {
|
|
49
53
|
Pool,
|
|
50
54
|
} from "pg";
|
|
51
55
|
|
|
@@ -74,7 +78,9 @@ export const db =
|
|
|
74
78
|
env: [
|
|
75
79
|
"DATABASE_URL=./data/bcp.sqlite",
|
|
76
80
|
],
|
|
77
|
-
source: `import
|
|
81
|
+
source: `import "bcp/server-only";
|
|
82
|
+
|
|
83
|
+
import fs from "node:fs";
|
|
78
84
|
import path from "node:path";
|
|
79
85
|
|
|
80
86
|
import Database from "better-sqlite3";
|
|
@@ -111,7 +117,9 @@ export const db =
|
|
|
111
117
|
"DATABASE_URL=mongodb://localhost:27017",
|
|
112
118
|
"DATABASE_NAME=bcp_app",
|
|
113
119
|
],
|
|
114
|
-
source: `import
|
|
120
|
+
source: `import "bcp/server-only";
|
|
121
|
+
|
|
122
|
+
import {
|
|
115
123
|
MongoClient,
|
|
116
124
|
} from "mongodb";
|
|
117
125
|
|
|
@@ -176,34 +184,9 @@ export function applyProjectOptions({
|
|
|
176
184
|
);
|
|
177
185
|
|
|
178
186
|
if (tailwind) {
|
|
179
|
-
|
|
180
|
-
...packageJson.devDependencies,
|
|
181
|
-
tailwindcss:
|
|
182
|
-
"^4.3.3",
|
|
183
|
-
"@tailwindcss/postcss":
|
|
184
|
-
"^4.3.3",
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
writeFile(
|
|
187
|
+
configureTailwind(
|
|
188
188
|
targetDirectory,
|
|
189
|
-
|
|
190
|
-
`export default {
|
|
191
|
-
plugins: {
|
|
192
|
-
"@tailwindcss/postcss": {},
|
|
193
|
-
},
|
|
194
|
-
};
|
|
195
|
-
`
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
writeFile(
|
|
199
|
-
targetDirectory,
|
|
200
|
-
"app/globals.css",
|
|
201
|
-
`@import "tailwindcss";
|
|
202
|
-
|
|
203
|
-
@theme {
|
|
204
|
-
--font-sans: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
205
|
-
}
|
|
206
|
-
`
|
|
189
|
+
packageJson
|
|
207
190
|
);
|
|
208
191
|
}
|
|
209
192
|
|
|
@@ -245,6 +228,191 @@ export function applyProjectOptions({
|
|
|
245
228
|
};
|
|
246
229
|
}
|
|
247
230
|
|
|
231
|
+
function configureTailwind(
|
|
232
|
+
targetDirectory,
|
|
233
|
+
packageJson
|
|
234
|
+
) {
|
|
235
|
+
packageJson.devDependencies = {
|
|
236
|
+
...packageJson.devDependencies,
|
|
237
|
+
tailwindcss:
|
|
238
|
+
"^4.3.3",
|
|
239
|
+
"@tailwindcss/cli":
|
|
240
|
+
"^4.3.3",
|
|
241
|
+
concurrently:
|
|
242
|
+
"^10.0.5",
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
packageJson.scripts = {
|
|
246
|
+
...packageJson.scripts,
|
|
247
|
+
dev:
|
|
248
|
+
"npm run css:build && concurrently -k -n tailwind,bcp \"npm run css:watch\" \"bcp dev\"",
|
|
249
|
+
build:
|
|
250
|
+
"npm run css:build:prod && bcp build",
|
|
251
|
+
"css:build":
|
|
252
|
+
"tailwindcss -i ./app/globals.css -o ./public/bcp.css",
|
|
253
|
+
"css:watch":
|
|
254
|
+
"tailwindcss -i ./app/globals.css -o ./public/bcp.css --watch",
|
|
255
|
+
"css:build:prod":
|
|
256
|
+
"tailwindcss -i ./app/globals.css -o ./public/bcp.css --minify",
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
writeFile(
|
|
260
|
+
targetDirectory,
|
|
261
|
+
"app/globals.css",
|
|
262
|
+
`@import "tailwindcss" source("../");
|
|
263
|
+
|
|
264
|
+
@theme {
|
|
265
|
+
--font-sans: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
266
|
+
}
|
|
267
|
+
`
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
fs.mkdirSync(
|
|
271
|
+
path.join(
|
|
272
|
+
targetDirectory,
|
|
273
|
+
"public"
|
|
274
|
+
),
|
|
275
|
+
{
|
|
276
|
+
recursive: true,
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
injectTailwindStylesheet(
|
|
281
|
+
targetDirectory
|
|
282
|
+
);
|
|
283
|
+
applyTailwindStarterStyles(
|
|
284
|
+
targetDirectory
|
|
285
|
+
);
|
|
286
|
+
appendGitIgnore(
|
|
287
|
+
targetDirectory,
|
|
288
|
+
"public/bcp.css"
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function injectTailwindStylesheet(
|
|
293
|
+
targetDirectory
|
|
294
|
+
) {
|
|
295
|
+
const layoutFile =
|
|
296
|
+
path.join(
|
|
297
|
+
targetDirectory,
|
|
298
|
+
"app",
|
|
299
|
+
"layout.tsx"
|
|
300
|
+
);
|
|
301
|
+
const source =
|
|
302
|
+
fs.readFileSync(
|
|
303
|
+
layoutFile,
|
|
304
|
+
"utf8"
|
|
305
|
+
);
|
|
306
|
+
const rootPattern =
|
|
307
|
+
/^([ \t]*)<div>[ \t]*(\r?\n)/m;
|
|
308
|
+
const match =
|
|
309
|
+
rootPattern.exec(
|
|
310
|
+
source
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
if (!match) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
"BCP create-app could not attach the Tailwind stylesheet to app/layout.tsx."
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const indent =
|
|
320
|
+
match[1];
|
|
321
|
+
const newline =
|
|
322
|
+
match[2];
|
|
323
|
+
const childIndent =
|
|
324
|
+
`${indent} `;
|
|
325
|
+
const propertyIndent =
|
|
326
|
+
`${childIndent} `;
|
|
327
|
+
const replacement =
|
|
328
|
+
`${indent}<div>${newline}` +
|
|
329
|
+
`${childIndent}<link${newline}` +
|
|
330
|
+
`${propertyIndent}rel="stylesheet"${newline}` +
|
|
331
|
+
`${propertyIndent}href="/bcp.css"${newline}` +
|
|
332
|
+
`${childIndent}/>${newline}`;
|
|
333
|
+
|
|
334
|
+
fs.writeFileSync(
|
|
335
|
+
layoutFile,
|
|
336
|
+
source.replace(
|
|
337
|
+
rootPattern,
|
|
338
|
+
replacement
|
|
339
|
+
),
|
|
340
|
+
"utf8"
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function applyTailwindStarterStyles(
|
|
345
|
+
targetDirectory
|
|
346
|
+
) {
|
|
347
|
+
const pageFile =
|
|
348
|
+
path.join(
|
|
349
|
+
targetDirectory,
|
|
350
|
+
"app",
|
|
351
|
+
"page.tsx"
|
|
352
|
+
);
|
|
353
|
+
let source =
|
|
354
|
+
fs.readFileSync(
|
|
355
|
+
pageFile,
|
|
356
|
+
"utf8"
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
source =
|
|
360
|
+
source.replace(
|
|
361
|
+
" <section>",
|
|
362
|
+
" <section className=\"mx-auto max-w-3xl space-y-6 px-6 py-16\">"
|
|
363
|
+
);
|
|
364
|
+
source =
|
|
365
|
+
source.replace(
|
|
366
|
+
" <h1>",
|
|
367
|
+
" <h1 className=\"text-4xl font-bold tracking-tight text-slate-900\">"
|
|
368
|
+
);
|
|
369
|
+
source =
|
|
370
|
+
source.replace(
|
|
371
|
+
" <p>",
|
|
372
|
+
" <p className=\"text-lg text-slate-600\">"
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
fs.writeFileSync(
|
|
376
|
+
pageFile,
|
|
377
|
+
source,
|
|
378
|
+
"utf8"
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function appendGitIgnore(
|
|
383
|
+
targetDirectory,
|
|
384
|
+
entry
|
|
385
|
+
) {
|
|
386
|
+
const filePath =
|
|
387
|
+
path.join(
|
|
388
|
+
targetDirectory,
|
|
389
|
+
".gitignore"
|
|
390
|
+
);
|
|
391
|
+
const current =
|
|
392
|
+
fs.existsSync(
|
|
393
|
+
filePath
|
|
394
|
+
)
|
|
395
|
+
? fs.readFileSync(
|
|
396
|
+
filePath,
|
|
397
|
+
"utf8"
|
|
398
|
+
).trimEnd()
|
|
399
|
+
: "";
|
|
400
|
+
const lines =
|
|
401
|
+
new Set(
|
|
402
|
+
current
|
|
403
|
+
.split(/\r?\n/)
|
|
404
|
+
.filter(Boolean)
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
lines.add(entry);
|
|
408
|
+
|
|
409
|
+
fs.writeFileSync(
|
|
410
|
+
filePath,
|
|
411
|
+
`${Array.from(lines).join("\n")}\n`,
|
|
412
|
+
"utf8"
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
248
416
|
function appendEnvExample(
|
|
249
417
|
targetDirectory,
|
|
250
418
|
lines
|
package/template/tsconfig.json
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
|
-
"module": "
|
|
5
|
-
"moduleResolution": "
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
6
|
"jsx": "react-jsx",
|
|
7
7
|
"strict": true,
|
|
8
8
|
"noEmit": true,
|
|
9
9
|
"esModuleInterop": true,
|
|
10
10
|
"allowSyntheticDefaultImports": true,
|
|
11
11
|
"skipLibCheck": true,
|
|
12
|
+
"baseUrl": ".",
|
|
13
|
+
"paths": {
|
|
14
|
+
"@/*": [
|
|
15
|
+
"./*"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
12
18
|
"types": [
|
|
13
19
|
"node",
|
|
14
20
|
"react",
|