Repository: Blazity/next-enterprise Branch: main Commit: e5e9735e943c Files: 41 Total size: 56.6 KB Directory structure: gitextract_1vk2cap0/ ├── .all-contributorsrc ├── .github/ │ ├── nodejs.version │ └── workflows/ │ ├── check.yml │ ├── nextjs_bundle_analysis.yml │ └── playwright.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .prettierignore ├── .releaserc ├── .storybook/ │ ├── main.ts │ └── preview.ts ├── .vscode/ │ └── settings.json ├── LICENSE ├── README.md ├── app/ │ ├── api/ │ │ └── health/ │ │ └── route.ts │ ├── layout.tsx │ └── page.tsx ├── components/ │ ├── Button/ │ │ ├── Button.stories.tsx │ │ ├── Button.test.tsx │ │ └── Button.tsx │ └── Tooltip/ │ └── Tooltip.tsx ├── e2e/ │ └── example.spec.ts ├── env.mjs ├── eslint.config.mjs ├── git-conventional-commits.yaml ├── instrumentation.ts ├── lp-items.tsx ├── next-env.d.ts ├── next.config.ts ├── package.json ├── playwright.config.ts ├── postcss.config.js ├── prettier.config.js ├── renovate.json ├── report-bundle-size.js ├── reset.d.ts ├── styles/ │ └── tailwind.css ├── tsconfig.json ├── vercel.json ├── vitest.config.ts └── vitest.setup.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "projectName": "next-enterprise", "projectOwner": "Blazity", "repoType": "github", "repoHost": "https://github.com", "files": [ "README.md" ], "imageSize": 100, "commit": true, "commitConvention": "angular", "contributors": [ { "login": "bmstefanski", "name": "Bart Stefanski", "avatar_url": "https://avatars.githubusercontent.com/u/28964599?v=4", "profile": "https://bstefanski.com/", "contributions": [ "code" ] }, { "login": "jjablonski-it", "name": "Jakub Jabłoński", "avatar_url": "https://avatars.githubusercontent.com/u/51968772?v=4", "profile": "https://github.com/jjablonski-it", "contributions": [ "infra" ] }, { "login": "neg4n", "name": "Igor Klepacki", "avatar_url": "https://avatars.githubusercontent.com/u/57688858?v=4", "profile": "https://neg4n.dev/", "contributions": [ "doc" ] } ], "contributorsPerLine": 7, "linkToUsage": true, "commitType": "docs" } ================================================ FILE: .github/nodejs.version ================================================ v24.3.0 ================================================ FILE: .github/workflows/check.yml ================================================ name: Check on: push: branches: - main - master - develop pull_request: workflow_dispatch: jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo "node_version=$(cat .github/nodejs.version)" >> $GITHUB_ENV - name: "use node ${{ env.node_version }}" uses: actions/setup-node@v3 with: node-version: "${{ env.node_version }}" - name: "Install pnpm & dependencies" uses: pnpm/action-setup@v4 with: run_install: | - recursive: true - args: [--frozen-lockfile] - name: Lint check run: pnpm run lint - name: Format check run: pnpm run prettier - name: Unit & Integration tests run: pnpm run test - name: Smoke & Acceptance tests run: | pnpm run build-storybook --quiet pnpm playwright install pnpm dlx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \ "pnpm dlx http-server storybook-static --port 6006 --silent" \ "pnpm dlx wait-on tcp:127.0.0.1:6006 && pnpm run test-storybook" ================================================ FILE: .github/workflows/nextjs_bundle_analysis.yml ================================================ name: "Next.js Bundle Analysis" on: push: branches: - main - develop pull_request: branches: - main - develop workflow_dispatch: defaults: run: # change this if your nextjs app does not live at the root of the repo working-directory: ./ jobs: analyze: env: SKIP_ENV_VALIDATION: true runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up node uses: actions/setup-node@v3 with: node-version: "20.x" - name: "Install pnpm & dependencies" uses: pnpm/action-setup@v4 with: run_install: | - recursive: true - args: [--frozen-lockfile] # - name: Install dependencies # run: pnpm install --frozen-lockfile - name: Restore next build uses: actions/cache@v3 id: restore-build-cache env: cache-name: cache-next-build with: path: .next/cache # change this if you prefer a more strict cache key: ${{ runner.os }}-build-${{ env.cache-name }} - name: Build next.js app env: SKIP_BUILD_PRODUCT_REDIRECTS: 1 # change this if your site requires a custom build command run: pnpm build # Here's the first place where next-bundle-analysis' own script is used # This step pulls the raw bundle stats for the current bundle - name: Analyze bundle run: node report-bundle-size.js - name: Upload bundle uses: actions/upload-artifact@v4 with: name: bundle path: .next/analyze/__bundle_analysis.json - name: Download base branch bundle stats uses: dawidd6/action-download-artifact@v8 if: success() && github.event.number with: workflow: nextjs_bundle_analysis.yml branch: ${{ github.event.pull_request.base.ref }} path: .next/analyze/base # And here's the second place - this runs after we have both the current and # base branch bundle stats, and will compare them to determine what changed. # There are two configurable arguments that come from package.json: # # - budget: optional, set a budget (bytes) against which size changes are measured # it's set to 350kb here by default, as informed by the following piece: # https://infrequently.org/2021/03/the-performance-inequality-gap/ # # - red-status-percentage: sets the percent size increase where you get a red # status indicator, defaults to 20% # # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` # entry in your package.json file. - name: Compare with base branch bundle if: success() && github.event.number run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - name: Get comment body id: get-comment-body if: success() && github.event.number uses: actions/github-script@v6 with: result-encoding: string script: | const fs = require('fs') const comment = fs.readFileSync('.next/analyze/__bundle_analysis_comment.txt', 'utf8') core.setOutput('body', comment) - name: Find Comment uses: peter-evans/find-comment@v2 if: success() && github.event.number id: fc with: issue-number: ${{ github.event.number }} body-includes: "" - name: Create Comment uses: peter-evans/create-or-update-comment@v3 if: success() && github.event.number && steps.fc.outputs.comment-id == 0 with: issue-number: ${{ github.event.number }} body: ${{ steps.get-comment-body.outputs.body }} - name: Update Comment uses: peter-evans/create-or-update-comment@v3 if: success() && github.event.number && steps.fc.outputs.comment-id != 0 with: issue-number: ${{ github.event.number }} body: ${{ steps.get-comment-body.outputs.body }} comment-id: ${{ steps.fc.outputs.comment-id }} edit-mode: replace ================================================ FILE: .github/workflows/playwright.yml ================================================ name: Playwright Tests on: push: branches: - main - master - develop pull_request: null workflow_dispatch: null jobs: test: timeout-minutes: 60 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo "node_version=$(cat .github/nodejs.version)" >> $GITHUB_ENV - name: "use node ${{ env.node_version }}" uses: actions/setup-node@v3 with: node-version: "${{ env.node_version }}" - name: "Install pnpm & dependencies" uses: pnpm/action-setup@v4 with: run_install: | - recursive: true - args: [--frozen-lockfile] - name: Install Playwright Browsers run: pnpm playwright install --with-deps - name: Run Playwright tests run: pnpm playwright test - uses: actions/upload-artifact@v4 if: always() with: name: playwright-report path: playwright-report/ retention-days: 30 ================================================ FILE: .gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies node_modules .pnp .pnp.js # testing coverage # next.js .next/ out/ build # misc .DS_Store *.pem # debug npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* # local env files .env.local .env.development.local .env.test.local .env.production.local storybook-static/ /test-results/ /playwright-report/ /playwright/.cache/ /.npm-only-allow .pnpm-store/ ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/qoomon/git-conventional-commits rev: v2.6.3 hooks: - id: conventional-commits ================================================ FILE: .prettierignore ================================================ .next node_modules ================================================ FILE: .releaserc ================================================ { branches: ["main"], "plugins": [ ["@semantic-release/npm", { "npmPublish": false }], "@semantic-release/release-notes-generator", "@semantic-release/github", "@semantic-release/commit-analyzer", "@semantic-release/git", "@semantic-release/changelog", ], } ================================================ FILE: .storybook/main.ts ================================================ import type { StorybookConfig } from "@storybook/nextjs" const config: StorybookConfig = { stories: ["../components/**/*.stories.mdx", "../components/**/*.stories.@(js|jsx|ts|tsx)"], addons: ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions"], framework: { name: "@storybook/nextjs", options: {}, }, docs: { autodocs: "tag", }, typescript: { check: false, checkOptions: {}, reactDocgen: false, reactDocgenTypescriptOptions: { shouldExtractLiteralValuesFromEnum: true, propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), }, }, } export default config ================================================ FILE: .storybook/preview.ts ================================================ import type { Preview } from "@storybook/react" import "../styles/tailwind.css" const preview: Preview = { parameters: { actions: { argTypesRegex: "^on[A-Z].*" }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }, } export default preview ================================================ FILE: .vscode/settings.json ================================================ { "tailwindCSS.experimental.classRegex": [ ["cva(?:<[^>]*>)?(([^)]*))", "[\"'`]([^\"'`]*).*?[\"'`]", "(?:twMerge|twJoin)\\(([^\\);]*)[\\);]"] ] } ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 Blazity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # [Next.js Enterprise Boilerplate](https://blazity.com/open-source/nextjs-enterprise-boilerplate) A production-ready template for building enterprise applications with Next.js. This boilerplate provides a solid foundation with carefully selected technologies and ready-to-go infrastructure to help you develop high-quality applications efficiently. ## Motivation While most Next.js boilerplates focus on individual developer needs with excessive complexity, **next-enterprise** prioritizes strategic simplicity for enterprise teams. It offers a streamlined foundation with high-impact features that maximize developer productivity and accelerate time-to-market for business-critical applications. Logo > [!NOTE] > **Blazity** is a group of Next.js architects. We help organizations architect, optimize, and deploy high-performance Next.js applications at scale. Contact us at [contact@blazity.com](https://blazity.com) if you’d like to talk about your project. ## Documentation There is a separate documentation that explains its functionality, highlights core business values and technical decisions, provides guidelines for future development, and includes architectural diagrams. We encourage you to [visit our docs (docs.blazity.com)](https://docs.blazity.com) to learn more ## Integrated features ### Boilerplate With this template you will get all the boilerplate features included: * [Next.js 15](https://nextjs.org/) - Performance-optimized configuration using App Directory * [Tailwind CSS v4](https://tailwindcss.com/) - Utility-first CSS framework for efficient UI development * [ESlint 9](https://eslint.org/) and [Prettier](https://prettier.io/) - Code consistency and error prevention * [Corepack](https://github.com/nodejs/corepack) & [pnpm](https://pnpm.io/) as the package manager - For project management without compromises * [Strict TypeScript](https://www.typescriptlang.org/) - Enhanced type safety with carefully crafted config and [ts-reset](https://github.com/total-typescript/ts-reset) library * [GitHub Actions](https://github.com/features/actions) - Pre-configured workflows including bundle size and performance tracking * Perfect Lighthouse score - Optimized performance metrics * [Bundle analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) - Monitor and manage bundle size during development * Testing suite - [Vitest](https://vitest.dev), [React Testing Library](https://testing-library.com/react), and [Playwright](https://playwright.dev/) for comprehensive testing * [Storybook](https://storybook.js.org/) - Component development and documentation * Advanced testing - Smoke and acceptance testing capabilities * [Conventional commits](https://www.conventionalcommits.org/) - Standardized commit history management * [Observability](https://opentelemetry.io/) - Open Telemetry integration * [Absolute imports](https://nextjs.org/docs/advanced-features/module-path-aliases) - Simplified import structure * [Health checks](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) - Kubernetes-compatible monitoring * [Radix UI](https://www.radix-ui.com/) - Headless components for customization * [CVA](http://cva.style/) (Class Variance Authority) - Consistent design system creation * [Renovate BOT](https://www.whitesourcesoftware.com/free-developer-tools/renovate) - Automated dependency and security updates * [Patch-package](https://www.npmjs.com/package/patch-package) - External dependency fixes without compromises * Component relationship tools - Graph for managing coupling and cohesion * [Semantic Release](https://github.com/semantic-release/semantic-release) - Automated changelog generation * [T3 Env](https://env.t3.gg/) - Streamlined environment variable management ### Infrastructure & deployments #### Vercel Easily deploy your Next.js app with [Vercel](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=github&utm_campaign=next-enterprise) by clicking the button below: [![Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/Blazity/next-enterprise) #### Custom cloud infrastructure **next-enterprise** offers dedicated infrastructure as code (IaC) solutions built with Terraform, designed specifically for deploying Next.js applications based on our extensive experience working with enterprise clients. Learn more in our [documentation (docs.blazity.com)][docs] how to quickstart with the deployments using simple CLI. #### Available cloud providers and theirs features: * **AWS (Amazon Web Services)** * Automated provisioning of AWS infrastructure * Scalable & secure setup using: * VPC - Isolated network infrastructure * Elastic Container Service (ECS) - Container orchestration * Elastic Container Registry (ECR) - Container image storage * Application Load Balancer - Traffic distribution * S3 + CloudFront - Static asset delivery and caching * AWS WAF - Web Application Firewall protection * Redis Cluster - Caching * CI/CD ready - Continuous integration and deployment pipeline *... more coming soon* ### Team & maintenance **next-enterprise** is backed and maintained by [Blazity](https://blazity.com), providing up to date security features and integrated feature updates. #### Active maintainers - Igor Klepacki ([neg4n](https://github.com/neg4n)) - Open Source Software Developer - Tomasz Czechowski ([tomaszczechowski](https://github.com/tomaszczechowski)) - Solutions Architect & DevOps - Jakub Jabłoński ([jjablonski-it](https://github.com/jjablonski-it)) - Head of Integrations #### All-time contributors [bmstefanski](https://github.com/bmstefanski) ## License MIT [docs]: https://docs.blazity.com/next-enterprise/deployments/enterprise-cli ================================================ FILE: app/api/health/route.ts ================================================ export async function GET() { return Response.json({ status: "ok" }) } ================================================ FILE: app/layout.tsx ================================================ import "styles/tailwind.css" export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ) } ================================================ FILE: app/page.tsx ================================================ import { Metadata } from "next" import { Button } from "components/Button/Button" import { LP_GRID_ITEMS } from "lp-items" export const metadata: Metadata = { title: "Next.js Enterprise Boilerplate", twitter: { card: "summary_large_image", }, openGraph: { url: "https://next-enterprise.vercel.app/", images: [ { width: 1200, height: 630, url: "https://raw.githubusercontent.com/Blazity/next-enterprise/main/.github/assets/project-logo.png", }, ], }, } export default function Web() { return ( <>

