create-bcp-app 0.1.3 → 0.1.4

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 CHANGED
@@ -27,9 +27,22 @@ Select a database:
27
27
  When Tailwind is enabled, the project includes:
28
28
 
29
29
  - `tailwindcss`
30
- - `@tailwindcss/postcss`
31
- - `postcss.config.mjs`
30
+ - `@tailwindcss/cli`
31
+ - `concurrently`
32
32
  - `app/globals.css`
33
+ - `app/api/bcp-styles/route.ts`
34
+ - a stylesheet link in `app/layout.tsx`
35
+ - starter Tailwind utility classes in `app/page.tsx`
36
+
37
+ The generated npm scripts compile Tailwind before starting BCP and keep Tailwind running in watch mode during development:
38
+
39
+ ```text
40
+ npm run css:build
41
+ npm run css:watch
42
+ npm run css:build:prod
43
+ ```
44
+
45
+ `npm run dev` performs an initial CSS build, then runs the Tailwind watcher and `bcp dev` together. `npm run build` creates a minified stylesheet before the BCP production build.
33
46
 
34
47
  ### Database
35
48
 
@@ -66,5 +79,5 @@ npx create-bcp-app my-app --yes
66
79
  The `--bcp` option is primarily useful for prerelease and local package testing, for example:
67
80
 
68
81
  ```bash
69
- npx create-bcp-app my-app --bcp file:../bcp-0.1.2.tgz
82
+ npx create-bcp-app my-app --bcp file:../bcp-0.1.4.tgz
70
83
  ```
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "create-bcp-app",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
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
  }
