mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
feat(cli): add react router support with alchemy (#542)
This commit is contained in:
@@ -29,7 +29,7 @@ export async function setupCombinedAlchemyDeploy(
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
@@ -49,18 +49,32 @@ export async function setupCombinedAlchemyDeploy(
|
||||
const isSolid = frontend.includes("solid");
|
||||
|
||||
if (isNext) {
|
||||
await setupNextAlchemyDeploy(projectDir, packageManager);
|
||||
await setupNextAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
} else if (isNuxt) {
|
||||
await setupNuxtAlchemyDeploy(projectDir, packageManager);
|
||||
await setupNuxtAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
} else if (isSvelte) {
|
||||
await setupSvelteAlchemyDeploy(projectDir, packageManager);
|
||||
await setupSvelteAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
} else if (isTanstackStart) {
|
||||
await setupTanStackStartAlchemyDeploy(projectDir, packageManager);
|
||||
await setupTanStackStartAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
} else if (isTanstackRouter) {
|
||||
await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
|
||||
await setupTanStackRouterAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
} else if (isReactRouter) {
|
||||
await setupReactRouterAlchemyDeploy(projectDir, packageManager);
|
||||
await setupReactRouterAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
} else if (isSolid) {
|
||||
await setupSolidAlchemyDeploy(projectDir, packageManager);
|
||||
await setupSolidAlchemyDeploy(projectDir, packageManager, {
|
||||
skipAppScripts: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
export async function setupNextAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
@@ -19,12 +20,14 @@ export async function setupNextAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
export async function setupNuxtAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
@@ -20,12 +21,14 @@ export async function setupNuxtAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import path from "node:path";
|
||||
import fs from "fs-extra";
|
||||
import { IndentationText, Node, Project, QuoteKind } from "ts-morph";
|
||||
import type { PackageManager } from "../../../types";
|
||||
import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
|
||||
export async function setupReactRouterAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
|
||||
await addPackageDependency({
|
||||
devDependencies: ["alchemy", "@cloudflare/vite-plugin", "dotenv"],
|
||||
devDependencies: ["alchemy", "dotenv"],
|
||||
projectDir: webAppDir,
|
||||
});
|
||||
|
||||
@@ -20,149 +20,14 @@ export async function setupReactRouterAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
|
||||
const viteConfigPath = path.join(webAppDir, "vite.config.ts");
|
||||
if (await fs.pathExists(viteConfigPath)) {
|
||||
try {
|
||||
const project = new Project({
|
||||
manipulationSettings: {
|
||||
indentationText: IndentationText.TwoSpaces,
|
||||
quoteKind: QuoteKind.Double,
|
||||
},
|
||||
});
|
||||
|
||||
project.addSourceFileAtPath(viteConfigPath);
|
||||
const sourceFile = project.getSourceFileOrThrow(viteConfigPath);
|
||||
|
||||
const alchemyImport = sourceFile.getImportDeclaration(
|
||||
"alchemy/cloudflare/react-router",
|
||||
);
|
||||
if (!alchemyImport) {
|
||||
sourceFile.addImportDeclaration({
|
||||
moduleSpecifier: "alchemy/cloudflare/react-router",
|
||||
defaultImport: "alchemy",
|
||||
});
|
||||
}
|
||||
|
||||
const exportAssignment = sourceFile.getExportAssignment(
|
||||
(d) => !d.isExportEquals(),
|
||||
);
|
||||
if (!exportAssignment) return;
|
||||
|
||||
const defineConfigCall = exportAssignment.getExpression();
|
||||
if (
|
||||
!Node.isCallExpression(defineConfigCall) ||
|
||||
defineConfigCall.getExpression().getText() !== "defineConfig"
|
||||
)
|
||||
return;
|
||||
|
||||
let configObject = defineConfigCall.getArguments()[0];
|
||||
if (!configObject) {
|
||||
configObject = defineConfigCall.addArgument("{}");
|
||||
}
|
||||
|
||||
if (Node.isObjectLiteralExpression(configObject)) {
|
||||
const pluginsProperty = configObject.getProperty("plugins");
|
||||
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
|
||||
const initializer = pluginsProperty.getInitializer();
|
||||
if (Node.isArrayLiteralExpression(initializer)) {
|
||||
const hasCloudflarePlugin = initializer
|
||||
.getElements()
|
||||
.some((el) => el.getText().includes("cloudflare("));
|
||||
|
||||
if (!hasCloudflarePlugin) {
|
||||
initializer.addElement("alchemy()");
|
||||
}
|
||||
}
|
||||
} else if (!pluginsProperty) {
|
||||
configObject.addPropertyAssignment({
|
||||
name: "plugins",
|
||||
initializer: "[alchemy()]",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await project.save();
|
||||
} catch (error) {
|
||||
console.warn("Failed to update vite.config.ts:", error);
|
||||
}
|
||||
}
|
||||
|
||||
const reactRouterConfigPath = path.join(webAppDir, "react-router.config.ts");
|
||||
if (await fs.pathExists(reactRouterConfigPath)) {
|
||||
try {
|
||||
const project = new Project({
|
||||
manipulationSettings: {
|
||||
indentationText: IndentationText.TwoSpaces,
|
||||
quoteKind: QuoteKind.Double,
|
||||
},
|
||||
});
|
||||
|
||||
project.addSourceFileAtPath(reactRouterConfigPath);
|
||||
const sourceFile = project.getSourceFileOrThrow(reactRouterConfigPath);
|
||||
|
||||
const exportAssignment = sourceFile.getExportAssignment(
|
||||
(d) => !d.isExportEquals(),
|
||||
);
|
||||
if (!exportAssignment) return;
|
||||
|
||||
const configExpression = exportAssignment.getExpression();
|
||||
let configObject: Node | undefined;
|
||||
|
||||
if (Node.isObjectLiteralExpression(configExpression)) {
|
||||
configObject = configExpression;
|
||||
} else if (Node.isSatisfiesExpression(configExpression)) {
|
||||
const expression = configExpression.getExpression();
|
||||
if (Node.isObjectLiteralExpression(expression)) {
|
||||
configObject = expression;
|
||||
}
|
||||
}
|
||||
|
||||
if (!configObject || !Node.isObjectLiteralExpression(configObject))
|
||||
return;
|
||||
|
||||
const futureProperty = configObject.getProperty("future");
|
||||
|
||||
if (!futureProperty) {
|
||||
configObject.addPropertyAssignment({
|
||||
name: "future",
|
||||
initializer: `{
|
||||
unstable_viteEnvironmentApi: true,
|
||||
}`,
|
||||
});
|
||||
} else if (Node.isPropertyAssignment(futureProperty)) {
|
||||
const futureInitializer = futureProperty.getInitializer();
|
||||
|
||||
if (Node.isObjectLiteralExpression(futureInitializer)) {
|
||||
const viteEnvApiProp = futureInitializer.getProperty(
|
||||
"unstable_viteEnvironmentApi",
|
||||
);
|
||||
|
||||
if (!viteEnvApiProp) {
|
||||
futureInitializer.addPropertyAssignment({
|
||||
name: "unstable_viteEnvironmentApi",
|
||||
initializer: "true",
|
||||
});
|
||||
} else if (Node.isPropertyAssignment(viteEnvApiProp)) {
|
||||
const value = viteEnvApiProp.getInitializer()?.getText();
|
||||
if (value === "false") {
|
||||
viteEnvApiProp.setInitializer("true");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await project.save();
|
||||
} catch (error) {
|
||||
console.warn("Failed to update react-router.config.ts:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
export async function setupSolidAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
@@ -19,12 +20,14 @@ export async function setupSolidAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
export async function setupSvelteAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
@@ -20,12 +21,15 @@ export async function setupSvelteAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
export async function setupTanStackRouterAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
@@ -19,12 +20,15 @@ export async function setupTanStackRouterAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { addPackageDependency } from "../../../utils/add-package-deps";
|
||||
export async function setupTanStackStartAlchemyDeploy(
|
||||
projectDir: string,
|
||||
_packageManager: PackageManager,
|
||||
options?: { skipAppScripts?: boolean },
|
||||
) {
|
||||
const webAppDir = path.join(projectDir, "apps/web");
|
||||
if (!(await fs.pathExists(webAppDir))) return;
|
||||
@@ -20,12 +21,15 @@ export async function setupTanStackStartAlchemyDeploy(
|
||||
if (await fs.pathExists(pkgPath)) {
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
if (!options?.skipAppScripts) {
|
||||
pkg.scripts = {
|
||||
...pkg.scripts,
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
dev: "alchemy dev",
|
||||
};
|
||||
}
|
||||
|
||||
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
||||
}
|
||||
|
||||
|
||||
@@ -99,11 +99,9 @@ export async function setupAlchemyServerDeploy(
|
||||
|
||||
packageJson.scripts = {
|
||||
...packageJson.scripts,
|
||||
dev: "wrangler dev --port=3000",
|
||||
build: "wrangler deploy --dry-run",
|
||||
dev: "alchemy dev",
|
||||
deploy: "alchemy deploy",
|
||||
destroy: "alchemy destroy",
|
||||
"alchemy:dev": "alchemy dev",
|
||||
};
|
||||
|
||||
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
||||
|
||||
Reference in New Issue
Block a user