import { fileExists } from "@/files"; import { dockerfileExists } from "../../docker"; import fs from "fs/promises"; import { AllResourceGroupTypes, ResourceGroupType, importResourceGroupType } from "@/resourceGroups"; import { BaseTemplate } from "@/templates"; import { ZodObject } from "zod"; import path from "path"; class TanstackStartFramework extends BaseTemplate { public data: any; constructor( public name: string, public directory: string, public resourceGroupType: ResourceGroupType, public inputSchema: ZodObject | undefined = undefined ) { const dirname = path.resolve(__dirname); super(name, directory, resourceGroupType, dirname); if ( !TanstackStartFramework.resourceGroupsSupported.includes( this.resourceGroupType ) ) { throw new Error("Resource group type not supported"); } const tmpResourceGroup = importResourceGroupType( resourceGroupType, name, directory ); if (!tmpResourceGroup) { throw new Error("Error importing resource group type"); } this.inputSchema = tmpResourceGroup.inputSchema; } public static resourceGroupsSupported: ResourceGroupType[] = [ ...AllResourceGroupTypes ]; public async generate() { const ensureDockerfile = async () => { if (await dockerfileExists()) { return; } try { await fs.copyFile(`${__dirname}/Dockerfile`, "Dockerfile"); } catch (error) { console.error("Unable to render Dockerfile", error); throw error; } }; const ensureAppConfig = async () => { const appConfigFile = "app.config.ts"; let appConfig = await fs.readFile(appConfigFile, "utf-8"); const serverMatch = appConfig.match(/server: *{/); if (!serverMatch) { appConfig = appConfig.replace( /export default defineConfig\({/, `export default defineConfig({\n server: { preset: 'node-server' },\n` ); } else { const presetMatch = appConfig.match(/preset: *'(.+)'/); if (presetMatch && presetMatch?.[1] !== "node-server") { throw new Error( `Limo support for Tanstack start is limited to the node-server preset. Current value is ${presetMatch[1]}` ); } else if (!presetMatch) { console.warn( "Unable to find server preset in app.config.ts. You may need to update it manually.\n See https://tanstack.com/router/latest/docs/framework/react/start/hosting/#nodejs for more info" ); } } await fs.writeFile(appConfigFile, appConfig); }; const updateDockerignore = async () => { if (!(await fileExists(".dockerignore"))) { await fs.writeFile(".dockerignore", ""); } const contents = await fs.readFile(".dockerignore", "utf-8"); const depsToCheck = [ "node_modules", "*.log", ".vinxi", ".git", ".DS_Store", ".output", "/data" ]; const outputToAppend = depsToCheck .filter((dep) => !contents.includes(dep)) .join("\n"); if (outputToAppend.length === 0) { return; } await fs.appendFile(".dockerignore", `\n${outputToAppend}`); }; await Promise.all([ ensureDockerfile(), ensureAppConfig(), updateDockerignore() ]); } public async destroy() { // TODO: codemod to remove the server preset from app.config.ts } } export default TanstackStartFramework;