Next.js Enterprise Boilerplate

Jumpstart your enterprise project with our feature-packed, high-performance Next.js boilerplate! Experience rapid UI development, AI-powered code reviews, and an extensive suite of tools for a smooth and enjoyable development process.

{LP_GRID_ITEMS.map((singleItem) => (
{singleItem.icon}

{singleItem.title}

{singleItem.description}

))}
) } ================================================ FILE: components/Button/Button.stories.tsx ================================================ import type { Meta, StoryObj } from "@storybook/react" import { Button } from "./Button" const meta: Meta = { title: "Button", component: Button, args: { intent: "primary", underline: false, children: "Button", size: "lg", }, argTypes: { intent: { options: ["primary", "secondary"], control: { type: "select" }, }, size: { options: ["sm", "lg"], control: { type: "select" }, }, }, } type Story = StoryObj export const Default: Story = { render: (args) => ) expect(screen.getByText("Click me")).toBeInTheDocument() }) it("applies correct intent classes", () => { const { container } = render( ) const link = container.querySelector("a") expect(link).toHaveClass("bg-transparent") expect(link).toHaveClass("text-blue-400") }) it("applies correct size classes", () => { const { container } = render( ) const link = container.querySelector("a") expect(link).toHaveClass("text-sm") expect(link).toHaveClass("min-w-20") }) }) ================================================ FILE: components/Button/Button.tsx ================================================ import { cva, type VariantProps } from "class-variance-authority" import { twMerge } from "tailwind-merge" const button = cva( [ "justify-center", "inline-flex", "items-center", "rounded-xl", "text-center", "border", "border-blue-400", "transition-colors", "delay-50", ], { variants: { intent: { primary: ["bg-blue-400", "text-white", "hover:enabled:bg-blue-700"], secondary: ["bg-transparent", "text-blue-400", "hover:enabled:bg-blue-400", "hover:enabled:text-white"], }, size: { sm: ["min-w-20", "h-full", "min-h-10", "text-sm", "py-1.5", "px-4"], lg: ["min-w-32", "h-full", "min-h-12", "text-lg", "py-2.5", "px-6"], }, underline: { true: ["underline"], false: [] }, }, defaultVariants: { intent: "primary", size: "lg", }, } ) export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { underline?: boolean href: string } export function Button({ className, intent, size, underline, ...props }: ButtonProps) { return ( {props.children} ) } ================================================ FILE: components/Tooltip/Tooltip.tsx ================================================ "use client" import * as RadixTooltip from "@radix-ui/react-tooltip" import { cva, type VariantProps } from "class-variance-authority" import React from "react" import { twMerge } from "tailwind-merge" const tooltipContent = cva([], { variants: { intent: { primary: ["rounded-md", "bg-zinc-700", "font-sans", "text-white"], }, size: { md: ["px-4", "py-2.5", "text-xs"], }, }, defaultVariants: { intent: "primary", size: "md", }, }) const tooltipArrow = cva([], { variants: { intent: { primary: ["fill-zinc-700"], }, size: { md: ["w-4", "h-2"], }, }, defaultVariants: { intent: "primary", size: "md", }, }) export interface TooltipProps extends VariantProps, RadixTooltip.TooltipProps { explainer: React.ReactElement | string children: React.ReactElement className?: string withArrow?: boolean side?: "top" | "right" | "bottom" | "left" } export function Tooltip({ children, explainer, open, defaultOpen, onOpenChange, intent, size, side = "top", className, withArrow, }: TooltipProps) { return ( {children} {explainer} {withArrow ? : null} ) } ================================================ FILE: e2e/example.spec.ts ================================================ import { expect, test } from "@playwright/test" test("has title", async ({ page }) => { await page.goto("./") await expect(page).toHaveTitle(/Next.js Enterprise Boilerplate/) }) ================================================ FILE: env.mjs ================================================ import { createEnv } from "@t3-oss/env-nextjs" import { z } from "zod" export const env = createEnv({ server: { ANALYZE: z .enum(["true", "false"]) .optional() .transform((value) => value === "true"), }, client: {}, runtimeEnv: { ANALYZE: process.env.ANALYZE, }, }) ================================================ FILE: eslint.config.mjs ================================================ import * as fs from "fs" // https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/381 // import eslintPluginTailwindcss from "eslint-plugin-tailwindcss" import eslintPluginImport from "eslint-plugin-import" import eslintPluginNext from "@next/eslint-plugin-next" import eslintPluginStorybook from "eslint-plugin-storybook" import typescriptEslint from "typescript-eslint" const eslintIgnore = [ ".git/", ".next/", "node_modules/", "dist/", "build/", "coverage/", "*.min.js", "*.config.js", "*.d.ts", ] const config = typescriptEslint.config( { ignores: eslintIgnore, }, ...eslintPluginStorybook.configs["flat/recommended"], // https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/381 // ...eslintPluginTailwindcss.configs["flat/recommended"], typescriptEslint.configs.recommended, eslintPluginImport.flatConfigs.recommended, { plugins: { "@next/next": eslintPluginNext, }, rules: { ...eslintPluginNext.configs.recommended.rules, ...eslintPluginNext.configs["core-web-vitals"].rules, }, }, { settings: { tailwindcss: { callees: ["classnames", "clsx", "ctl", "cn", "cva"], }, "import/resolver": { typescript: true, node: true, }, }, rules: { "@typescript-eslint/no-unused-vars": [ "warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_", }, ], "sort-imports": [ "error", { ignoreCase: true, ignoreDeclarationSort: true, }, ], "import/order": [ "warn", { groups: ["external", "builtin", "internal", "sibling", "parent", "index"], pathGroups: [ ...getDirectoriesToSort().map((singleDir) => ({ pattern: `${singleDir}/**`, group: "internal", })), { pattern: "env", group: "internal", }, { pattern: "theme", group: "internal", }, { pattern: "public/**", group: "internal", position: "after", }, ], pathGroupsExcludedImportTypes: ["internal"], alphabetize: { order: "asc", caseInsensitive: true, }, }, ], }, } ) function getDirectoriesToSort() { const ignoredSortingDirectories = [".git", ".next", ".vscode", "node_modules"] return fs .readdirSync(process.cwd()) .filter((file) => fs.statSync(process.cwd() + "/" + file).isDirectory()) .filter((f) => !ignoredSortingDirectories.includes(f)) } export default config ================================================ FILE: git-conventional-commits.yaml ================================================ --- convention: commitTypes: - feat - fix - perf - refactor - style - test - build - ops - docs - chore - merge - revert commitScopes: [] releaseTagGlobPattern: v[0-9]*.[0-9]*.[0-9]* changelog: commitTypes: - feat - fix - perf - merge includeInvalidCommits: true commitIgnoreRegexPattern: "^WIP " headlines: feat: Features fix: Bug Fixes perf: Performance Improvements merge: Merges breakingChange: BREAKING CHANGES ## GitHub # commitUrl: https://github.com/ACCOUNT/REPOSITORY/commit/%commit% # commitRangeUrl: https://github.com/ACCOUNT/REPOSITORY/compare/%from%...%to%?diff=split ## GitHub Issues # issueRegexPattern: "#[0-9]+" # issueUrl: https://github.com/ACCOUNT/REPOSITORY/issues/%issue% ## Jira Issues # issueRegexPattern: "[A-Z][A-Z0-9]+-[0-9]+" # issueUrl: https://WORKSPACE.atlassian.net/browse/%issue% ================================================ FILE: instrumentation.ts ================================================ import { registerOTel } from "@vercel/otel" export function register() { registerOTel("next-app") } ================================================ FILE: lp-items.tsx ================================================ export const LP_GRID_ITEMS = [ { title: "Next.js", description: "Fast by default, with config optimized for performance.", icon: ( ), }, { title: "Tailwind CSS", description: "A utility-first CSS framework for rapid UI development.", icon: ( ), }, { title: "ESlint & Prettier", description: "For clean, consistent, and error-free code.", icon: ( ), }, { title: "Extremely strict TypeScript", description: "With `ts-reset` library for ultimate type safety.", icon: ( ), }, { title: "Bundle analyzer plugin", description: "Keep an eye on your bundle size.", icon: ( ), }, { title: "Vitest & React Testing Library", description: "For rock-solid unit and integration tests.", icon: ( ), }, { title: "Playwright", description: "Write end-to-end tests like a pro.", icon: ( ), }, { title: "Storybook", description: "Create, test, and showcase your components.", icon: ( ), }, { title: "Smoke Testing & Acceptance Tests", description: "For confidence in your deployments.", icon: ( ), }, { title: "Conventional commits git hook", description: "Keep your commit history neat and tidy.", icon: ( ), }, { title: "Observability", description: "Open Telemetry integration for seamless monitoring.", icon: ( ), }, { title: "Absolute imports", description: "No more spaghetti imports.", icon: ( ), }, { title: "Health checks", description: "Kubernetes-compatible for robust deployments.", icon: ( ), }, { title: "Radix UI", description: "Headless UI components for endless customization.", icon: ( ), }, { title: "CVA", description: "Create a consistent, reusable, and atomic design system.", icon: ( ), }, { title: "Renovate BOT", description: "Auto-updating dependencies, so you can focus on coding.", icon: ( ), }, { title: "Patch-package", description: "Fix external dependencies without losing your mind.", icon: ( ), }, { title: "Components coupling & cohesion graph", description: "A tool for managing component relationships.", icon: ( ), }, { title: "GitHub Actions", description: "Pre-configured actions for smooth workflows, including Bundle Size and performance stats.", icon: ( ), }, { title: "Automated ChatGPT Code Reviews", description: "Stay on the cutting edge with AI-powered code reviews!", icon: ( ), }, { title: "Semantic Release", description: "For automatic changelog generation.", icon: ( ), }, ] ================================================ FILE: next-env.d.ts ================================================ /// /// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. ================================================ FILE: next.config.ts ================================================ import withBundleAnalyzer from "@next/bundle-analyzer" import { type NextConfig } from "next" import { env } from "./env.mjs" const config: NextConfig = { reactStrictMode: true, logging: { fetches: { fullUrl: true, }, }, rewrites: async () => [ { source: "/healthz", destination: "/api/health" }, { source: "/api/healthz", destination: "/api/health" }, { source: "/health", destination: "/api/health" }, { source: "/ping", destination: "/api/health" }, ], } export default env.ANALYZE ? withBundleAnalyzer({ enabled: env.ANALYZE })(config) : config ================================================ FILE: package.json ================================================ { "name": "next-enterprise", "version": "0.0.0", "private": true, "scripts": { "dev": "cross-env FORCE_COLOR=1 next dev --turbo", "build": "next build", "start": "next start", "lint": "next lint", "lint:fix": "next lint --fix", "prettier": "prettier --check \"**/*.{js,jsx,ts,tsx}\"", "prettier:fix": "prettier --write \"**/*.{js,jsx,ts,tsx}\"", "analyze": "cross-env ANALYZE=true pnpm run build", "storybook": "cross-env FORCE_COLOR=1 storybook dev -p 6006", "test-storybook": "cross-env FORCE_COLOR=1 test-storybook", "build-storybook": "cross-env FORCE_COLOR=1 storybook build", "test": "cross-env FORCE_COLOR=1 vitest", "test:watch": "cross-env FORCE_COLOR=1 vitest --watch", "test:ui": "cross-env FORCE_COLOR=1 vitest --ui", "test:coverage": "cross-env FORCE_COLOR=1 vitest --coverage", "e2e:headless": "playwright test", "e2e:ui": "playwright test --ui", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "postinstall": "npx patch-package -y", "coupling-graph": "npx madge --extensions js,jsx,ts,tsx,css,md,mdx ./ --exclude '.next|tailwind.config.js|reset.d.ts|prettier.config.js|postcss.config.js|playwright.config.ts|next.config.js|next-env.d.ts|instrumentation.ts|e2e/|README.md|.storybook/|.eslintrc.js' --image graph.svg" }, "dependencies": { "@next/bundle-analyzer": "^15.3.1", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-form": "^0.1.8", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-radio-group": "^1.3.8", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slider": "^1.3.6", "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", "@semantic-release/changelog": "^6.0.3", "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/git": "^10.0.1", "@semantic-release/github": "^12.0.6", "@semantic-release/npm": "^13.1.5", "@semantic-release/release-notes-generator": "^14.1.0", "@t3-oss/env-nextjs": "^0.13.10", "@vercel/otel": "^1.12.0", "class-variance-authority": "^0.7.1", "lodash": "^4.17.23", "next": "15.5.10", "react": "^19.2.4", "react-dom": "^19.2.4", "tailwind-merge": "^3.5.0", "zod": "^3.24.4" }, "devDependencies": { "@babel/core": "^7.29.0", "@babel/plugin-syntax-flow": "^7.28.6", "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-react-jsx": "^7.28.6", "@eslint/eslintrc": "^3.3.5", "@next/eslint-plugin-next": "15.1.6", "@opentelemetry/api": "1.7.0", "@opentelemetry/resources": "1.18.1", "@opentelemetry/sdk-node": "0.45.1", "@opentelemetry/sdk-trace-node": "1.18.1", "@opentelemetry/semantic-conventions": "1.40.0", "@playwright/test": "^1.58.2", "@storybook/addon-controls": "^8.6.14", "@storybook/addon-essentials": "^8.6.14", "@storybook/addon-interactions": "^8.6.14", "@storybook/addon-links": "^8.6.14", "@storybook/blocks": "^8.6.14", "@storybook/nextjs": "^8.6.14", "@storybook/react": "^8.6.14", "@storybook/test": "^8.6.18", "@storybook/test-runner": "^0.21.3", "@tailwindcss/postcss": "^4.2.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@total-typescript/ts-reset": "^0.6.1", "@types/node": "^22.15.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@typescript-eslint/eslint-plugin": "^8.57.1", "@vitejs/plugin-react": "^4.7.0", "@vitest/ui": "^3.2.4", "all-contributors-cli": "^6.26.1", "cross-env": "^7.0.3", "eslint": "^9.26.0", "eslint-config-next": "15.1.6", "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.32.0", "eslint-plugin-storybook": "^0.11.6", "eslint-plugin-tailwindcss": "^3.18.2", "fetch-mock": "^12.6.0", "gzip-size": "6.0.0", "jsdom": "^26.1.0", "mkdirp": "^3.0.1", "patch-package": "^8.0.1", "postcss": "^8.5.8", "postcss-import": "^16.1.1", "postinstall-postinstall": "^2.1.0", "prettier": "^3.8.1", "prettier-plugin-tailwindcss": "^0.7.2", "semantic-release": "^25.0.3", "storybook": "^8.6.18", "tailwindcss": "^4.2.1", "tsc": "^2.0.4", "typed-query-selector": "^2.12.1", "typescript": "^5.9.3", "typescript-eslint": "^8.57.1", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.2.4", "webpack": "5.99.9" }, "engines": { "node": ">=20.0.0" }, "packageManager": "pnpm@10.0.0", "pnpm": { "overrides": { "tmp@<=0.2.3": ">=0.2.4" } } } ================================================ FILE: playwright.config.ts ================================================ import { defineConfig, devices } from "@playwright/test" /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ // require('dotenv').config(); /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ testDir: "./e2e", /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: "http://127.0.0.1:3000", /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: "on-first-retry", }, /* Configure projects for major browsers */ projects: [ { name: "chromium", use: { ...devices["Desktop Chrome"] }, }, { name: "firefox", use: { ...devices["Desktop Firefox"] }, }, { name: "webkit", use: { ...devices["Desktop Safari"] }, }, /* Test against mobile viewports. */ // { // name: 'Mobile Chrome', // use: { ...devices['Pixel 5'] }, // }, // { // name: 'Mobile Safari', // use: { ...devices['iPhone 12'] }, // }, /* Test against branded browsers. */ // { // name: 'Microsoft Edge', // use: { ...devices['Desktop Edge'], channel: 'msedge' }, // }, // { // name: 'Google Chrome', // use: { ..devices['Desktop Chrome'], channel: 'chrome' }, // }, ], /* Run your local dev server before starting the tests */ webServer: { command: "pnpm dev", url: "http://127.0.0.1:3000", reuseExistingServer: !process.env.CI, }, }) ================================================ FILE: postcss.config.js ================================================ module.exports = { plugins: { "postcss-import": {}, "@tailwindcss/postcss": {}, }, } ================================================ FILE: prettier.config.js ================================================ module.exports = { plugins: ["prettier-plugin-tailwindcss"], trailingComma: "es5", tabWidth: 2, printWidth: 120, semi: false, } ================================================ FILE: renovate.json ================================================ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base" ], "packageRules": [ { "enabled": false, "matchPackagePatterns": ["*"] } ], "vulnerabilityAlerts": { "enabled": true }, "osvVulnerabilityAlerts": true } ================================================ FILE: report-bundle-size.js ================================================ #!/usr/bin/env node /* eslint-disable no-console */ /** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ // edited to work with the appdir by @raphaelbadia const gzSize = require("gzip-size") const mkdirp = require("mkdirp") const fs = require("fs") const path = require("path") // Pull options from `package.json` const options = getOptions() const BUILD_OUTPUT_DIRECTORY = getBuildOutputDirectory(options) // first we check to make sure that the build output directory exists const nextMetaRoot = path.join(process.cwd(), BUILD_OUTPUT_DIRECTORY) try { fs.accessSync(nextMetaRoot, fs.constants.R_OK) } catch (err) { console.error( `No build output found at "${nextMetaRoot}" - you may not have your working directory set correctly, or not have run "next build".` ) process.exit(1) } // if so, we can import the build manifest const buildMeta = require(path.join(nextMetaRoot, "build-manifest.json")) const appDirMeta = require(path.join(nextMetaRoot, "app-build-manifest.json")) // this memory cache ensures we dont read any script file more than once // bundles are often shared between pages const memoryCache = {} // since _app is the template that all other pages are rendered into, // every page must load its scripts. we'll measure its size here const globalBundle = buildMeta.pages["/_app"] const globalBundleSizes = getScriptSizes(globalBundle) // next, we calculate the size of each page's scripts, after // subtracting out the global scripts const allPageSizes = Object.values(buildMeta.pages).reduce((acc, scriptPaths, i) => { const pagePath = Object.keys(buildMeta.pages)[i] const scriptSizes = getScriptSizes(scriptPaths.filter((scriptPath) => !globalBundle.includes(scriptPath))) acc[pagePath] = scriptSizes return acc }, {}) const globalAppDirBundle = buildMeta.rootMainFiles const globalAppDirBundleSizes = getScriptSizes(globalAppDirBundle) const allAppDirSizes = Object.values(appDirMeta.pages).reduce((acc, scriptPaths, i) => { const pagePath = Object.keys(appDirMeta.pages)[i] const scriptSizes = getScriptSizes(scriptPaths.filter((scriptPath) => !globalAppDirBundle.includes(scriptPath))) acc[pagePath] = scriptSizes return acc }, {}) // format and write the output const rawData = JSON.stringify({ ...allAppDirSizes, __global: globalAppDirBundleSizes, }) // log ouputs to the gh actions panel console.log(rawData) mkdirp.sync(path.join(nextMetaRoot, "analyze/")) fs.writeFileSync(path.join(nextMetaRoot, "analyze/__bundle_analysis.json"), rawData) // -------------- // Util Functions // -------------- // given an array of scripts, return the total of their combined file sizes function getScriptSizes(scriptPaths) { const res = scriptPaths.reduce( (acc, scriptPath) => { const [rawSize, gzipSize] = getScriptSize(scriptPath) acc.raw += rawSize acc.gzip += gzipSize return acc }, { raw: 0, gzip: 0 } ) return res } // given an individual path to a script, return its file size function getScriptSize(scriptPath) { const encoding = "utf8" const p = path.join(nextMetaRoot, scriptPath) let rawSize, gzipSize if (Object.keys(memoryCache).includes(p)) { rawSize = memoryCache[p][0] gzipSize = memoryCache[p][1] } else { const textContent = fs.readFileSync(p, encoding) rawSize = Buffer.byteLength(textContent, encoding) gzipSize = gzSize.sync(textContent) memoryCache[p] = [rawSize, gzipSize] } return [rawSize, gzipSize] } /** * Reads options from `package.json` */ function getOptions(pathPrefix = process.cwd()) { const pkg = require(path.join(pathPrefix, "package.json")) return { ...pkg.nextBundleAnalysis, name: pkg.name } } /** * Gets the output build directory, defaults to `.next` * * @param {object} options the options parsed from package.json.nextBundleAnalysis using `getOptions` * @returns {string} */ function getBuildOutputDirectory(options) { return options.buildOutputDirectory || ".next" } ================================================ FILE: reset.d.ts ================================================ import "@total-typescript/ts-reset" import "typed-query-selector/strict" ================================================ FILE: styles/tailwind.css ================================================ @import 'tailwindcss'; /* The default border color has changed to `currentColor` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. If we ever want to remove these styles, we need to add an explicit border color utility to any element that depends on these defaults. */ @layer base { *, ::after, ::before, ::backdrop, ::file-selector-button { border-color: var(--color-gray-200, currentColor); } } ================================================ FILE: tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "display": "Next.js", "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "noUncheckedIndexedAccess": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "baseUrl": ".", "types": ["node", "vitest/globals", "@testing-library/jest-dom"], "plugins": [ { "name": "next" } ] }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mjs", "vitest.config.ts", ".next/types/**/*.ts", "eslint.config.mjs"], "exclude": ["node_modules"] } ================================================ FILE: vercel.json ================================================ { "$schema": "https://openapi.vercel.sh/vercel.json", "installCommand": "corepack enable && pnpm install" } ================================================ FILE: vitest.config.ts ================================================ import { defineConfig } from "vitest/config" import react from "@vitejs/plugin-react" import tsconfigPaths from "vite-tsconfig-paths" export default defineConfig({ plugins: [tsconfigPaths(), react()], test: { environment: "jsdom", setupFiles: "./vitest.setup.ts", globals: true, include: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"], exclude: ["**/node_modules/**", "**/dist/**", "**/e2e/**", ".next/**"], }, }) ================================================ FILE: vitest.setup.ts ================================================ import "@testing-library/jest-dom"