create-apollo-monorepo 0.9.2 → 0.9.3
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/index.mjs +182 -74
- package/package.json +2 -2
package/index.mjs
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { execSync } from "node:child_process";
|
|
18
18
|
import { randomBytes } from "node:crypto";
|
|
19
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
19
|
+
import { existsSync, mkdirSync, writeFileSync, symlinkSync, rmSync } from "node:fs";
|
|
20
20
|
import { resolve, basename } from "node:path";
|
|
21
21
|
import { createInterface } from "node:readline";
|
|
22
22
|
|
|
@@ -27,7 +27,7 @@ const BACKEND_BRANCH = "main";
|
|
|
27
27
|
const BACKEND_PATH = "apps/backend";
|
|
28
28
|
const FRONTEND_PATH = "apps/frontend";
|
|
29
29
|
const PROXY_PATH = "apps/proxy";
|
|
30
|
-
const MIN_NODE_MAJOR =
|
|
30
|
+
const MIN_NODE_MAJOR = 22;
|
|
31
31
|
|
|
32
32
|
// Default dev ports. Kept in sync with scripts/with-env.mjs and the proxy
|
|
33
33
|
// template. .env.local is the runtime source of truth — these are the
|
|
@@ -435,33 +435,7 @@ function writeRootPackageJson(targetDir, dirName) {
|
|
|
435
435
|
devDependencies: {
|
|
436
436
|
concurrently: "^9.0.0",
|
|
437
437
|
},
|
|
438
|
-
engines: { node: ">=
|
|
439
|
-
pnpm: {
|
|
440
|
-
// apollo-cms transitively pulls multiple esbuild versions (0.18, 0.25, 0.27).
|
|
441
|
-
// pnpm's binary symlink can pick the wrong platform binary for esbuild's
|
|
442
|
-
// postinstall version check, failing with "Expected X.Y.Z but got A.B.C".
|
|
443
|
-
// Allow listed packages to run their build/postinstall scripts; the rest
|
|
444
|
-
// are skipped (pnpm 10 default is empty allow-list).
|
|
445
|
-
onlyBuiltDependencies: [
|
|
446
|
-
"@parcel/watcher",
|
|
447
|
-
"@rolldown/binding-darwin-arm64",
|
|
448
|
-
"@rolldown/binding-linux-arm64-gnu",
|
|
449
|
-
"@rolldown/binding-linux-x64-gnu",
|
|
450
|
-
"@sentry/cli",
|
|
451
|
-
"@swc/core",
|
|
452
|
-
"@swc/core-darwin-arm64",
|
|
453
|
-
"@swc/core-darwin-x64",
|
|
454
|
-
"@swc/core-linux-arm64-gnu",
|
|
455
|
-
"@swc/core-linux-x64-gnu",
|
|
456
|
-
"better-sqlite3",
|
|
457
|
-
"core-js",
|
|
458
|
-
"core-js-pure",
|
|
459
|
-
"esbuild",
|
|
460
|
-
"msw",
|
|
461
|
-
"sharp",
|
|
462
|
-
"unrs-resolver",
|
|
463
|
-
],
|
|
464
|
-
},
|
|
438
|
+
engines: { node: ">=22", pnpm: ">=10" },
|
|
465
439
|
};
|
|
466
440
|
writeFileSync(resolve(targetDir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
|
|
467
441
|
|
|
@@ -475,17 +449,77 @@ function writeRootPackageJson(targetDir, dirName) {
|
|
|
475
449
|
"strict-peer-dependencies=false",
|
|
476
450
|
"public-hoist-pattern[]=*esbuild*",
|
|
477
451
|
"public-hoist-pattern[]=*types*",
|
|
452
|
+
// Next.js 16's instrumentation hook (used by Sentry / OpenTelemetry
|
|
453
|
+
// shipped via apollo-cms) loads require-in-the-middle / import-in-the-middle
|
|
454
|
+
// at runtime via a bare require. Under pnpm's strict node_modules these
|
|
455
|
+
// sit deep inside .pnpm/ and the resolver can't see them — Next then
|
|
456
|
+
// crashes on boot with "Failed to load external module require-in-the-middle".
|
|
457
|
+
// Hoisting them (plus their `shimmer` dep) to the root node_modules fixes it.
|
|
458
|
+
"public-hoist-pattern[]=*require-in-the-middle*",
|
|
459
|
+
"public-hoist-pattern[]=*import-in-the-middle*",
|
|
460
|
+
"public-hoist-pattern[]=*shimmer*",
|
|
478
461
|
"shell-emulator=true",
|
|
479
462
|
"",
|
|
480
463
|
].join("\n"),
|
|
481
464
|
);
|
|
482
465
|
}
|
|
483
466
|
|
|
467
|
+
// Link an app's .env.local to the monorepo root .env.local so the root file
|
|
468
|
+
// stays the single source of truth. Next.js only reads .env.local from its
|
|
469
|
+
// own CWD, so this symlink lets `cd apps/<app> && next dev|build` see the
|
|
470
|
+
// shared config. Falls back to a regular copy (with a warning) on platforms
|
|
471
|
+
// where symlink creation requires elevation (Windows non-admin).
|
|
472
|
+
function linkRootEnvLocal(targetDir, appRelPath, fallbackLines) {
|
|
473
|
+
const envPath = resolve(targetDir, appRelPath, ".env.local");
|
|
474
|
+
// appRelPath is `apps/<name>` (2 segments deep) → `../../.env.local`.
|
|
475
|
+
const depth = appRelPath.split("/").filter(Boolean).length;
|
|
476
|
+
const linkTarget = "../".repeat(depth) + ".env.local";
|
|
477
|
+
if (existsSync(envPath)) rmSync(envPath);
|
|
478
|
+
try {
|
|
479
|
+
symlinkSync(linkTarget, envPath);
|
|
480
|
+
success(`${appRelPath}/.env.local → ${linkTarget} (symlink)`);
|
|
481
|
+
} catch {
|
|
482
|
+
writeFileSync(envPath, [...fallbackLines, ""].join("\n"));
|
|
483
|
+
warn(
|
|
484
|
+
`symlink failed — wrote a copy at ${appRelPath}/.env.local (keep it in sync with the root file manually).`,
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
484
489
|
function writePnpmWorkspace(targetDir) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
490
|
+
// pnpm 10 reads `onlyBuiltDependencies` from pnpm-workspace.yaml (the
|
|
491
|
+
// package.json#pnpm location is deprecated for workspaces). apollo-cms
|
|
492
|
+
// transitively pulls multiple esbuild versions (0.18, 0.25, 0.27); pnpm's
|
|
493
|
+
// binary symlink can pick the wrong platform binary for esbuild's
|
|
494
|
+
// postinstall version check, failing with "Expected X.Y.Z but got A.B.C".
|
|
495
|
+
// Allow listed packages to run their build/postinstall scripts; the rest
|
|
496
|
+
// are skipped (pnpm 10 default is empty allow-list).
|
|
497
|
+
const yaml = [
|
|
498
|
+
"packages:",
|
|
499
|
+
" - 'apps/*'",
|
|
500
|
+
" - 'apps/cms-plugins/*'",
|
|
501
|
+
"",
|
|
502
|
+
"onlyBuiltDependencies:",
|
|
503
|
+
" - '@parcel/watcher'",
|
|
504
|
+
" - '@rolldown/binding-darwin-arm64'",
|
|
505
|
+
" - '@rolldown/binding-linux-arm64-gnu'",
|
|
506
|
+
" - '@rolldown/binding-linux-x64-gnu'",
|
|
507
|
+
" - '@sentry/cli'",
|
|
508
|
+
" - '@swc/core'",
|
|
509
|
+
" - '@swc/core-darwin-arm64'",
|
|
510
|
+
" - '@swc/core-darwin-x64'",
|
|
511
|
+
" - '@swc/core-linux-arm64-gnu'",
|
|
512
|
+
" - '@swc/core-linux-x64-gnu'",
|
|
513
|
+
" - 'better-sqlite3'",
|
|
514
|
+
" - 'core-js'",
|
|
515
|
+
" - 'core-js-pure'",
|
|
516
|
+
" - 'esbuild'",
|
|
517
|
+
" - 'msw'",
|
|
518
|
+
" - 'sharp'",
|
|
519
|
+
" - 'unrs-resolver'",
|
|
520
|
+
"",
|
|
521
|
+
].join("\n");
|
|
522
|
+
writeFileSync(resolve(targetDir, "pnpm-workspace.yaml"), yaml);
|
|
489
523
|
}
|
|
490
524
|
|
|
491
525
|
// Single-origin nginx reference. Only emitted when adminPrefix is set, since
|
|
@@ -812,7 +846,7 @@ function parseTarget(input) {
|
|
|
812
846
|
scripts: {
|
|
813
847
|
start: "node server.mjs",
|
|
814
848
|
},
|
|
815
|
-
engines: { node: ">=
|
|
849
|
+
engines: { node: ">=22" },
|
|
816
850
|
};
|
|
817
851
|
writeFileSync(resolve(dir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
|
|
818
852
|
|
|
@@ -899,7 +933,7 @@ function writeRootGitignore(targetDir) {
|
|
|
899
933
|
writeFileSync(resolve(targetDir, ".gitignore"), ignore);
|
|
900
934
|
}
|
|
901
935
|
|
|
902
|
-
function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecret, adminPrefix, backendInternalUrl }) {
|
|
936
|
+
function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecret, adminPrefix, backendInternalUrl, pm2Namespace }) {
|
|
903
937
|
const header = adminPrefix
|
|
904
938
|
? [
|
|
905
939
|
"# Single-origin monorepo dev env",
|
|
@@ -949,6 +983,10 @@ function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecre
|
|
|
949
983
|
`APOLLO_ASSET_PREFIX=${adminPrefix}`,
|
|
950
984
|
"# Project-specific plugins — keeps the apollo-cms submodule clean.",
|
|
951
985
|
`APOLLO_EXTRA_PLUGINS_DIR=../cms-plugins`,
|
|
986
|
+
"# PM2 namespace — groups this project's processes so you can",
|
|
987
|
+
"# `pm2 stop <namespace>` / `pm2 restart <namespace>` independently of",
|
|
988
|
+
"# other projects on the same host. Consumed by ecosystem.config.cjs.",
|
|
989
|
+
`PM2_NAMESPACE=${pm2Namespace}`,
|
|
952
990
|
"",
|
|
953
991
|
"# ── Frontend (apps/frontend) ─────────────────────────────────────",
|
|
954
992
|
"# Where the frontend's rewrites point internally. In dev, leave blank",
|
|
@@ -962,6 +1000,10 @@ function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecre
|
|
|
962
1000
|
"# ── Backend (apps/backend) ───────────────────────────────────────",
|
|
963
1001
|
"# Project-specific plugins — keeps the apollo-cms submodule clean.",
|
|
964
1002
|
`APOLLO_EXTRA_PLUGINS_DIR=../cms-plugins`,
|
|
1003
|
+
"# PM2 namespace — groups this project's processes so you can",
|
|
1004
|
+
"# `pm2 stop <namespace>` / `pm2 restart <namespace>` independently of",
|
|
1005
|
+
"# other projects on the same host. Consumed by ecosystem.config.cjs.",
|
|
1006
|
+
`PM2_NAMESPACE=${pm2Namespace}`,
|
|
965
1007
|
"",
|
|
966
1008
|
"# ── Frontend (apps/frontend) ─────────────────────────────────────",
|
|
967
1009
|
`NEXT_PUBLIC_BACKEND_URL=${siteUrl}`,
|
|
@@ -1488,55 +1530,111 @@ console.log("✓ env check passed");
|
|
|
1488
1530
|
// since Next.js handles that internally and the proxy is single-threaded by design).
|
|
1489
1531
|
function writePm2Config(targetDir, dirName, adminPrefix) {
|
|
1490
1532
|
const singleOrigin = !!adminPrefix;
|
|
1533
|
+
// The proxy `env` block conditionally includes ADMIN_PREFIX in single-origin
|
|
1534
|
+
// mode. Built outside the template so we don't emit a stray comma or blank line.
|
|
1535
|
+
const proxyEnv = [
|
|
1536
|
+
"NODE_ENV: 'production',",
|
|
1537
|
+
"PROXY_PORT,",
|
|
1538
|
+
"FRONTEND_PORT,",
|
|
1539
|
+
"BACKEND_PORT,",
|
|
1540
|
+
...(singleOrigin ? [`ADMIN_PREFIX: '${adminPrefix}',`] : []),
|
|
1541
|
+
].map((l) => " " + l).join("\n");
|
|
1542
|
+
|
|
1491
1543
|
const config = `// PM2 ecosystem config for ${dirName}.
|
|
1544
|
+
//
|
|
1545
|
+
// Loads .env.local at the top so PM2 picks up PROXY_PORT / FRONTEND_PORT /
|
|
1546
|
+
// BACKEND_PORT / PM2_NAMESPACE without a shell wrapper. The .env.local file
|
|
1547
|
+
// is the single source of truth — edit ports there, not here.
|
|
1548
|
+
//
|
|
1492
1549
|
// Usage:
|
|
1493
1550
|
// pnpm install
|
|
1494
1551
|
// pnpm backend:upgrade
|
|
1495
1552
|
// pnpm build
|
|
1496
|
-
// pm2 start ecosystem.config.cjs # FE + BE
|
|
1497
|
-
// pm2 start ecosystem.config.cjs --only proxy #
|
|
1553
|
+
// pm2 start ecosystem.config.cjs # FE + BE + proxy + cron
|
|
1554
|
+
// pm2 start ecosystem.config.cjs --only proxy # only the reverse proxy
|
|
1498
1555
|
// pm2 start ecosystem.config.cjs --only cron # self-hosted cron fallback
|
|
1556
|
+
// pm2 stop \${PM2_NAMESPACE} # stop everything in this project
|
|
1499
1557
|
// pm2 save && pm2 startup # persist across reboots
|
|
1500
1558
|
|
|
1559
|
+
const fs = require('fs');
|
|
1560
|
+
const path = require('path');
|
|
1561
|
+
|
|
1562
|
+
// Inline .env.local parser. Kept tiny (no dotenv dep) so the ecosystem file
|
|
1563
|
+
// stays runnable before \`pnpm install\` finishes.
|
|
1564
|
+
const envPath = path.resolve(__dirname, '.env.local');
|
|
1565
|
+
if (fs.existsSync(envPath)) {
|
|
1566
|
+
for (const line of fs.readFileSync(envPath, 'utf8').split('\\n')) {
|
|
1567
|
+
const m = line.match(/^\\s*([A-Z0-9_]+)\\s*=\\s*(.*?)\\s*$/i);
|
|
1568
|
+
if (!m) continue;
|
|
1569
|
+
const k = m[1];
|
|
1570
|
+
let v = m[2];
|
|
1571
|
+
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1);
|
|
1572
|
+
if (process.env[k] === undefined) process.env[k] = v;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
const NAMESPACE = process.env.PM2_NAMESPACE || '${dirName}';
|
|
1577
|
+
const FRONTEND_PORT = Number(process.env.FRONTEND_PORT) || 3001;
|
|
1578
|
+
const BACKEND_PORT = Number(process.env.BACKEND_PORT) || 3002;
|
|
1579
|
+
const PROXY_PORT = Number(process.env.PROXY_PORT) || 3030;
|
|
1580
|
+
|
|
1581
|
+
// Backend's internal URL (loopback). Cron MUST target this, never the proxy or
|
|
1582
|
+
// frontend — going through the FE just adds a failure mode (HTML error → JSON
|
|
1583
|
+
// parse blowup in dev-cron.ts).
|
|
1584
|
+
const BACKEND_INTERNAL_URL = process.env.BACKEND_INTERNAL_URL || \`http://127.0.0.1:\${BACKEND_PORT}\`;
|
|
1585
|
+
|
|
1501
1586
|
module.exports = {
|
|
1502
1587
|
apps: [
|
|
1503
1588
|
{
|
|
1504
|
-
name:
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1589
|
+
name: \`frontend:\${FRONTEND_PORT}\`,
|
|
1590
|
+
namespace: NAMESPACE,
|
|
1591
|
+
cwd: './apps/frontend',
|
|
1592
|
+
script: 'node_modules/next/dist/bin/next',
|
|
1593
|
+
args: 'start',
|
|
1594
|
+
env: {
|
|
1595
|
+
NODE_ENV: 'production',
|
|
1596
|
+
PORT: FRONTEND_PORT,
|
|
1597
|
+
// Next.js rewrites read this at request time. Without it the FE
|
|
1598
|
+
// falls back to http://localhost:3000 and every /admin, /api, and
|
|
1599
|
+
// /uploads request returns ECONNREFUSED.
|
|
1600
|
+
BACKEND_INTERNAL_URL,
|
|
1601
|
+
},
|
|
1602
|
+
max_memory_restart: '1G',
|
|
1510
1603
|
autorestart: true,
|
|
1511
1604
|
},
|
|
1512
1605
|
{
|
|
1513
|
-
name:
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1606
|
+
name: \`backend:\${BACKEND_PORT}\`,
|
|
1607
|
+
namespace: NAMESPACE,
|
|
1608
|
+
cwd: './apps/backend',
|
|
1609
|
+
script: 'node_modules/next/dist/bin/next',
|
|
1610
|
+
args: 'start',
|
|
1611
|
+
env: { NODE_ENV: 'production', PORT: BACKEND_PORT },
|
|
1612
|
+
max_memory_restart: '1G',
|
|
1519
1613
|
autorestart: true,
|
|
1520
1614
|
},
|
|
1521
1615
|
{
|
|
1522
|
-
name:
|
|
1523
|
-
|
|
1616
|
+
name: \`proxy:\${PROXY_PORT}\`,
|
|
1617
|
+
namespace: NAMESPACE,
|
|
1618
|
+
script: './apps/proxy/server.mjs',
|
|
1524
1619
|
env: {
|
|
1525
|
-
|
|
1526
|
-
PROXY_PORT: Number(process.env.PROXY_PORT) || 3030,
|
|
1527
|
-
FRONTEND_PORT: Number(process.env.FRONTEND_PORT) || 3001,
|
|
1528
|
-
BACKEND_PORT: Number(process.env.BACKEND_PORT) || 3002,
|
|
1529
|
-
${singleOrigin ? `ADMIN_PREFIX: "${adminPrefix}",` : ""}
|
|
1620
|
+
${proxyEnv}
|
|
1530
1621
|
},
|
|
1531
|
-
max_memory_restart:
|
|
1622
|
+
max_memory_restart: '256M',
|
|
1532
1623
|
autorestart: true,
|
|
1533
1624
|
},
|
|
1534
1625
|
{
|
|
1535
|
-
name:
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1626
|
+
name: 'cron',
|
|
1627
|
+
namespace: NAMESPACE,
|
|
1628
|
+
cwd: './apps/backend',
|
|
1629
|
+
script: 'scripts/dev-cron.ts',
|
|
1630
|
+
interpreter: 'bun',
|
|
1631
|
+
env: {
|
|
1632
|
+
NODE_ENV: 'production',
|
|
1633
|
+
// dev-cron.ts derives its target from NEXT_PUBLIC_SITE_URL. Override
|
|
1634
|
+
// it to the backend loopback so cron skips the FE/proxy entirely.
|
|
1635
|
+
NEXT_PUBLIC_SITE_URL: BACKEND_INTERNAL_URL,
|
|
1636
|
+
CRON_SECRET: process.env.CRON_SECRET,
|
|
1637
|
+
},
|
|
1540
1638
|
autorestart: true,
|
|
1541
1639
|
},
|
|
1542
1640
|
],
|
|
@@ -1815,12 +1913,18 @@ The installer scaffolds \`ecosystem.config.cjs\`. To supervise everything:
|
|
|
1815
1913
|
|
|
1816
1914
|
\`\`\`bash
|
|
1817
1915
|
pm2 start ecosystem.config.cjs # FE + BE + proxy + cron (all four)
|
|
1818
|
-
pm2 start ecosystem.config.cjs --only
|
|
1916
|
+
pm2 start ecosystem.config.cjs --only proxy # only the reverse proxy
|
|
1819
1917
|
pm2 save && pm2 startup # persist across reboots
|
|
1820
|
-
pm2 logs
|
|
1821
|
-
pm2 reload
|
|
1918
|
+
pm2 logs \${PM2_NAMESPACE:-${dirName}} # tail just this project's logs
|
|
1919
|
+
pm2 reload \${PM2_NAMESPACE:-${dirName}} # zero-downtime restart (namespace-scoped)
|
|
1920
|
+
pm2 stop \${PM2_NAMESPACE:-${dirName}} # stop only this project
|
|
1822
1921
|
\`\`\`
|
|
1823
1922
|
|
|
1923
|
+
All four processes are grouped under the \`PM2_NAMESPACE\` set in \`.env.local\`
|
|
1924
|
+
(defaults to \`${dirName}\`), so namespace commands target only this project
|
|
1925
|
+
even when other PM2 apps share the host. Process names embed the bound port
|
|
1926
|
+
(\`frontend:3001\`, \`backend:3002\`, \`proxy:3030\`) for quick \`pm2 ls\` triage.
|
|
1927
|
+
|
|
1824
1928
|
The proxy and cron processes can be omitted with \`--only\` if you front the
|
|
1825
1929
|
apps with nginx/Caddy or use platform cron (system cron, k8s CronJob).
|
|
1826
1930
|
|
|
@@ -1944,7 +2048,7 @@ async function main() {
|
|
|
1944
2048
|
writeRootPackageJson(targetDir, dirName);
|
|
1945
2049
|
writePnpmWorkspace(targetDir);
|
|
1946
2050
|
writeRootGitignore(targetDir);
|
|
1947
|
-
writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecret, adminPrefix, backendInternalUrl });
|
|
2051
|
+
writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecret, adminPrefix, backendInternalUrl, pm2Namespace: dirName });
|
|
1948
2052
|
writeReadme(targetDir, dirName, frontendName, adminPrefix);
|
|
1949
2053
|
writeClaudeMd(targetDir, adminPrefix);
|
|
1950
2054
|
if (adminPrefix) writeNginxSample(targetDir, adminPrefix);
|
|
@@ -1995,23 +2099,27 @@ async function main() {
|
|
|
1995
2099
|
);
|
|
1996
2100
|
}
|
|
1997
2101
|
|
|
1998
|
-
|
|
1999
|
-
const backendEnvLines = [
|
|
2102
|
+
const backendFallback = [
|
|
2000
2103
|
`DATABASE_URL=${dbUrl}`,
|
|
2001
2104
|
`APOLLO_SECRET=${authSecret}`,
|
|
2002
2105
|
`CRON_SECRET=${cronSecret}`,
|
|
2003
2106
|
`NEXT_PUBLIC_SITE_URL=${siteUrl}`,
|
|
2004
2107
|
`NEXT_PUBLIC_DEFAULT_LOCALE=${locale}`,
|
|
2005
2108
|
`APOLLO_EXTRA_PLUGINS_DIR=../cms-plugins`,
|
|
2109
|
+
`PM2_NAMESPACE=${dirName}`,
|
|
2006
2110
|
];
|
|
2007
|
-
if (adminPrefix) {
|
|
2008
|
-
|
|
2009
|
-
}
|
|
2010
|
-
backendEnvLines.push("");
|
|
2011
|
-
writeFileSync(resolve(targetDir, BACKEND_PATH, ".env.local"), backendEnvLines.join("\n"));
|
|
2012
|
-
success("apps/backend/.env.local");
|
|
2111
|
+
if (adminPrefix) backendFallback.push(`APOLLO_ASSET_PREFIX=${adminPrefix}`);
|
|
2112
|
+
linkRootEnvLocal(targetDir, BACKEND_PATH, backendFallback);
|
|
2013
2113
|
}
|
|
2014
2114
|
|
|
2115
|
+
// Frontend gets the same treatment — Next.js running in apps/frontend
|
|
2116
|
+
// can't see the root file otherwise, and next.config.ts references
|
|
2117
|
+
// BACKEND_INTERNAL_URL for the rewrites destination.
|
|
2118
|
+
const frontendFallback = adminPrefix
|
|
2119
|
+
? [`BACKEND_INTERNAL_URL=${backendInternalUrl}`]
|
|
2120
|
+
: [`NEXT_PUBLIC_BACKEND_URL=${siteUrl}`];
|
|
2121
|
+
linkRootEnvLocal(targetDir, FRONTEND_PATH, frontendFallback);
|
|
2122
|
+
|
|
2015
2123
|
// ── Step 7: Install ──
|
|
2016
2124
|
if (flags.skipInstall) {
|
|
2017
2125
|
step(7, "Skipping dependency installation (--skip-install)");
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-apollo-monorepo",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Scaffold a monorepo with a frontend app and Apollo CMS as a git submodule backend (single-origin via Next.js rewrites + assetPrefix)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-apollo-monorepo": "index.mjs"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=
|
|
10
|
+
"node": ">=22"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
13
|
"apollo",
|