mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Added support for building mobile applications with Expo
This commit is contained in:
@@ -9,6 +9,7 @@ export const PKG_ROOT = path.join(distPath, "../");
|
||||
|
||||
export const DEFAULT_CONFIG: ProjectConfig = {
|
||||
projectName: "my-better-t-app",
|
||||
frontend: ["web"],
|
||||
database: "sqlite",
|
||||
orm: "drizzle",
|
||||
auth: true,
|
||||
|
||||
@@ -87,7 +87,7 @@ async function setupPwa(projectDir: string) {
|
||||
await fs.copy(pwaTemplateDir, projectDir, { overwrite: true });
|
||||
}
|
||||
|
||||
const clientPackageDir = path.join(projectDir, "apps/client");
|
||||
const clientPackageDir = path.join(projectDir, "apps/web");
|
||||
|
||||
addPackageDependency({
|
||||
dependencies: ["vite-plugin-pwa"],
|
||||
|
||||
@@ -23,7 +23,7 @@ export async function setupAuth(
|
||||
}
|
||||
|
||||
const serverDir = path.join(projectDir, "apps/server");
|
||||
const clientDir = path.join(projectDir, "apps/client");
|
||||
const clientDir = path.join(projectDir, "apps/web");
|
||||
|
||||
try {
|
||||
addPackageDependency({
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
fixGitignoreFiles,
|
||||
setupAuthTemplate,
|
||||
setupBackendFramework,
|
||||
setupFrontendTemplates,
|
||||
setupOrmTemplate,
|
||||
} from "./template-manager";
|
||||
|
||||
@@ -29,6 +30,8 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
||||
await fs.ensureDir(projectDir);
|
||||
|
||||
await copyBaseTemplate(projectDir);
|
||||
await setupFrontendTemplates(projectDir, options.frontend);
|
||||
|
||||
await fixGitignoreFiles(projectDir);
|
||||
|
||||
await setupBackendFramework(projectDir, options.backendFramework);
|
||||
@@ -89,6 +92,7 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
||||
options.orm,
|
||||
options.addons,
|
||||
options.runtime,
|
||||
options.frontend,
|
||||
);
|
||||
|
||||
return projectDir;
|
||||
|
||||
@@ -57,7 +57,7 @@ Then, run the development server:
|
||||
${packageManagerRunCmd} dev
|
||||
\`\`\`
|
||||
|
||||
Open [http://localhost:3001](http://localhost:3001) in your browser to see the client application.
|
||||
Open [http://localhost:3001](http://localhost:3001) in your browser to see the web application.
|
||||
The API is running at [http://localhost:3000](http://localhost:3000).
|
||||
|
||||
## Project Structure
|
||||
@@ -65,7 +65,7 @@ The API is running at [http://localhost:3000](http://localhost:3000).
|
||||
\`\`\`
|
||||
${projectName}/
|
||||
├── apps/
|
||||
│ ├── client/ # Frontend application (React, TanStack Router)
|
||||
│ ├── web/ # Frontend application (React, TanStack Router)
|
||||
│ └── server/ # Backend API (Hono, tRPC)
|
||||
\`\`\`
|
||||
|
||||
@@ -173,9 +173,9 @@ function generateScriptsList(
|
||||
orm: ProjectOrm,
|
||||
auth: boolean,
|
||||
): string {
|
||||
let scripts = `- \`${packageManagerRunCmd} dev\`: Start both client and server in development mode
|
||||
- \`${packageManagerRunCmd} build\`: Build both client and server
|
||||
- \`${packageManagerRunCmd} dev:client\`: Start only the client
|
||||
let scripts = `- \`${packageManagerRunCmd} dev\`: Start both web and server in development mode
|
||||
- \`${packageManagerRunCmd} build\`: Build both web and server
|
||||
- \`${packageManagerRunCmd} dev:web\`: Start only the web application
|
||||
- \`${packageManagerRunCmd} dev:server\`: Start only the server
|
||||
- \`${packageManagerRunCmd} check-types\`: Check TypeScript types across all apps`;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ export async function setupEnvironmentVariables(
|
||||
options: ProjectConfig,
|
||||
): Promise<void> {
|
||||
const serverDir = path.join(projectDir, "apps/server");
|
||||
const clientDir = path.join(projectDir, "apps/client");
|
||||
|
||||
const envPath = path.join(serverDir, ".env");
|
||||
let envContent = "";
|
||||
@@ -49,16 +48,35 @@ export async function setupEnvironmentVariables(
|
||||
|
||||
await fs.writeFile(envPath, envContent.trim());
|
||||
|
||||
const clientEnvPath = path.join(clientDir, ".env");
|
||||
let clientEnvContent = "";
|
||||
if (options.frontend.includes("web")) {
|
||||
const clientDir = path.join(projectDir, "apps/web");
|
||||
const clientEnvPath = path.join(clientDir, ".env");
|
||||
let clientEnvContent = "";
|
||||
|
||||
if (await fs.pathExists(clientEnvPath)) {
|
||||
clientEnvContent = await fs.readFile(clientEnvPath, "utf8");
|
||||
if (await fs.pathExists(clientEnvPath)) {
|
||||
clientEnvContent = await fs.readFile(clientEnvPath, "utf8");
|
||||
}
|
||||
|
||||
if (!clientEnvContent.includes("VITE_SERVER_URL")) {
|
||||
clientEnvContent += "VITE_SERVER_URL=http://localhost:3000\n";
|
||||
}
|
||||
|
||||
await fs.writeFile(clientEnvPath, clientEnvContent.trim());
|
||||
}
|
||||
|
||||
if (!clientEnvContent.includes("VITE_SERVER_URL")) {
|
||||
clientEnvContent += "VITE_SERVER_URL=http://localhost:3000\n";
|
||||
}
|
||||
if (options.frontend.includes("native")) {
|
||||
const nativeDir = path.join(projectDir, "apps/native");
|
||||
const nativeEnvPath = path.join(nativeDir, ".env");
|
||||
let nativeEnvContent = "";
|
||||
|
||||
await fs.writeFile(clientEnvPath, clientEnvContent.trim());
|
||||
if (await fs.pathExists(nativeEnvPath)) {
|
||||
nativeEnvContent = await fs.readFile(nativeEnvPath, "utf8");
|
||||
}
|
||||
|
||||
if (!nativeEnvContent.includes("EXPO_PUBLIC_SERVER_URL")) {
|
||||
nativeEnvContent += "EXPO_PUBLIC_SERVER_URL=http://localhost:3000\n";
|
||||
}
|
||||
|
||||
await fs.writeFile(nativeEnvPath, nativeEnvContent.trim());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ async function setupTodoExample(
|
||||
): Promise<void> {
|
||||
const todoExampleDir = path.join(PKG_ROOT, "template/examples/todo");
|
||||
if (await fs.pathExists(todoExampleDir)) {
|
||||
const todoRouteDir = path.join(todoExampleDir, "apps/client/src/routes");
|
||||
const targetRouteDir = path.join(projectDir, "apps/client/src/routes");
|
||||
const todoRouteDir = path.join(todoExampleDir, "apps/web/src/routes");
|
||||
const targetRouteDir = path.join(projectDir, "apps/web/src/routes");
|
||||
await fs.copy(todoRouteDir, targetRouteDir, { overwrite: true });
|
||||
|
||||
if (orm !== "none") {
|
||||
@@ -55,7 +55,7 @@ async function updateHeaderWithTodoLink(
|
||||
): Promise<void> {
|
||||
const headerPath = path.join(
|
||||
projectDir,
|
||||
"apps/client/src/components/header.tsx",
|
||||
"apps/web/src/components/header.tsx",
|
||||
);
|
||||
|
||||
if (await fs.pathExists(headerPath)) {
|
||||
@@ -125,7 +125,7 @@ async function updateRouterIndex(projectDir: string): Promise<void> {
|
||||
}
|
||||
|
||||
async function addTodoButtonToHomepage(projectDir: string): Promise<void> {
|
||||
const indexPath = path.join(projectDir, "apps/client/src/routes/index.tsx");
|
||||
const indexPath = path.join(projectDir, "apps/web/src/routes/index.tsx");
|
||||
|
||||
if (await fs.pathExists(indexPath)) {
|
||||
let indexContent = await fs.readFile(indexPath, "utf8");
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
PackageManager,
|
||||
ProjectAddons,
|
||||
ProjectDatabase,
|
||||
ProjectFrontend,
|
||||
ProjectOrm,
|
||||
Runtime,
|
||||
} from "../types";
|
||||
@@ -13,9 +14,10 @@ export function displayPostInstallInstructions(
|
||||
projectName: string,
|
||||
packageManager: PackageManager,
|
||||
depsInstalled: boolean,
|
||||
orm?: ProjectOrm,
|
||||
addons?: ProjectAddons[],
|
||||
runtime?: Runtime,
|
||||
orm: ProjectOrm,
|
||||
addons: ProjectAddons[],
|
||||
runtime: Runtime,
|
||||
frontends: ProjectFrontend[],
|
||||
) {
|
||||
const runCmd = packageManager === "npm" ? "npm run" : packageManager;
|
||||
const cdCmd = `cd ${projectName}`;
|
||||
@@ -32,15 +34,29 @@ export function displayPostInstallInstructions(
|
||||
const lintingInstructions = hasHuskyOrBiome
|
||||
? getLintingInstructions(runCmd)
|
||||
: "";
|
||||
const nativeInstructions = frontends?.includes("native")
|
||||
? getNativeInstructions()
|
||||
: "";
|
||||
|
||||
const hasWebFrontend = frontends?.includes("web");
|
||||
const hasNativeFrontend = frontends?.includes("native");
|
||||
const hasFrontend = hasWebFrontend || hasNativeFrontend;
|
||||
|
||||
log.info(`${pc.bold("Next steps:")}
|
||||
${pc.cyan("1.")} ${cdCmd}
|
||||
${!depsInstalled ? `${pc.cyan("2.")} ${packageManager} install\n` : ""}${pc.cyan(depsInstalled ? "2." : "3.")} ${runCmd} dev
|
||||
|
||||
${pc.bold("Your project will be available at:")}
|
||||
${pc.cyan("•")} Frontend: http://localhost:3001
|
||||
${pc.cyan("•")} API: http://localhost:3000
|
||||
${databaseInstructions ? `\n${databaseInstructions.trim()}` : ""}${tauriInstructions ? `\n${tauriInstructions.trim()}` : ""}${lintingInstructions ? `\n${lintingInstructions.trim()}` : ""}`);
|
||||
${
|
||||
hasFrontend
|
||||
? `${hasWebFrontend ? `${pc.cyan("•")} Frontend: http://localhost:3001\n` : ""}`
|
||||
: `${pc.yellow("NOTE:")} You are creating a backend-only app (no frontend selected)\n`
|
||||
}${pc.cyan("•")} API: http://localhost:3000
|
||||
${nativeInstructions ? `\n${nativeInstructions.trim()}` : ""}${databaseInstructions ? `\n${databaseInstructions.trim()}` : ""}${tauriInstructions ? `\n${tauriInstructions.trim()}` : ""}${lintingInstructions ? `\n${lintingInstructions.trim()}` : ""}`);
|
||||
}
|
||||
|
||||
function getNativeInstructions(): string {
|
||||
return `${pc.yellow("NOTE:")} If the Expo app cannot connect to the server, update the EXPO_PUBLIC_SERVER_URL in apps/native/.env to use your local IP address instead of localhost:\n${pc.dim("EXPO_PUBLIC_SERVER_URL=http://192.168.0.103:3000")}\n`;
|
||||
}
|
||||
|
||||
function getLintingInstructions(runCmd?: string): string {
|
||||
@@ -95,5 +111,5 @@ function getDatabaseInstructions(
|
||||
}
|
||||
|
||||
function getTauriInstructions(runCmd?: string): string {
|
||||
return `${pc.bold("Desktop app with Tauri:")}\n${pc.cyan("•")} Start desktop app: ${pc.dim(`cd apps/client && ${runCmd} desktop:dev`)}\n${pc.cyan("•")} Build desktop app: ${pc.dim(`cd apps/client && ${runCmd} desktop:build`)}\n${pc.yellow("NOTE:")} Tauri requires Rust and platform-specific dependencies. See: ${pc.dim("https://v2.tauri.app/start/prerequisites/")}\n\n`;
|
||||
return `${pc.bold("Desktop app with Tauri:")}\n${pc.cyan("•")} Start desktop app: ${pc.dim(`cd apps/web && ${runCmd} desktop:dev`)}\n${pc.cyan("•")} Build desktop app: ${pc.dim(`cd apps/web && ${runCmd} desktop:build`)}\n${pc.yellow("NOTE:")} Tauri requires Rust and platform-specific dependencies. See: ${pc.dim("https://v2.tauri.app/start/prerequisites/")}\n\n`;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export async function setupTauri(
|
||||
packageManager: PackageManager,
|
||||
): Promise<void> {
|
||||
const s = spinner();
|
||||
const clientPackageDir = path.join(projectDir, "apps/client");
|
||||
const clientPackageDir = path.join(projectDir, "apps/web");
|
||||
|
||||
try {
|
||||
s.start("Setting up Tauri desktop app support...");
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import path from "node:path";
|
||||
import fs from "fs-extra";
|
||||
import { PKG_ROOT } from "../constants";
|
||||
import type { BackendFramework, ProjectDatabase, ProjectOrm } from "../types";
|
||||
import type {
|
||||
BackendFramework,
|
||||
ProjectDatabase,
|
||||
ProjectFrontend,
|
||||
ProjectOrm,
|
||||
} from "../types";
|
||||
|
||||
export async function copyBaseTemplate(projectDir: string): Promise<void> {
|
||||
const templateDir = path.join(PKG_ROOT, "template/base");
|
||||
@@ -11,6 +16,30 @@ export async function copyBaseTemplate(projectDir: string): Promise<void> {
|
||||
await fs.copy(templateDir, projectDir);
|
||||
}
|
||||
|
||||
export async function setupFrontendTemplates(
|
||||
projectDir: string,
|
||||
frontends: ProjectFrontend[],
|
||||
): Promise<void> {
|
||||
if (!frontends.includes("web")) {
|
||||
const webDir = path.join(projectDir, "apps/web");
|
||||
if (await fs.pathExists(webDir)) {
|
||||
await fs.remove(webDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!frontends.includes("native")) {
|
||||
const nativeDir = path.join(projectDir, "apps/native");
|
||||
if (await fs.pathExists(nativeDir)) {
|
||||
await fs.remove(nativeDir);
|
||||
}
|
||||
} else {
|
||||
await fs.writeFile(
|
||||
path.join(projectDir, ".npmrc"),
|
||||
"node-linker=hoisted\n",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function setupBackendFramework(
|
||||
projectDir: string,
|
||||
framework: BackendFramework,
|
||||
@@ -67,8 +96,8 @@ export async function setupAuthTemplate(
|
||||
|
||||
const authTemplateDir = path.join(PKG_ROOT, "template/with-auth");
|
||||
if (await fs.pathExists(authTemplateDir)) {
|
||||
const clientAuthDir = path.join(authTemplateDir, "apps/client");
|
||||
const projectClientDir = path.join(projectDir, "apps/client");
|
||||
const clientAuthDir = path.join(authTemplateDir, "apps/web");
|
||||
const projectClientDir = path.join(projectDir, "apps/web");
|
||||
await fs.copy(clientAuthDir, projectClientDir, { overwrite: true });
|
||||
|
||||
const serverAuthDir = path.join(authTemplateDir, "apps/server/src");
|
||||
@@ -118,7 +147,8 @@ export async function setupAuthTemplate(
|
||||
export async function fixGitignoreFiles(projectDir: string): Promise<void> {
|
||||
const gitignorePaths = [
|
||||
path.join(projectDir, "_gitignore"),
|
||||
path.join(projectDir, "apps/client/_gitignore"),
|
||||
path.join(projectDir, "apps/web/_gitignore"),
|
||||
path.join(projectDir, "apps/native/_gitignore"),
|
||||
path.join(projectDir, "apps/server/_gitignore"),
|
||||
];
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
ProjectAddons,
|
||||
ProjectConfig,
|
||||
ProjectExamples,
|
||||
ProjectFrontend,
|
||||
Runtime,
|
||||
} from "./types";
|
||||
import { displayConfig } from "./utils/display-config";
|
||||
@@ -59,6 +60,10 @@ async function main() {
|
||||
.option("--hono", "Use Hono backend framework")
|
||||
.option("--elysia", "Use Elysia backend framework")
|
||||
.option("--runtime <runtime>", "Specify runtime (bun or node)")
|
||||
.option("--web", "Include web frontend")
|
||||
.option("--native", "Include Expo frontend")
|
||||
.option("--no-web", "Exclude web frontend")
|
||||
.option("--no-native", "Exclude Expo frontend")
|
||||
.parse();
|
||||
|
||||
const s = spinner();
|
||||
@@ -115,6 +120,16 @@ async function main() {
|
||||
.filter((e) => e === "todo") as ProjectExamples[])
|
||||
: [],
|
||||
}),
|
||||
...((options.web !== undefined || options.native !== undefined) && {
|
||||
frontend: [
|
||||
...(options.web === false ? [] : options.web === true ? ["web"] : []),
|
||||
...(options.native === false
|
||||
? []
|
||||
: options.native === true
|
||||
? ["native"]
|
||||
: []),
|
||||
] as ProjectFrontend[],
|
||||
}),
|
||||
};
|
||||
|
||||
if (!options.yes && Object.keys(flagConfig).length > 0) {
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
import { cancel, confirm, isCancel } from "@clack/prompts";
|
||||
import { cancel, confirm, isCancel, log } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { ProjectFrontend } from "../types";
|
||||
|
||||
export async function getAuthChoice(
|
||||
auth: boolean | undefined,
|
||||
hasDatabase: boolean,
|
||||
frontends?: ProjectFrontend[],
|
||||
): Promise<boolean> {
|
||||
if (!hasDatabase) return false;
|
||||
|
||||
const hasNative = frontends?.includes("native");
|
||||
const hasWeb = frontends?.includes("web");
|
||||
|
||||
if (hasNative) {
|
||||
log.warn(
|
||||
pc.yellow("Note: Authentication is not yet available with native"),
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasWeb) return false;
|
||||
|
||||
if (auth !== undefined) return auth;
|
||||
|
||||
const response = await confirm({
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
ProjectConfig,
|
||||
ProjectDatabase,
|
||||
ProjectExamples,
|
||||
ProjectFrontend,
|
||||
ProjectOrm,
|
||||
Runtime,
|
||||
} from "../types";
|
||||
@@ -15,6 +16,7 @@ import { getAuthChoice } from "./auth";
|
||||
import { getBackendFrameworkChoice } from "./backend-framework";
|
||||
import { getDatabaseChoice } from "./database";
|
||||
import { getExamplesChoice } from "./examples";
|
||||
import { getFrontendChoice } from "./frontend-option";
|
||||
import { getGitChoice } from "./git";
|
||||
import { getNoInstallChoice } from "./install";
|
||||
import { getORMChoice } from "./orm";
|
||||
@@ -36,6 +38,7 @@ type PromptGroupResults = {
|
||||
turso: boolean;
|
||||
backendFramework: BackendFramework;
|
||||
runtime: Runtime;
|
||||
frontend: ProjectFrontend[];
|
||||
};
|
||||
|
||||
export async function gatherConfig(
|
||||
@@ -46,13 +49,18 @@ export async function gatherConfig(
|
||||
projectName: async () => {
|
||||
return getProjectName(flags.projectName);
|
||||
},
|
||||
frontend: () => getFrontendChoice(flags.frontend),
|
||||
backendFramework: () => getBackendFrameworkChoice(flags.backendFramework),
|
||||
runtime: () => getRuntimeChoice(flags.runtime),
|
||||
database: () => getDatabaseChoice(flags.database),
|
||||
orm: ({ results }) =>
|
||||
getORMChoice(flags.orm, results.database !== "none"),
|
||||
auth: ({ results }) =>
|
||||
getAuthChoice(flags.auth, results.database !== "none"),
|
||||
getAuthChoice(
|
||||
flags.auth,
|
||||
results.database !== "none",
|
||||
results.frontend,
|
||||
),
|
||||
turso: ({ results }) =>
|
||||
results.database === "sqlite" && results.orm !== "prisma"
|
||||
? getTursoSetupChoice(flags.turso)
|
||||
@@ -74,6 +82,7 @@ export async function gatherConfig(
|
||||
|
||||
return {
|
||||
projectName: result.projectName,
|
||||
frontend: result.frontend,
|
||||
database: result.database,
|
||||
orm: result.orm,
|
||||
auth: result.auth,
|
||||
|
||||
35
apps/cli/src/prompts/frontend-option.ts
Normal file
35
apps/cli/src/prompts/frontend-option.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { cancel, isCancel, multiselect } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { ProjectFrontend } from "../types";
|
||||
|
||||
export async function getFrontendChoice(
|
||||
frontendOptions?: ProjectFrontend[],
|
||||
): Promise<ProjectFrontend[]> {
|
||||
if (frontendOptions !== undefined) return frontendOptions;
|
||||
|
||||
const response = await multiselect<ProjectFrontend>({
|
||||
message: "Which frontend applications would you like to create?",
|
||||
options: [
|
||||
{
|
||||
value: "web",
|
||||
label: "Web App",
|
||||
hint: "React + TanStack Router web application",
|
||||
},
|
||||
{
|
||||
value: "native",
|
||||
label: "Native App",
|
||||
hint: "React Native + Expo application",
|
||||
},
|
||||
],
|
||||
initialValues: DEFAULT_CONFIG.frontend,
|
||||
required: false,
|
||||
});
|
||||
|
||||
if (isCancel(response)) {
|
||||
cancel(pc.red("Operation cancelled"));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export async function getORMChoice(
|
||||
{
|
||||
value: "prisma",
|
||||
label: "Prisma",
|
||||
hint: "Powerful, feature-rich ORM with schema migrations",
|
||||
hint: "Powerful, feature-rich ORM",
|
||||
},
|
||||
],
|
||||
initialValue: DEFAULT_CONFIG.orm,
|
||||
|
||||
@@ -5,6 +5,7 @@ export type ProjectAddons = "pwa" | "biome" | "tauri" | "husky";
|
||||
export type BackendFramework = "hono" | "elysia";
|
||||
export type Runtime = "node" | "bun";
|
||||
export type ProjectExamples = "todo";
|
||||
export type ProjectFrontend = "web" | "native";
|
||||
|
||||
export interface ProjectConfig {
|
||||
projectName: string;
|
||||
@@ -19,4 +20,5 @@ export interface ProjectConfig {
|
||||
packageManager: PackageManager;
|
||||
noInstall?: boolean;
|
||||
turso?: boolean;
|
||||
frontend: ProjectFrontend[];
|
||||
}
|
||||
|
||||
@@ -35,6 +35,20 @@ export function generateReproducibleCommand(config: ProjectConfig): string {
|
||||
flags.push(`--runtime ${config.runtime}`);
|
||||
}
|
||||
|
||||
if (config.frontend) {
|
||||
if (config.frontend.includes("web")) {
|
||||
flags.push("--web");
|
||||
} else {
|
||||
flags.push("--no-web");
|
||||
}
|
||||
|
||||
if (config.frontend.includes("native")) {
|
||||
flags.push("--native");
|
||||
} else {
|
||||
flags.push("--no-native");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.addons.length > 0) {
|
||||
for (const addon of config.addons) {
|
||||
flags.push(`--${addon}`);
|
||||
|
||||
Reference in New Issue
Block a user