mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
add nuxt and expo with orpc
This commit is contained in:
@@ -10,8 +10,9 @@ import type { ProjectConfig } from "../types";
|
||||
export async function setupAddons(config: ProjectConfig) {
|
||||
const { projectName, addons, frontend } = config;
|
||||
const projectDir = path.resolve(process.cwd(), projectName);
|
||||
const hasWebFrontend =
|
||||
const hasReactWebFrontend =
|
||||
frontend.includes("react-router") || frontend.includes("tanstack-router");
|
||||
const hasNuxtFrontend = frontend.includes("nuxt");
|
||||
|
||||
if (addons.includes("turborepo")) {
|
||||
await addPackageDependency({
|
||||
@@ -20,10 +21,10 @@ export async function setupAddons(config: ProjectConfig) {
|
||||
});
|
||||
}
|
||||
|
||||
if (addons.includes("pwa") && hasWebFrontend) {
|
||||
if (addons.includes("pwa") && hasReactWebFrontend) {
|
||||
await setupPwa(projectDir, frontend);
|
||||
}
|
||||
if (addons.includes("tauri") && hasWebFrontend) {
|
||||
if (addons.includes("tauri") && (hasReactWebFrontend || hasNuxtFrontend)) {
|
||||
await setupTauri(config);
|
||||
}
|
||||
if (addons.includes("biome")) {
|
||||
@@ -89,6 +90,11 @@ async function setupHusky(projectDir: string) {
|
||||
}
|
||||
|
||||
async function setupPwa(projectDir: string, frontends: ProjectFrontend[]) {
|
||||
const isCompatibleFrontend = frontends.some((f) =>
|
||||
["react-router", "tanstack-router"].includes(f),
|
||||
);
|
||||
if (!isCompatibleFrontend) return;
|
||||
|
||||
const clientPackageDir = getWebAppDir(projectDir, frontends);
|
||||
|
||||
if (!(await fs.pathExists(clientPackageDir))) {
|
||||
|
||||
@@ -4,39 +4,84 @@ import type { ProjectConfig } from "../types";
|
||||
import { addPackageDependency } from "../utils/add-package-deps";
|
||||
|
||||
export async function setupApi(config: ProjectConfig): Promise<void> {
|
||||
const { api, projectName } = config;
|
||||
const { api, projectName, frontend } = config;
|
||||
const projectDir = path.resolve(process.cwd(), projectName);
|
||||
const webDir = path.join(projectDir, "apps/web");
|
||||
const serverDir = path.join(projectDir, "apps/server");
|
||||
const webDirExists = await fs.pathExists(webDir);
|
||||
const hasReactWeb = frontend.some((f) =>
|
||||
["tanstack-router", "react-router", "tanstack-start", "next"].includes(f),
|
||||
);
|
||||
const hasNuxtWeb = frontend.includes("nuxt");
|
||||
|
||||
if (api === "orpc") {
|
||||
if (webDirExists) {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@orpc/react-query", "@orpc/server", "@orpc/client"],
|
||||
projectDir: webDir,
|
||||
});
|
||||
}
|
||||
await addPackageDependency({
|
||||
dependencies: ["@orpc/server", "@orpc/client"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
|
||||
if (api === "trpc") {
|
||||
if (webDirExists) {
|
||||
await addPackageDependency({
|
||||
dependencies: [
|
||||
"@trpc/tanstack-react-query",
|
||||
"@trpc/server",
|
||||
"@trpc/client",
|
||||
],
|
||||
projectDir: webDir,
|
||||
});
|
||||
}
|
||||
} else if (api === "trpc") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@trpc/server", "@trpc/client"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
if (config.backend === "hono") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@hono/trpc-server"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
} else if (config.backend === "elysia") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@elysiajs/trpc"],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (webDirExists) {
|
||||
if (hasReactWeb) {
|
||||
if (api === "orpc") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@orpc/react-query", "@orpc/client", "@orpc/server"],
|
||||
projectDir: webDir,
|
||||
});
|
||||
} else if (api === "trpc") {
|
||||
await addPackageDependency({
|
||||
dependencies: [
|
||||
"@trpc/tanstack-react-query",
|
||||
"@trpc/client",
|
||||
"@trpc/server",
|
||||
],
|
||||
projectDir: webDir,
|
||||
});
|
||||
}
|
||||
} else if (hasNuxtWeb) {
|
||||
if (api === "orpc") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@orpc/vue-query", "@orpc/client", "@orpc/server"],
|
||||
projectDir: webDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frontend.includes("native")) {
|
||||
const nativeDir = path.join(projectDir, "apps/native");
|
||||
if (await fs.pathExists(nativeDir)) {
|
||||
if (api === "trpc") {
|
||||
await addPackageDependency({
|
||||
dependencies: [
|
||||
"@trpc/tanstack-react-query",
|
||||
"@trpc/client",
|
||||
"@trpc/server",
|
||||
],
|
||||
projectDir: nativeDir,
|
||||
});
|
||||
} else if (api === "orpc") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["@orpc/react-query", "@orpc/client", "@orpc/server"],
|
||||
projectDir: nativeDir,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,15 @@ export async function setupAuth(config: ProjectConfig): Promise<void> {
|
||||
projectDir: serverDir,
|
||||
});
|
||||
|
||||
const hasWebFrontend =
|
||||
frontend.includes("react-router") ||
|
||||
frontend.includes("tanstack-router") ||
|
||||
frontend.includes("tanstack-start") ||
|
||||
frontend.includes("next");
|
||||
const hasWebFrontend = frontend.some((f) =>
|
||||
[
|
||||
"react-router",
|
||||
"tanstack-router",
|
||||
"tanstack-start",
|
||||
"next",
|
||||
"nuxt",
|
||||
].includes(f),
|
||||
);
|
||||
|
||||
if (hasWebFrontend && clientDirExists) {
|
||||
await addPackageDependency({
|
||||
|
||||
@@ -17,7 +17,6 @@ import { initializeGit, updatePackageConfigurations } from "./project-config";
|
||||
import { setupRuntime } from "./runtime-setup";
|
||||
import {
|
||||
copyBaseTemplate,
|
||||
fixGitignoreFiles,
|
||||
handleExtras,
|
||||
setupAddonsTemplate,
|
||||
setupAuthTemplate,
|
||||
@@ -70,8 +69,6 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
||||
|
||||
await initializeGit(projectDir, options.git);
|
||||
|
||||
await fixGitignoreFiles(projectDir, options);
|
||||
|
||||
log.success("Project template successfully scaffolded!");
|
||||
|
||||
if (options.install) {
|
||||
|
||||
@@ -54,13 +54,18 @@ export async function setupEnvironmentVariables(
|
||||
const hasTanStackRouter = options.frontend.includes("tanstack-router");
|
||||
const hasTanStackStart = options.frontend.includes("tanstack-start");
|
||||
const hasNextJs = options.frontend.includes("next");
|
||||
const hasNuxt = options.frontend.includes("nuxt");
|
||||
const hasWebFrontend =
|
||||
hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs;
|
||||
hasReactRouter ||
|
||||
hasTanStackRouter ||
|
||||
hasTanStackStart ||
|
||||
hasNextJs ||
|
||||
hasNuxt;
|
||||
|
||||
let corsOrigin = "http://localhost:3000";
|
||||
let corsOrigin = "http://localhost:3001";
|
||||
if (hasReactRouter) {
|
||||
corsOrigin = "http://localhost:5173";
|
||||
} else if (hasTanStackRouter || hasTanStackStart || hasNextJs) {
|
||||
} else if (hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt) {
|
||||
corsOrigin = "http://localhost:3001";
|
||||
}
|
||||
|
||||
@@ -121,6 +126,8 @@ export async function setupEnvironmentVariables(
|
||||
|
||||
if (hasNextJs) {
|
||||
envVarName = "NEXT_PUBLIC_SERVER_URL";
|
||||
} else if (hasNuxt) {
|
||||
envVarName = "NUXT_PUBLIC_SERVER_URL";
|
||||
}
|
||||
|
||||
const clientVars: EnvVariable[] = [
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import path from "node:path";
|
||||
import fs from "fs-extra";
|
||||
import type { AvailableDependencies } from "../constants";
|
||||
import type { ProjectConfig } from "../types";
|
||||
import { addPackageDependency } from "../utils/add-package-deps";
|
||||
|
||||
export async function setupExamples(config: ProjectConfig): Promise<void> {
|
||||
const { projectName, examples } = config;
|
||||
const { projectName, examples, frontend } = config;
|
||||
const projectDir = path.resolve(process.cwd(), projectName);
|
||||
|
||||
if (examples.includes("ai")) {
|
||||
@@ -12,9 +13,15 @@ export async function setupExamples(config: ProjectConfig): Promise<void> {
|
||||
const serverDir = path.join(projectDir, "apps/server");
|
||||
const clientDirExists = await fs.pathExists(clientDir);
|
||||
|
||||
const hasNuxt = frontend.includes("nuxt");
|
||||
|
||||
if (clientDirExists) {
|
||||
const dependencies: AvailableDependencies[] = ["ai"];
|
||||
if (hasNuxt) {
|
||||
dependencies.push("@ai-sdk/vue");
|
||||
}
|
||||
await addPackageDependency({
|
||||
dependencies: ["ai"],
|
||||
dependencies,
|
||||
projectDir: clientDir,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,14 +37,22 @@ export function displayPostInstallInstructions(
|
||||
? getNativeInstructions()
|
||||
: "";
|
||||
const pwaInstructions =
|
||||
addons?.includes("pwa") && frontend?.includes("react-router")
|
||||
addons?.includes("pwa") &&
|
||||
(frontend?.includes("react-router") ||
|
||||
frontend?.includes("tanstack-router")) // Exclude Nuxt from PWA instructions
|
||||
? getPwaInstructions()
|
||||
: "";
|
||||
const starlightInstructions = addons?.includes("starlight")
|
||||
? getStarlightInstructions(runCmd)
|
||||
: "";
|
||||
const hasWeb = frontend?.some((f) =>
|
||||
["tanstack-router", "react-router", "next", "tanstack-start"].includes(f),
|
||||
[
|
||||
"tanstack-router",
|
||||
"react-router",
|
||||
"next",
|
||||
"tanstack-start",
|
||||
"nuxt", // Include Nuxt here
|
||||
].includes(f),
|
||||
);
|
||||
const hasNative = frontend?.includes("native");
|
||||
const bunWebNativeWarning =
|
||||
@@ -57,12 +65,13 @@ export function displayPostInstallInstructions(
|
||||
const hasTanstackRouter = frontend?.includes("tanstack-router");
|
||||
const hasTanstackStart = frontend?.includes("tanstack-start");
|
||||
const hasReactRouter = frontend?.includes("react-router");
|
||||
const hasNuxt = frontend?.includes("nuxt"); // Add Nuxt check
|
||||
const hasWebFrontend =
|
||||
hasTanstackRouter || hasReactRouter || hasTanstackStart;
|
||||
hasTanstackRouter || hasReactRouter || hasTanstackStart || hasNuxt; // Include Nuxt
|
||||
const hasNativeFrontend = frontend?.includes("native");
|
||||
const hasFrontend = hasWebFrontend || hasNativeFrontend;
|
||||
|
||||
const webPort = hasReactRouter ? "5173" : "3001";
|
||||
const webPort = hasReactRouter ? "5173" : "3001"; // Nuxt uses 3001, same as others
|
||||
const tazeCommand = getPackageExecutionCommand(packageManager, "taze -r");
|
||||
|
||||
consola.box(
|
||||
@@ -93,7 +102,9 @@ ${
|
||||
lintingInstructions ? `\n${lintingInstructions.trim()}` : ""
|
||||
}${pwaInstructions ? `\n${pwaInstructions.trim()}` : ""}${
|
||||
starlightInstructions ? `\n${starlightInstructions.trim()}` : ""
|
||||
}${noOrmWarning ? `\n${noOrmWarning.trim()}` : ""}${bunWebNativeWarning ? `\n${bunWebNativeWarning.trim()}` : ""}
|
||||
}${noOrmWarning ? `\n${noOrmWarning.trim()}` : ""}${
|
||||
bunWebNativeWarning ? `\n${bunWebNativeWarning.trim()}` : ""
|
||||
}
|
||||
|
||||
${pc.bold("Update all dependencies:\n")}${pc.cyan(tazeCommand)}
|
||||
|
||||
@@ -177,9 +188,13 @@ function getStarlightInstructions(runCmd?: string): string {
|
||||
}
|
||||
|
||||
function getNoOrmWarning(): string {
|
||||
return `\n${pc.yellow("WARNING:")} Database selected without an ORM. Features requiring database access (e.g., examples, auth) need manual setup.\n`;
|
||||
return `\n${pc.yellow(
|
||||
"WARNING:",
|
||||
)} Database selected without an ORM. Features requiring database access (e.g., examples, auth) need manual setup.\n`;
|
||||
}
|
||||
|
||||
function getBunWebNativeWarning(): string {
|
||||
return `\n${pc.yellow("WARNING:")} 'bun' might cause issues with web + native apps in a monorepo. Use 'pnpm' if problems arise.\n`;
|
||||
return `\n${pc.yellow(
|
||||
"WARNING:",
|
||||
)} 'bun' might cause issues with web + native apps in a monorepo. Use 'pnpm' if problems arise.\n`;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { log } from "@clack/prompts";
|
||||
import { $, execa } from "execa";
|
||||
import fs from "fs-extra";
|
||||
import pc from "picocolors";
|
||||
import { dependencyVersionMap } from "../constants";
|
||||
import type { ProjectConfig } from "../types";
|
||||
|
||||
export async function updatePackageConfigurations(
|
||||
|
||||
@@ -42,15 +42,19 @@ export async function setupTauri(config: ProjectConfig): Promise<void> {
|
||||
}
|
||||
|
||||
const hasReactRouter = frontend.includes("react-router");
|
||||
const hasNuxt = frontend.includes("nuxt");
|
||||
|
||||
const devUrl = hasReactRouter
|
||||
? "http://localhost:5173"
|
||||
: "http://localhost:3001";
|
||||
|
||||
const frontendDist = hasNuxt ? "../.output/public" : "../dist";
|
||||
|
||||
const tauriArgs = [
|
||||
"init",
|
||||
`--app-name=${path.basename(projectDir)}`,
|
||||
`--window-title=${path.basename(projectDir)}`,
|
||||
"--frontend-dist=../dist",
|
||||
`--frontend-dist=${frontendDist}`,
|
||||
`--dev-url=${devUrl}`,
|
||||
`--before-dev-command=\"${packageManager} run dev\"`,
|
||||
`--before-build-command=\"${packageManager} run build\"`,
|
||||
|
||||
@@ -28,17 +28,21 @@ async function processAndCopyFiles(
|
||||
if (relativeSrcPath.endsWith(".hbs")) {
|
||||
relativeDestPath = relativeSrcPath.slice(0, -4);
|
||||
}
|
||||
if (path.basename(relativeSrcPath) === "_gitignore") {
|
||||
relativeDestPath = path.join(path.dirname(relativeSrcPath), ".gitignore");
|
||||
}
|
||||
|
||||
const destPath = path.join(destDir, relativeDestPath);
|
||||
|
||||
await fs.ensureDir(path.dirname(destPath));
|
||||
|
||||
if (!overwrite && (await fs.pathExists(destPath))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (srcPath.endsWith(".hbs")) {
|
||||
await processTemplate(srcPath, destPath, context);
|
||||
} else {
|
||||
if (!overwrite && (await fs.pathExists(destPath))) {
|
||||
continue;
|
||||
}
|
||||
await fs.copy(srcPath, destPath, { overwrite: true });
|
||||
}
|
||||
}
|
||||
@@ -49,62 +53,69 @@ export async function copyBaseTemplate(
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
const templateDir = path.join(PKG_ROOT, "templates/base");
|
||||
await processAndCopyFiles(
|
||||
["package.json", "_gitignore"],
|
||||
templateDir,
|
||||
projectDir,
|
||||
context,
|
||||
);
|
||||
await processAndCopyFiles(["**/*"], templateDir, projectDir, context);
|
||||
}
|
||||
|
||||
export async function setupFrontendTemplates(
|
||||
projectDir: string,
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
const webFrontends = context.frontend.filter(
|
||||
(f) =>
|
||||
f === "tanstack-router" ||
|
||||
f === "react-router" ||
|
||||
f === "tanstack-start" ||
|
||||
f === "next",
|
||||
const hasReactWeb = context.frontend.some((f) =>
|
||||
["tanstack-router", "react-router", "tanstack-start", "next"].includes(f),
|
||||
);
|
||||
const hasNuxtWeb = context.frontend.includes("nuxt");
|
||||
const hasNative = context.frontend.includes("native");
|
||||
|
||||
if (webFrontends.length > 0) {
|
||||
if (hasReactWeb || hasNuxtWeb) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
await fs.ensureDir(webAppDir);
|
||||
|
||||
const webBaseDir = path.join(PKG_ROOT, "templates/frontend/web-base");
|
||||
if (await fs.pathExists(webBaseDir)) {
|
||||
await processAndCopyFiles("**/*", webBaseDir, webAppDir, context);
|
||||
}
|
||||
|
||||
for (const framework of webFrontends) {
|
||||
const frameworkSrcDir = path.join(
|
||||
if (hasReactWeb) {
|
||||
const webBaseDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/frontend/${framework}`,
|
||||
"templates/frontend/react/web-base",
|
||||
);
|
||||
if (await fs.pathExists(frameworkSrcDir)) {
|
||||
await processAndCopyFiles("**/*", frameworkSrcDir, webAppDir, context);
|
||||
if (await fs.pathExists(webBaseDir)) {
|
||||
await processAndCopyFiles("**/*", webBaseDir, webAppDir, context);
|
||||
}
|
||||
const reactFramework = context.frontend.find((f) =>
|
||||
["tanstack-router", "react-router", "tanstack-start", "next"].includes(
|
||||
f,
|
||||
),
|
||||
);
|
||||
if (reactFramework) {
|
||||
const frameworkSrcDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/frontend/react/${reactFramework}`,
|
||||
);
|
||||
if (await fs.pathExists(frameworkSrcDir)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
frameworkSrcDir,
|
||||
webAppDir,
|
||||
context,
|
||||
);
|
||||
}
|
||||
const apiWebBaseDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/web/react/base`,
|
||||
);
|
||||
if (await fs.pathExists(apiWebBaseDir)) {
|
||||
await processAndCopyFiles("**/*", apiWebBaseDir, webAppDir, context);
|
||||
}
|
||||
}
|
||||
} else if (hasNuxtWeb) {
|
||||
const nuxtBaseDir = path.join(PKG_ROOT, "templates/frontend/nuxt");
|
||||
if (await fs.pathExists(nuxtBaseDir)) {
|
||||
await processAndCopyFiles("**/*", nuxtBaseDir, webAppDir, context);
|
||||
}
|
||||
const apiWebNuxtDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/web/nuxt`,
|
||||
);
|
||||
if (await fs.pathExists(apiWebNuxtDir)) {
|
||||
await processAndCopyFiles("**/*", apiWebNuxtDir, webAppDir, context);
|
||||
}
|
||||
}
|
||||
|
||||
const webFramework = webFrontends[0];
|
||||
|
||||
const apiWebBaseDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/web/base`,
|
||||
);
|
||||
if (await fs.pathExists(apiWebBaseDir)) {
|
||||
await processAndCopyFiles("**/*", apiWebBaseDir, webAppDir, context);
|
||||
}
|
||||
|
||||
const apiWebFrameworkDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/web/${webFramework}`,
|
||||
);
|
||||
if (await fs.pathExists(apiWebFrameworkDir)) {
|
||||
await processAndCopyFiles("**/*", apiWebFrameworkDir, webAppDir, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,14 +128,32 @@ export async function setupFrontendTemplates(
|
||||
await processAndCopyFiles("**/*", nativeBaseDir, nativeAppDir, context);
|
||||
}
|
||||
|
||||
const apiNativeSrcDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/native`,
|
||||
);
|
||||
|
||||
if (await fs.pathExists(apiNativeSrcDir)) {
|
||||
await processAndCopyFiles("**/*", apiNativeSrcDir, nativeAppDir, context);
|
||||
} else {
|
||||
if (context.api === "trpc") {
|
||||
const apiNativeSrcDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/native`,
|
||||
);
|
||||
if (await fs.pathExists(apiNativeSrcDir)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
apiNativeSrcDir,
|
||||
nativeAppDir,
|
||||
context,
|
||||
);
|
||||
}
|
||||
} else if (context.api === "orpc") {
|
||||
const apiNativeSrcDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/api/${context.api}/native`,
|
||||
);
|
||||
if (await fs.pathExists(apiNativeSrcDir)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
apiNativeSrcDir,
|
||||
nativeAppDir,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,13 +251,10 @@ export async function setupAuthTemplate(
|
||||
const webAppDirExists = await fs.pathExists(webAppDir);
|
||||
const nativeAppDirExists = await fs.pathExists(nativeAppDir);
|
||||
|
||||
const webFrontends = context.frontend.filter(
|
||||
(f) =>
|
||||
f === "tanstack-router" ||
|
||||
f === "react-router" ||
|
||||
f === "tanstack-start" ||
|
||||
f === "next",
|
||||
const hasReactWeb = context.frontend.some((f) =>
|
||||
["tanstack-router", "react-router", "tanstack-start", "next"].includes(f),
|
||||
);
|
||||
const hasNuxtWeb = context.frontend.includes("nuxt");
|
||||
const hasNative = context.frontend.includes("native");
|
||||
|
||||
if (serverAppDirExists) {
|
||||
@@ -240,12 +266,6 @@ export async function setupAuthTemplate(
|
||||
serverAppDir,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
consola.warn(
|
||||
pc.yellow(
|
||||
`Warning: Base auth server template not found at ${authServerBaseSrc}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (context.backend === "next") {
|
||||
@@ -260,12 +280,6 @@ export async function setupAuthTemplate(
|
||||
serverAppDir,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
consola.warn(
|
||||
pc.yellow(
|
||||
`Warning: Next auth server template not found at ${authServerNextSrc}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,44 +308,40 @@ export async function setupAuthTemplate(
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
consola.warn(
|
||||
pc.yellow(
|
||||
"Warning: apps/server directory does not exist, skipping server-side auth template setup.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (webFrontends.length > 0 && webAppDirExists) {
|
||||
const authWebBaseSrc = path.join(PKG_ROOT, "templates/auth/web/base");
|
||||
if (await fs.pathExists(authWebBaseSrc)) {
|
||||
await processAndCopyFiles("**/*", authWebBaseSrc, webAppDir, context);
|
||||
} else {
|
||||
consola.warn(
|
||||
pc.yellow(
|
||||
`Warning: Base auth web template not found at ${authWebBaseSrc}`,
|
||||
if ((hasReactWeb || hasNuxtWeb) && webAppDirExists) {
|
||||
if (hasReactWeb) {
|
||||
const authWebBaseSrc = path.join(
|
||||
PKG_ROOT,
|
||||
"templates/auth/web/react/base",
|
||||
);
|
||||
if (await fs.pathExists(authWebBaseSrc)) {
|
||||
await processAndCopyFiles("**/*", authWebBaseSrc, webAppDir, context);
|
||||
}
|
||||
const reactFramework = context.frontend.find((f) =>
|
||||
["tanstack-router", "react-router", "tanstack-start", "next"].includes(
|
||||
f,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
for (const framework of webFrontends) {
|
||||
const authWebFrameworkSrc = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/auth/web/${framework}`,
|
||||
);
|
||||
if (await fs.pathExists(authWebFrameworkSrc)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
authWebFrameworkSrc,
|
||||
webAppDir,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
consola.warn(
|
||||
pc.yellow(
|
||||
`Warning: Auth web template for ${framework} not found at ${authWebFrameworkSrc}`,
|
||||
),
|
||||
if (reactFramework) {
|
||||
const authWebFrameworkSrc = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/auth/web/react/${reactFramework}`,
|
||||
);
|
||||
if (await fs.pathExists(authWebFrameworkSrc)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
authWebFrameworkSrc,
|
||||
webAppDir,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (hasNuxtWeb) {
|
||||
const authWebNuxtSrc = path.join(PKG_ROOT, "templates/auth/web/nuxt");
|
||||
if (await fs.pathExists(authWebNuxtSrc)) {
|
||||
await processAndCopyFiles("**/*", authWebNuxtSrc, webAppDir, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,50 +364,25 @@ export async function setupAddonsTemplate(
|
||||
projectDir: string,
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
if (context.addons.includes("turborepo")) {
|
||||
const turboSrcDir = path.join(PKG_ROOT, "templates/addons/turborepo");
|
||||
if (await fs.pathExists(turboSrcDir)) {
|
||||
await processAndCopyFiles("**/*", turboSrcDir, projectDir, context);
|
||||
} else {
|
||||
consola.warn(pc.yellow("Warning: Turborepo addon template not found."));
|
||||
}
|
||||
}
|
||||
if (!context.addons || context.addons.length === 0) return;
|
||||
|
||||
if (context.addons.includes("husky")) {
|
||||
const huskySrcDir = path.join(PKG_ROOT, "templates/addons/husky");
|
||||
if (await fs.pathExists(huskySrcDir)) {
|
||||
await processAndCopyFiles("**/*", huskySrcDir, projectDir, context);
|
||||
} else {
|
||||
consola.warn(pc.yellow("Warning: Husky addon template not found."));
|
||||
}
|
||||
}
|
||||
for (const addon of context.addons) {
|
||||
if (addon === "none") continue;
|
||||
|
||||
if (context.addons.includes("biome")) {
|
||||
const biomeSrcDir = path.join(PKG_ROOT, "templates/addons/biome");
|
||||
if (await fs.pathExists(biomeSrcDir)) {
|
||||
await processAndCopyFiles("**/*", biomeSrcDir, projectDir, context);
|
||||
} else {
|
||||
consola.warn(pc.yellow("Warning: Biome addon template not found."));
|
||||
}
|
||||
}
|
||||
let addonSrcDir = path.join(PKG_ROOT, `templates/addons/${addon}`);
|
||||
let addonDestDir = projectDir;
|
||||
|
||||
if (context.addons.includes("pwa")) {
|
||||
const pwaSrcDir = path.join(PKG_ROOT, "templates/addons/pwa/apps/web");
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
const webAppDirExists = await fs.pathExists(webAppDir);
|
||||
|
||||
if (await fs.pathExists(pwaSrcDir)) {
|
||||
if (webAppDirExists) {
|
||||
await processAndCopyFiles("**/*", pwaSrcDir, webAppDir, context);
|
||||
} else {
|
||||
consola.warn(
|
||||
pc.yellow(
|
||||
"Warning: apps/web directory not found, cannot setup PWA addon template.",
|
||||
),
|
||||
);
|
||||
if (addon === "pwa") {
|
||||
addonSrcDir = path.join(PKG_ROOT, "templates/addons/pwa/apps/web");
|
||||
addonDestDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(addonDestDir))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (await fs.pathExists(addonSrcDir)) {
|
||||
await processAndCopyFiles("**/*", addonSrcDir, addonDestDir, context);
|
||||
} else {
|
||||
consola.warn(pc.yellow("Warning: PWA addon template not found."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,7 +399,14 @@ export async function setupExamplesTemplate(
|
||||
const serverAppDirExists = await fs.pathExists(serverAppDir);
|
||||
const webAppDirExists = await fs.pathExists(webAppDir);
|
||||
|
||||
const hasReactWeb = context.frontend.some((f) =>
|
||||
["tanstack-router", "react-router", "tanstack-start", "next"].includes(f),
|
||||
);
|
||||
const hasNuxtWeb = context.frontend.includes("nuxt");
|
||||
|
||||
for (const example of context.examples) {
|
||||
if (example === "none") continue;
|
||||
|
||||
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
||||
|
||||
if (serverAppDirExists) {
|
||||
@@ -456,10 +448,10 @@ export async function setupExamplesTemplate(
|
||||
}
|
||||
}
|
||||
|
||||
if (webAppDirExists) {
|
||||
const exampleWebSrc = path.join(exampleBaseDir, "web");
|
||||
if (hasReactWeb && webAppDirExists) {
|
||||
const exampleWebSrc = path.join(exampleBaseDir, "web/react");
|
||||
if (await fs.pathExists(exampleWebSrc)) {
|
||||
const webFrameworks = context.frontend.filter((f) =>
|
||||
const reactFramework = context.frontend.find((f) =>
|
||||
[
|
||||
"next",
|
||||
"react-router",
|
||||
@@ -467,8 +459,11 @@ export async function setupExamplesTemplate(
|
||||
"tanstack-start",
|
||||
].includes(f),
|
||||
);
|
||||
for (const framework of webFrameworks) {
|
||||
const exampleWebFrameworkSrc = path.join(exampleWebSrc, framework);
|
||||
if (reactFramework) {
|
||||
const exampleWebFrameworkSrc = path.join(
|
||||
exampleWebSrc,
|
||||
reactFramework,
|
||||
);
|
||||
if (await fs.pathExists(exampleWebFrameworkSrc)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
@@ -480,36 +475,27 @@ export async function setupExamplesTemplate(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function fixGitignoreFiles(
|
||||
projectDir: string,
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
const gitignoreFiles = await globby(["**/.gitignore.hbs", "**/_gitignore"], {
|
||||
cwd: projectDir,
|
||||
dot: true,
|
||||
onlyFiles: true,
|
||||
absolute: true,
|
||||
ignore: ["**/node_modules/**", "**/.git/**"],
|
||||
});
|
||||
|
||||
for (const currentPath of gitignoreFiles) {
|
||||
const dir = path.dirname(currentPath);
|
||||
const filename = path.basename(currentPath);
|
||||
const destPath = path.join(dir, ".gitignore");
|
||||
|
||||
try {
|
||||
if (filename === ".gitignore.hbs") {
|
||||
await processTemplate(currentPath, destPath, context);
|
||||
await fs.remove(currentPath);
|
||||
} else if (filename === "_gitignore") {
|
||||
await fs.move(currentPath, destPath, { overwrite: true });
|
||||
} else if (hasNuxtWeb && webAppDirExists) {
|
||||
// Only copy Nuxt examples if the API is oRPC (as tRPC is not supported)
|
||||
if (context.api === "orpc") {
|
||||
const exampleWebNuxtSrc = path.join(exampleBaseDir, "web/nuxt");
|
||||
if (await fs.pathExists(exampleWebNuxtSrc)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
exampleWebNuxtSrc,
|
||||
webAppDir,
|
||||
context,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
consola.info(
|
||||
pc.gray(
|
||||
`Skipping Nuxt web template for example '${example}' (template not found).`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
consola.error(`Error processing gitignore file ${currentPath}:`, error);
|
||||
// If API is tRPC, skip Nuxt examples silently as CLI validation prevents this combo.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -518,24 +504,24 @@ export async function handleExtras(
|
||||
projectDir: string,
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
const extrasDir = path.join(PKG_ROOT, "templates/extras");
|
||||
|
||||
if (context.packageManager === "pnpm") {
|
||||
const pnpmWorkspaceSrc = path.join(
|
||||
PKG_ROOT,
|
||||
"templates/extras/pnpm-workspace.yaml",
|
||||
);
|
||||
const pnpmWorkspaceSrc = path.join(extrasDir, "pnpm-workspace.yaml");
|
||||
const pnpmWorkspaceDest = path.join(projectDir, "pnpm-workspace.yaml");
|
||||
if (await fs.pathExists(pnpmWorkspaceSrc)) {
|
||||
await fs.copy(pnpmWorkspaceSrc, pnpmWorkspaceDest);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
if (context.frontend.includes("native")) {
|
||||
const npmrcSrc = path.join(PKG_ROOT, "templates/extras/_npmrc");
|
||||
if (
|
||||
context.packageManager === "pnpm" &&
|
||||
(context.frontend.includes("native") || context.frontend.includes("nuxt"))
|
||||
) {
|
||||
const npmrcTemplateSrc = path.join(extrasDir, "_npmrc.hbs");
|
||||
const npmrcDest = path.join(projectDir, ".npmrc");
|
||||
if (await fs.pathExists(npmrcSrc)) {
|
||||
await fs.copy(npmrcSrc, npmrcDest);
|
||||
} else {
|
||||
if (await fs.pathExists(npmrcTemplateSrc)) {
|
||||
await processTemplate(npmrcTemplateSrc, npmrcDest, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user