@@ -176,34 +176,9 @@ export function applyProjectOptions({
176
176
  );
177
177
 
178
178
  if (tailwind) {
179
- packageJson.devDependencies = {
180
- ...packageJson.devDependencies,
181
- tailwindcss:
182
- "^4.3.3",
183
- "@tailwindcss/postcss":
184
- "^4.3.3",
185
- };
186
-
187
- writeFile(
179
+ configureTailwind(
188
180
  targetDirectory,
189
- "postcss.config.mjs",
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
- `
181
+ packageJson
207
182
  );
208
183
  }
209
184
 
@@ -245,6 +220,241 @@ export function applyProjectOptions({
245
220
  };
246
221
  }
247
222
 
223
+ function configureTailwind(
224
+ targetDirectory,
225
+ packageJson
226
+ ) {
227
+ packageJson.devDependencies = {
228
+ ...packageJson.devDependencies,
229
+ tailwindcss:
230
+ "^4.3.3",
231
+ "@tailwindcss/cli":
232
+ "^4.3.3",
233
+ concurrently:
234
+ "^10.0.5",
235
+ };
236
+
237
+ packageJson.scripts = {
238
+ ...packageJson.scripts,
239
+ dev:
240
+ "npm run css:build && concurrently -k -n tailwind,bcp \"npm run css:watch\" \"bcp dev\"",
241
+ build:
242
+ "npm run css:build:prod && bcp build",
243
+ "css:build":
244
+ "tailwindcss -i ./app/globals.css -o ./public/bcp.css",
245
+ "css:watch":
246
+ "tailwindcss -i ./app/globals.css -o ./public/bcp.css --watch",
247
+ "css:build:prod":
248
+ "tailwindcss -i ./app/globals.css -o ./public/bcp.css --minify",
249
+ };
250
+
251
+ writeFile(
252
+ targetDirectory,
253
+ "app/globals.css",
254
+ `@import "tailwindcss" source("../");
255
+
256
+ @theme {
257
+ --font-sans: Inter, ui-sans-serif, system-ui, sans-serif;
258
+ }
259
+ `
260
+ );
261
+
262
+ writeFile(
263
+ targetDirectory,
264
+ "app/api/bcp-styles/route.ts",
265
+ `import fs from "node:fs/promises";
266
+ import path from "node:path";
267
+
268
+ export async function GET() {
269
+ const stylesheet =
270
+ path.join(
271
+ process.cwd(),
272
+ "public",
273
+ "bcp.css"
274
+ );
275
+
276
+ try {
277
+ const css =
278
+ await fs.readFile(
279
+ stylesheet,
280
+ "utf8"
281
+ );
282
+
283
+ return new Response(
284
+ css,
285
+ {
286
+ headers: {
287
+ "Content-Type":
288
+ "text/css; charset=utf-8",
289
+ "Cache-Control":
290
+ "no-store, max-age=0",
291
+ },
292
+ }
293
+ );
294
+ } catch {
295
+ return new Response(
296
+ "/* BCP Tailwind stylesheet has not been built yet. */",
297
+ {
298
+ status: 503,
299
+ headers: {
300
+ "Content-Type":
301
+ "text/css; charset=utf-8",
302
+ "Cache-Control":
303
+ "no-store, max-age=0",
304
+ },
305
+ }
306
+ );
307
+ }
308
+ }
309
+ `
310
+ );
311
+
312
+ fs.mkdirSync(
313
+ path.join(
314
+ targetDirectory,
315
+ "public"
316
+ ),
317
+ {
318
+ recursive: true,
319
+ }
320
+ );
321
+
322
+ injectTailwindStylesheet(
323
+ targetDirectory
324
+ );
325
+ applyTailwindStarterStyles(
326
+ targetDirectory
327
+ );
328
+ appendGitIgnore(
329
+ targetDirectory,
330
+ "public/bcp.css"
331
+ );
332
+ }
333
+
334
+ function injectTailwindStylesheet(
335
+ targetDirectory
336
+ ) {
337
+ const layoutFile =
338
+ path.join(
339
+ targetDirectory,
340
+ "app",
341
+ "layout.tsx"
342
+ );
343
+ const source =
344
+ fs.readFileSync(
345
+ layoutFile,
346
+ "utf8"
347
+ );
348
+ const rootPattern =
349
+ /^([ \t]*)<div>[ \t]*(\r?\n)/m;
350
+ const match =
351
+ rootPattern.exec(
352
+ source
353
+ );
354
+
355
+ if (!match) {
356
+ throw new Error(
357
+ "BCP create-app could not attach the Tailwind stylesheet to app/layout.tsx."
358
+ );
359
+ }
360
+
361
+ const indent =
362
+ match[1];
363
+ const newline =
364
+ match[2];
365
+ const childIndent =
366
+ `${indent} `;
367
+ const propertyIndent =
368
+ `${childIndent} `;
369
+ const replacement =
370
+ `${indent}<div>${newline}` +
371
+ `${childIndent}<link${newline}` +
372
+ `${propertyIndent}rel="stylesheet"${newline}` +
373
+ `${propertyIndent}href="/api/bcp-styles"${newline}` +
374
+ `${childIndent}/>${newline}`;
375
+
376
+ fs.writeFileSync(
377
+ layoutFile,
378
+ source.replace(
379
+ rootPattern,
380
+ replacement
381
+ ),
382
+ "utf8"
383
+ );
384
+ }
385
+
386
+ function applyTailwindStarterStyles(
387
+ targetDirectory
388
+ ) {
389
+ const pageFile =
390
+ path.join(
391
+ targetDirectory,
392
+ "app",
393
+ "page.tsx"
394
+ );
395
+ let source =
396
+ fs.readFileSync(
397
+ pageFile,
398
+ "utf8"
399
+ );
400
+
401
+ source =
402
+ source.replace(
403
+ " <section>",
404
+ " <section className=\"mx-auto max-w-3xl space-y-6 px-6 py-16\">"
405
+ );
406
+ source =
407
+ source.replace(
408
+ " <h1>",
409
+ " <h1 className=\"text-4xl font-bold tracking-tight text-slate-900\">"
410
+ );
411
+ source =
412
+ source.replace(
413
+ " <p>",
414
+ " <p className=\"text-lg text-slate-600\">"
415
+ );
416
+
417
+ fs.writeFileSync(
418
+ pageFile,
419
+ source,
420
+ "utf8"
421
+ );
422
+ }
423
+
424
+ function appendGitIgnore(
425
+ targetDirectory,
426
+ entry
427
+ ) {
428
+ const filePath =
429
+ path.join(
430
+ targetDirectory,
431
+ ".gitignore"
432
+ );
433
+ const current =
434
+ fs.existsSync(
435
+ filePath
436
+ )
437
+ ? fs.readFileSync(
438
+ filePath,
439
+ "utf8"
440
+ ).trimEnd()
441
+ : "";
442
+ const lines =
443
+ new Set(
444
+ current
445
+ .split(/\r?\n/)
446
+ .filter(Boolean)
447
+ );
448
+
449
+ lines.add(entry);
450
+
451
+ fs.writeFileSync(
452
+ filePath,
453
+ `${Array.from(lines).join("\n")}\n`,
454
+ "utf8"
455
+ );
456
+ }
457
+
248
458
  function appendEnvExample(
249
459
  targetDirectory,
250
460
  lines