Add Progressive Web App (PWA) support

Add PWA setup with vite-plugin-pwa, assets generator, and templates
Include CLI flag and interactive prompt option for PWA installation
This commit is contained in:
Aman Varshney
2025-03-22 13:05:45 +05:30
parent 9c53d77965
commit 66a47c7c61
11 changed files with 102 additions and 13 deletions

View File

@@ -0,0 +1,5 @@
---
"create-better-t-stack": minor
---
Add Progressive Web App (PWA) support

View File

@@ -28,6 +28,9 @@ export const dependencyVersionMap = {
"@prisma/client": "^5.7.1",
prisma: "^5.7.1",
"vite-plugin-pwa": "^0.21.2",
"@vite-pwa/assets-generator": "^0.2.6",
} as const;
export type AvailableDependencies = keyof typeof dependencyVersionMap;

View File

@@ -1,11 +1,16 @@
import path from "node:path";
import fs from "fs-extra";
import { PKG_ROOT } from "../constants";
import type { ProjectAddons } from "../types";
import { addPackageDependency } from "../utils/add-package-deps";
export async function setupAddons(projectDir: string, addons: ProjectAddons[]) {
if (addons.includes("docker")) {
await setupDocker(projectDir);
}
if (addons.includes("pwa")) {
await setupPwa(projectDir);
}
}
async function setupDocker(projectDir: string) {
@@ -89,3 +94,30 @@ node_modules
dockerignoreContent,
);
}
async function setupPwa(projectDir: string) {
const pwaTemplateDir = path.join(PKG_ROOT, "template/with-pwa");
if (await fs.pathExists(pwaTemplateDir)) {
await fs.copy(pwaTemplateDir, projectDir, { overwrite: true });
}
const clientPackageDir = path.join(projectDir, "packages/client");
addPackageDependency({
dependencies: ["vite-plugin-pwa"],
devDependencies: ["@vite-pwa/assets-generator"],
projectDir: clientPackageDir,
});
const clientPackageJsonPath = path.join(clientPackageDir, "package.json");
if (await fs.pathExists(clientPackageJsonPath)) {
const packageJson = await fs.readJson(clientPackageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
"generate-pwa-assets": "pwa-assets-generator",
};
await fs.writeJson(clientPackageJsonPath, packageJson, { spaces: 2 });
}
}

View File

@@ -135,15 +135,6 @@ cd packages/server && ${packageManagerRunCmd} db:local
`;
}
if (auth) {
setup += `
3. Generate the authentication schema:
\`\`\`bash
cd packages/server && ${packageManagerRunCmd} auth:generate
\`\`\`
`;
}
setup += `
${auth ? "4" : "3"}. ${
orm === "prisma"

View File

@@ -31,6 +31,7 @@ async function main() {
.option("--auth", "Include authentication")
.option("--no-auth", "Exclude authentication")
.option("--docker", "Include Docker setup")
.option("--pwa", "Include Progressive Web App support")
.option("--no-addons", "Skip all additional addons")
.option("--git", "Include git setup")
.option("--no-git", "Skip git initialization")
@@ -64,17 +65,20 @@ async function main() {
...(options.prisma && { orm: "prisma" }),
...("auth" in options && { auth: options.auth }),
...(options.npm && { packageManager: "npm" }),
...(options.pnpm && { packageManager: "pnpm" }),
...(options.pnpm && { packageManager: " pnpm" }),
...(options.yarn && { packageManager: "yarn" }),
...(options.bun && { packageManager: "bun" }),
...("git" in options && { git: options.git }),
...("install" in options && { noInstall: !options.install }),
...("turso" in options && { turso: options.turso }),
...((options.docker || options.addons === false) && {
...((options.docker || options.pwa || options.addons === false) && {
addons:
options.addons === false
? []
: ([...(options.docker ? ["docker"] : [])] as ProjectAddons[]),
: ([
...(options.docker ? ["docker"] : []),
...(options.pwa ? ["pwa"] : []),
] as ProjectAddons[]),
}),
};

View File

@@ -15,6 +15,11 @@ export async function getAddonsChoice(
label: "Docker setup",
hint: "Containerize your application",
},
{
value: "pwa",
label: "PWA (Progressive Web App)",
hint: "Make your app installable and work offline",
},
],
required: false,
});

View File

@@ -1,7 +1,7 @@
export type ProjectDatabase = "sqlite" | "postgres" | "none";
export type ProjectOrm = "drizzle" | "prisma" | "none";
export type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
export type ProjectAddons = "docker";
export type ProjectAddons = "docker" | "pwa";
export interface ProjectConfig {
projectName: string;

View File

@@ -19,3 +19,5 @@ dist/
*.env*
!.env.example
dev-dist

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,12 @@
import {
defineConfig,
minimal2023Preset as preset,
} from "@vite-pwa/assets-generator/config";
export default defineConfig({
headLinkOptions: {
preset: "2023",
},
preset,
images: ["public/logo.png"],
});

View File

@@ -0,0 +1,35 @@
import tailwindcss from "@tailwindcss/vite";
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
import react from "@vitejs/plugin-react";
import path from "path";
import { defineConfig } from "vite";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
plugins: [
tailwindcss(),
TanStackRouterVite({}),
react(),
VitePWA({
registerType: "autoUpdate",
manifest: {
name: "My App",
short_name: "My App ",
description: "My App",
theme_color: "#0c0c0c",
},
pwaAssets: {
disabled: false,
config: true,
},
devOptions: {
enabled: true,
},
}),
],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});