├── .gitignore
├── app-search-turborepo
├── .eslintrc.js
├── .gitignore
├── .npmrc
├── .vscode
│ └── settings.json
├── README.md
├── apps
│ └── app-search
│ │ ├── .eslintrc.js
│ │ ├── README.md
│ │ ├── app
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── users
│ │ │ └── page.tsx
│ │ ├── next-env.d.ts
│ │ ├── next.config.js
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── public
│ │ ├── circles.svg
│ │ ├── next.svg
│ │ ├── turborepo.svg
│ │ └── vercel.svg
│ │ ├── tailwind.config.js
│ │ └── tsconfig.json
├── package.json
├── packages
│ ├── eslint-config
│ │ ├── README.md
│ │ ├── library.js
│ │ ├── next.js
│ │ ├── package.json
│ │ └── react-internal.js
│ ├── typescript-config
│ │ ├── base.json
│ │ ├── nextjs.json
│ │ ├── package.json
│ │ └── react-library.json
│ └── ui
│ │ ├── .eslintrc.js
│ │ ├── package.json
│ │ ├── src
│ │ ├── Comments.tsx
│ │ ├── SearchableComments.tsx
│ │ ├── Users.tsx
│ │ └── types.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.lint.json
│ │ └── turbo
│ │ └── generators
│ │ ├── config.ts
│ │ └── templates
│ │ └── component.hbs
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── tsconfig.json
└── turbo.json
├── app-search
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── app
│ │ ├── components
│ │ │ ├── Comments.tsx
│ │ │ ├── SearchableComments.tsx
│ │ │ └── Users.tsx
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── users
│ │ │ └── page.tsx
│ └── types.ts
├── tailwind.config.ts
└── tsconfig.json
├── app-simple
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── app
│ │ ├── components
│ │ │ ├── Comments.tsx
│ │ │ └── Users.tsx
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── users
│ │ │ └── page.tsx
│ └── types.ts
├── tailwind.config.ts
└── tsconfig.json
├── app-suspense
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── app
│ │ ├── components
│ │ │ ├── Comments.tsx
│ │ │ └── Users.tsx
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── users
│ │ │ └── page.tsx
│ └── constants.ts
├── tailwind.config.ts
└── tsconfig.json
├── pages-search
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
│ ├── favicon.ico
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── api
│ │ │ └── comment-search.ts
│ │ ├── components
│ │ │ ├── Comments.tsx
│ │ │ └── Users.tsx
│ │ ├── index.tsx
│ │ └── users.tsx
│ ├── styles
│ │ └── globals.css
│ └── types.ts
├── tailwind.config.ts
└── tsconfig.json
├── pages-simple
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
│ ├── favicon.ico
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── api
│ │ │ └── hello.ts
│ │ ├── components
│ │ │ ├── Comments.tsx
│ │ │ └── Users.tsx
│ │ ├── index.tsx
│ │ └── users.tsx
│ ├── styles
│ │ └── globals.css
│ └── types.ts
├── tailwind.config.ts
└── tsconfig.json
└── pages-suspense
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
├── favicon.ico
├── next.svg
└── vercel.svg
├── src
├── constants.ts
├── getCommentsServer.ts
├── getUsersServer.ts
├── pages
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── api
│ │ ├── comments.ts
│ │ └── users.ts
│ ├── components
│ │ ├── Comments.tsx
│ │ └── Users.tsx
│ ├── index.tsx
│ └── users.tsx
├── styles
│ └── globals.css
└── types.ts
├── tailwind.config.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .next
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/app-search-turborepo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // This configuration only applies to the package manager root.
2 | /** @type {import("eslint").Linter.Config} */
3 | module.exports = {
4 | ignorePatterns: ["apps/**", "packages/**"],
5 | extends: ["@repo/eslint-config/library.js"],
6 | parser: "@typescript-eslint/parser",
7 | parserOptions: {
8 | project: true,
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/app-search-turborepo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # Dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # Local env files
9 | .env
10 | .env.local
11 | .env.development.local
12 | .env.test.local
13 | .env.production.local
14 |
15 | # Testing
16 | coverage
17 |
18 | # Turbo
19 | .turbo
20 |
21 | # Vercel
22 | .vercel
23 |
24 | # Build Outputs
25 | .next/
26 | out/
27 | build
28 | dist
29 |
30 |
31 | # Debug
32 | npm-debug.log*
33 | yarn-debug.log*
34 | yarn-error.log*
35 |
36 | # Misc
37 | .DS_Store
38 | *.pem
39 |
--------------------------------------------------------------------------------
/app-search-turborepo/.npmrc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/app-search-turborepo/.npmrc
--------------------------------------------------------------------------------
/app-search-turborepo/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.workingDirectories": [
3 | {
4 | "mode": "auto"
5 | }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/app-search-turborepo/README.md:
--------------------------------------------------------------------------------
1 | # Turborepo starter
2 |
3 | This is an official starter Turborepo.
4 |
5 | ## Using this example
6 |
7 | Run the following command:
8 |
9 | ```sh
10 | npx create-turbo@latest
11 | ```
12 |
13 | ## What's inside?
14 |
15 | This Turborepo includes the following packages/apps:
16 |
17 | ### Apps and Packages
18 |
19 | - `docs`: a [Next.js](https://nextjs.org/) app
20 | - `web`: another [Next.js](https://nextjs.org/) app
21 | - `@repo/ui`: a stub React component library shared by both `web` and `docs` applications
22 | - `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`)
23 | - `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo
24 |
25 | Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).
26 |
27 | ### Utilities
28 |
29 | This Turborepo has some additional tools already setup for you:
30 |
31 | - [TypeScript](https://www.typescriptlang.org/) for static type checking
32 | - [ESLint](https://eslint.org/) for code linting
33 | - [Prettier](https://prettier.io) for code formatting
34 |
35 | ### Build
36 |
37 | To build all apps and packages, run the following command:
38 |
39 | ```
40 | cd my-turborepo
41 | pnpm build
42 | ```
43 |
44 | ### Develop
45 |
46 | To develop all apps and packages, run the following command:
47 |
48 | ```
49 | cd my-turborepo
50 | pnpm dev
51 | ```
52 |
53 | ### Remote Caching
54 |
55 | Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines.
56 |
57 | By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup), then enter the following commands:
58 |
59 | ```
60 | cd my-turborepo
61 | npx turbo login
62 | ```
63 |
64 | This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview).
65 |
66 | Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo:
67 |
68 | ```
69 | npx turbo link
70 | ```
71 |
72 | ## Useful Links
73 |
74 | Learn more about the power of Turborepo:
75 |
76 | - [Tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks)
77 | - [Caching](https://turbo.build/repo/docs/core-concepts/caching)
78 | - [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching)
79 | - [Filtering](https://turbo.build/repo/docs/core-concepts/monorepos/filtering)
80 | - [Configuration Options](https://turbo.build/repo/docs/reference/configuration)
81 | - [CLI Usage](https://turbo.build/repo/docs/reference/command-line-reference)
82 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /** @type {import("eslint").Linter.Config} */
2 | module.exports = {
3 | root: true,
4 | extends: ["@repo/eslint-config/next.js"],
5 | parser: "@typescript-eslint/parser",
6 | parserOptions: {
7 | project: true,
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/README.md:
--------------------------------------------------------------------------------
1 | ## Getting Started
2 |
3 | First, run the development server:
4 |
5 | ```bash
6 | yarn dev
7 | ```
8 |
9 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
10 |
11 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
12 |
13 | To create [API routes](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) add an `api/` directory to the `app/` directory with a `route.ts` file. For individual endpoints, create a subfolder in the `api` directory, like `api/hello/route.ts` would map to [http://localhost:3000/api/hello](http://localhost:3000/api/hello).
14 |
15 | ## Learn More
16 |
17 | To learn more about Next.js, take a look at the following resources:
18 |
19 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
20 | - [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial.
21 |
22 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
23 |
24 | ## Deploy on Vercel
25 |
26 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js.
27 |
28 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
29 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/app-search-turborepo/apps/app-search/app/favicon.ico
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import "./globals.css";
2 | import type { Metadata } from "next";
3 | import { Inter } from "next/font/google";
4 |
5 | const inter = Inter({ subsets: ["latin"] });
6 |
7 | export const metadata: Metadata = {
8 | title: "Create Turborepo",
9 | description: "Generated by create turbo",
10 | };
11 |
12 | export default function RootLayout({
13 | children,
14 | }: {
15 | children: React.ReactNode;
16 | }): JSX.Element {
17 | return (
18 |
19 |
{children}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/app/page.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "@repo/ui/Comments";
2 |
3 | export default function Page() {
4 | return (
5 |
6 |
Home Page
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/app/users/page.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "@repo/ui/Comments";
2 | import Users from "@repo/ui/Users";
3 |
4 | export default function Home() {
5 | return (
6 |
7 |
Users Page
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | module.exports = {
3 | transpilePackages: ["@repo/ui"],
4 | };
5 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-search",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "eslint . --max-warnings 0"
10 | },
11 | "dependencies": {
12 | "@repo/ui": "workspace:*",
13 | "next": "^14.0.4",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "devDependencies": {
18 | "@next/eslint-plugin-next": "^14.0.4",
19 | "@repo/eslint-config": "workspace:*",
20 | "@repo/typescript-config": "workspace:*",
21 | "@tailwindcss/container-queries": "^0.1.1",
22 | "@tailwindcss/typography": "^0.5.10",
23 | "@types/eslint": "^8.56.1",
24 | "@types/node": "^20.10.6",
25 | "@types/react": "^18.2.46",
26 | "@types/react-dom": "^18.2.18",
27 | "autoprefixer": "^10.4.17",
28 | "eslint": "^8.56.0",
29 | "postcss": "^8.4.33",
30 | "tailwindcss": "^3.4.1",
31 | "typescript": "^5.3.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/public/circles.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/public/turborepo.svg:
--------------------------------------------------------------------------------
1 |
33 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./app/**/*.{js,ts,jsx,tsx,mdx}",
5 | "../../packages/ui/**/*.{js,ts,jsx,tsx,mdx}",
6 | ],
7 | theme: {
8 | extend: {
9 | backgroundImage: {
10 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
11 | "gradient-conic":
12 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
13 | },
14 | },
15 | },
16 | plugins: [require("@tailwindcss/typography")],
17 | };
18 |
--------------------------------------------------------------------------------
/app-search-turborepo/apps/app-search/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/nextjs.json",
3 | "compilerOptions": {
4 | "plugins": [
5 | {
6 | "name": "next"
7 | }
8 | ]
9 | },
10 | "include": [
11 | "next-env.d.ts",
12 | "next.config.js",
13 | "**/*.ts",
14 | "**/*.tsx",
15 | ".next/types/**/*.ts"
16 | ],
17 | "exclude": ["node_modules"]
18 | }
19 |
--------------------------------------------------------------------------------
/app-search-turborepo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-search-turborepo",
3 | "private": true,
4 | "scripts": {
5 | "build": "turbo build",
6 | "dev": "turbo dev",
7 | "lint": "turbo lint",
8 | "format": "prettier --write \"**/*.{ts,tsx,md}\""
9 | },
10 | "devDependencies": {
11 | "@repo/eslint-config": "workspace:*",
12 | "@repo/typescript-config": "workspace:*",
13 | "prettier": "^3.1.1",
14 | "turbo": "latest"
15 | },
16 | "packageManager": "pnpm@8.9.0",
17 | "engines": {
18 | "node": ">=18"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/eslint-config/README.md:
--------------------------------------------------------------------------------
1 | # `@turbo/eslint-config`
2 |
3 | Collection of internal eslint configurations.
4 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/eslint-config/library.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require("node:path");
2 |
3 | const project = resolve(process.cwd(), "tsconfig.json");
4 |
5 | /** @type {import("eslint").Linter.Config} */
6 | module.exports = {
7 | extends: ["eslint:recommended", "prettier", "eslint-config-turbo"],
8 | plugins: ["only-warn"],
9 | globals: {
10 | React: true,
11 | JSX: true,
12 | },
13 | env: {
14 | node: true,
15 | },
16 | settings: {
17 | "import/resolver": {
18 | typescript: {
19 | project,
20 | },
21 | },
22 | },
23 | ignorePatterns: [
24 | // Ignore dotfiles
25 | ".*.js",
26 | "node_modules/",
27 | "dist/",
28 | ],
29 | overrides: [
30 | {
31 | files: ["*.js?(x)", "*.ts?(x)"],
32 | },
33 | ],
34 | };
35 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/eslint-config/next.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require("node:path");
2 |
3 | const project = resolve(process.cwd(), "tsconfig.json");
4 |
5 | /** @type {import("eslint").Linter.Config} */
6 | module.exports = {
7 | extends: [
8 | "eslint:recommended",
9 | "prettier",
10 | require.resolve("@vercel/style-guide/eslint/next"),
11 | "eslint-config-turbo",
12 | ],
13 | globals: {
14 | React: true,
15 | JSX: true,
16 | },
17 | env: {
18 | node: true,
19 | browser: true,
20 | },
21 | plugins: ["only-warn"],
22 | settings: {
23 | "import/resolver": {
24 | typescript: {
25 | project,
26 | },
27 | },
28 | },
29 | ignorePatterns: [
30 | // Ignore dotfiles
31 | ".*.js",
32 | "node_modules/",
33 | ],
34 | overrides: [{ files: ["*.js?(x)", "*.ts?(x)"] }],
35 | };
36 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/eslint-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@repo/eslint-config",
3 | "version": "0.0.0",
4 | "private": true,
5 | "files": [
6 | "library.js",
7 | "next.js",
8 | "react-internal.js"
9 | ],
10 | "devDependencies": {
11 | "@vercel/style-guide": "^5.1.0",
12 | "eslint-config-turbo": "^1.11.3",
13 | "eslint-config-prettier": "^9.1.0",
14 | "eslint-plugin-only-warn": "^1.1.0",
15 | "@typescript-eslint/parser": "^6.17.0",
16 | "@typescript-eslint/eslint-plugin": "^6.17.0",
17 | "typescript": "^5.3.3"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/eslint-config/react-internal.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require("node:path");
2 |
3 | const project = resolve(process.cwd(), "tsconfig.json");
4 |
5 | /*
6 | * This is a custom ESLint configuration for use with
7 | * internal (bundled by their consumer) libraries
8 | * that utilize React.
9 | *
10 | * This config extends the Vercel Engineering Style Guide.
11 | * For more information, see https://github.com/vercel/style-guide
12 | *
13 | */
14 |
15 | /** @type {import("eslint").Linter.Config} */
16 | module.exports = {
17 | extends: ["eslint:recommended", "prettier", "eslint-config-turbo"],
18 | plugins: ["only-warn"],
19 | globals: {
20 | React: true,
21 | JSX: true,
22 | },
23 | env: {
24 | browser: true,
25 | },
26 | settings: {
27 | "import/resolver": {
28 | typescript: {
29 | project,
30 | },
31 | },
32 | },
33 | ignorePatterns: [
34 | // Ignore dotfiles
35 | ".*.js",
36 | "node_modules/",
37 | "dist/",
38 | ],
39 | overrides: [
40 | // Force ESLint to detect .tsx files
41 | { files: ["*.js?(x)", "*.ts?(x)"] },
42 | ],
43 | };
44 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/typescript-config/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Default",
4 | "compilerOptions": {
5 | "declaration": true,
6 | "declarationMap": true,
7 | "esModuleInterop": true,
8 | "incremental": false,
9 | "isolatedModules": true,
10 | "lib": ["es2022", "DOM", "DOM.Iterable"],
11 | "module": "NodeNext",
12 | "moduleDetection": "force",
13 | "moduleResolution": "NodeNext",
14 | "noUncheckedIndexedAccess": true,
15 | "resolveJsonModule": true,
16 | "skipLibCheck": true,
17 | "strict": true,
18 | "target": "ES2022"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/typescript-config/nextjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Next.js",
4 | "extends": "./base.json",
5 | "compilerOptions": {
6 | "plugins": [{ "name": "next" }],
7 | "module": "ESNext",
8 | "moduleResolution": "Bundler",
9 | "allowJs": true,
10 | "jsx": "preserve",
11 | "noEmit": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/typescript-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@repo/typescript-config",
3 | "version": "0.0.0",
4 | "private": true,
5 | "license": "MIT",
6 | "publishConfig": {
7 | "access": "public"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/typescript-config/react-library.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "React Library",
4 | "extends": "./base.json",
5 | "compilerOptions": {
6 | "jsx": "react-jsx",
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /** @type {import("eslint").Linter.Config} */
2 | module.exports = {
3 | root: true,
4 | extends: ["@repo/eslint-config/react-internal.js"],
5 | parser: "@typescript-eslint/parser",
6 | parserOptions: {
7 | project: "./tsconfig.lint.json",
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@repo/ui",
3 | "version": "0.0.0",
4 | "private": true,
5 | "exports": {
6 | "./Comments": "./src/Comments.tsx",
7 | "./Users": "./src/Users.tsx"
8 | },
9 | "scripts": {
10 | "lint": "eslint . --max-warnings 0",
11 | "generate:component": "turbo gen react-component"
12 | },
13 | "devDependencies": {
14 | "@repo/eslint-config": "workspace:*",
15 | "@repo/typescript-config": "workspace:*",
16 | "@turbo/gen": "^1.11.3",
17 | "@types/node": "^20.10.6",
18 | "@types/eslint": "^8.56.1",
19 | "@types/react": "^18.2.46",
20 | "@types/react-dom": "^18.2.18",
21 | "eslint": "^8.56.0",
22 | "react": "^18.2.0",
23 | "typescript": "^5.3.3"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/src/Comments.tsx:
--------------------------------------------------------------------------------
1 | import SearchableComments from "./SearchableComments";
2 | import { Comment } from "./types";
3 |
4 | const getComments = async () =>
5 | (
6 | await fetch("https://jsonplaceholder.typicode.com/comments")
7 | ).json() as Promise;
8 |
9 | export default async function Comments() {
10 | const comments = await getComments();
11 |
12 | const search = async (search: string) => {
13 | "use server";
14 | const comments = await getComments();
15 | return comments
16 | .filter(
17 | (comment) =>
18 | comment.name.toLowerCase().includes(search) ||
19 | comment.body.toLowerCase().includes(search)
20 | )
21 | .slice(0, 20);
22 | };
23 |
24 | return (
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/src/SearchableComments.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { useState } from "react";
3 | import { Comment } from "./types";
4 |
5 | export default function SearchableComments({
6 | comments,
7 | search,
8 | }: {
9 | comments: Comment[];
10 | search: (search: string) => Promise;
11 | }) {
12 | const [searchTerm, setSearchTerm] = useState("");
13 | const [searchResults, setSearchResults] = useState(comments);
14 |
15 | const handleChange = async (e: React.ChangeEvent) => {
16 | setSearchTerm(e.target.value);
17 | setSearchResults(await search(e.target.value));
18 | };
19 |
20 | return (
21 |
22 |
23 |
29 |
32 |
33 |
Comments
34 |
35 | {searchResults.map((comment) => (
36 |
37 |
38 |
{comment.name}
39 |
{comment.body}
40 |
41 |
42 | ))}
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/src/Users.tsx:
--------------------------------------------------------------------------------
1 | import { User } from "./types";
2 |
3 | export default async function Users() {
4 | const res = await fetch("https://jsonplaceholder.typicode.com/users");
5 | const users = (await res.json()) as User[];
6 |
7 | return (
8 |
9 |
Users
10 |
11 | {users.slice(0, 20).map((user) => (
12 |
13 |
14 |
{user.name}
15 |
{user.phone}
16 |
17 |
18 | ))}
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Comment {
2 | id: number;
3 | name: string;
4 | body: string;
5 | }
6 |
7 | export interface User {
8 | id: string;
9 | email: string;
10 | name: string;
11 | phone: string;
12 | }
13 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/react-library.json",
3 | "compilerOptions": {
4 | "outDir": "dist"
5 | },
6 | "include": ["src"],
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/tsconfig.lint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/react-library.json",
3 | "compilerOptions": {
4 | "outDir": "dist"
5 | },
6 | "include": ["src", "turbo"],
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/turbo/generators/config.ts:
--------------------------------------------------------------------------------
1 | import type { PlopTypes } from "@turbo/gen";
2 |
3 | // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation
4 |
5 | export default function generator(plop: PlopTypes.NodePlopAPI): void {
6 | // A simple generator to add a new React component to the internal UI library
7 | plop.setGenerator("react-component", {
8 | description: "Adds a new react component",
9 | prompts: [
10 | {
11 | type: "input",
12 | name: "name",
13 | message: "What is the name of the component?",
14 | },
15 | ],
16 | actions: [
17 | {
18 | type: "add",
19 | path: "src/{{kebabCase name}}.tsx",
20 | templateFile: "templates/component.hbs",
21 | },
22 | {
23 | type: "append",
24 | path: "index.tsx",
25 | pattern: /"exports": {(?)/g,
26 | template: '"./{{kebabCase name}}": "./src/{{kebabCase name}}.tsx",',
27 | },
28 | ],
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/app-search-turborepo/packages/ui/turbo/generators/templates/component.hbs:
--------------------------------------------------------------------------------
1 | export const {{ pascalCase name }} = ({ children }: { children: React.ReactNode }) => {
2 | return (
3 |
4 |
{{ pascalCase name }} Component
5 | {children}
6 |
7 | );
8 | };
9 |
--------------------------------------------------------------------------------
/app-search-turborepo/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "apps/*"
3 | - "packages/*"
4 |
--------------------------------------------------------------------------------
/app-search-turborepo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/base.json"
3 | }
4 |
--------------------------------------------------------------------------------
/app-search-turborepo/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "globalDependencies": ["**/.env.*local"],
4 | "pipeline": {
5 | "build": {
6 | "dependsOn": ["^build"],
7 | "outputs": [".next/**", "!.next/cache/**"]
8 | },
9 | "lint": {
10 | "dependsOn": ["^lint"]
11 | },
12 | "dev": {
13 | "cache": false,
14 | "persistent": true
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app-search/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/app-search/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/app-search/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/app-search/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/app-search/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-comments",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "14.1.0",
13 | "react": "^18",
14 | "react-dom": "^18"
15 | },
16 | "devDependencies": {
17 | "@tailwindcss/container-queries": "^0.1.1",
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.1.0",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app-search/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/app-search/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-search/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-search/src/app/components/Comments.tsx:
--------------------------------------------------------------------------------
1 | import SearchableComments from "./SearchableComments";
2 | import { Comment } from "@/types";
3 |
4 | const getComments = async () =>
5 | (
6 | await fetch("https://jsonplaceholder.typicode.com/comments", {
7 | cache: "no-cache",
8 | })
9 | ).json() as Promise;
10 |
11 | export default async function Comments() {
12 | const comments = await getComments();
13 |
14 | const search = async (search: string) => {
15 | "use server";
16 | const comments = await getComments();
17 | return comments
18 | .filter(
19 | (comment) =>
20 | comment.name.toLowerCase().includes(search) ||
21 | comment.body.toLowerCase().includes(search)
22 | )
23 | .slice(0, 20);
24 | };
25 |
26 | return (
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/app-search/src/app/components/SearchableComments.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { useState } from "react";
3 | import { Comment } from "@/types";
4 |
5 | export default function SearchableComments({
6 | comments,
7 | search,
8 | }: {
9 | comments: Comment[];
10 | search: (search: string) => Promise;
11 | }) {
12 | const [searchTerm, setSearchTerm] = useState("");
13 | const [searchResults, setSearchResults] = useState(comments);
14 |
15 | const handleChange = async (e: React.ChangeEvent) => {
16 | setSearchTerm(e.target.value);
17 | setSearchResults(await search(e.target.value));
18 | };
19 |
20 | return (
21 |
22 |
23 |
29 |
32 |
33 |
Comments
34 |
35 | {searchResults.map((comment) => (
36 |
37 |
38 |
{comment.name}
39 |
{comment.body}
40 |
41 |
42 | ))}
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/app-search/src/app/components/Users.tsx:
--------------------------------------------------------------------------------
1 | import { User } from "@/types";
2 |
3 | export default async function Users() {
4 | const res = await fetch("https://jsonplaceholder.typicode.com/users", {
5 | cache: "no-cache",
6 | });
7 | const users = (await res.json()) as User[];
8 |
9 | return (
10 |
11 |
Users
12 |
13 | {users.slice(0, 20).map((user) => (
14 |
15 |
16 |
{user.name}
17 |
{user.phone}
18 |
19 |
20 | ))}
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/app-search/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/app-search/src/app/favicon.ico
--------------------------------------------------------------------------------
/app-search/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app-search/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { Inter } from "next/font/google";
3 | import "./globals.css";
4 |
5 | const inter = Inter({ subsets: ["latin"] });
6 |
7 | export const metadata: Metadata = {
8 | title: "Create Next App",
9 | description: "Generated by create next app",
10 | };
11 |
12 | export default function RootLayout({
13 | children,
14 | }: Readonly<{
15 | children: React.ReactNode;
16 | }>) {
17 | return (
18 |
19 |
20 | {children}
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/app-search/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "./components/Comments";
2 |
3 | export default function Home() {
4 | return (
5 |
6 |
Home Page
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app-search/src/app/users/page.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "../components/Comments";
2 | import Users from "../components/Users";
3 |
4 | export default function Home() {
5 | return (
6 |
7 |
Users Page
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/app-search/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Comment {
2 | id: number;
3 | name: string;
4 | body: string;
5 | }
6 |
7 | export interface User {
8 | id: string;
9 | email: string;
10 | name: string;
11 | phone: string;
12 | }
13 |
--------------------------------------------------------------------------------
/app-search/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | },
17 | },
18 | plugins: [require("@tailwindcss/container-queries")],
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/app-search/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./src/*"]
22 | }
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/app-simple/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/app-simple/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/app-simple/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/app-simple/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/app-simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-comments",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "14.1.0",
13 | "react": "^18",
14 | "react-dom": "^18"
15 | },
16 | "devDependencies": {
17 | "@tailwindcss/container-queries": "^0.1.1",
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.1.0",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app-simple/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/app-simple/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-simple/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-simple/src/app/components/Comments.tsx:
--------------------------------------------------------------------------------
1 | import { Comment } from "@/types";
2 |
3 | export default async function Comments() {
4 | const res = await fetch("https://jsonplaceholder.typicode.com/comments");
5 | const comments = (await res.json()) as Comment[];
6 |
7 | return (
8 |
9 |
Comments
10 |
11 | {comments.slice(0, 20).map((comment) => (
12 |
13 |
14 |
{comment.name}
15 |
{comment.body}
16 |
17 |
18 | ))}
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app-simple/src/app/components/Users.tsx:
--------------------------------------------------------------------------------
1 | import { User } from "@/types";
2 |
3 | export default async function Users() {
4 | const res = await fetch("https://jsonplaceholder.typicode.com/users");
5 | const users = (await res.json()) as User[];
6 |
7 | return (
8 |
9 |
Users
10 |
11 | {users.slice(0, 20).map((user) => (
12 |
13 |
14 |
{user.name}
15 |
{user.phone}
16 |
17 |
18 | ))}
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app-simple/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/app-simple/src/app/favicon.ico
--------------------------------------------------------------------------------
/app-simple/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app-simple/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { Inter } from "next/font/google";
3 | import "./globals.css";
4 |
5 | const inter = Inter({ subsets: ["latin"] });
6 |
7 | export const metadata: Metadata = {
8 | title: "Create Next App",
9 | description: "Generated by create next app",
10 | };
11 |
12 | export default function RootLayout({
13 | children,
14 | }: Readonly<{
15 | children: React.ReactNode;
16 | }>) {
17 | return (
18 |
19 |
20 | {children}
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/app-simple/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "./components/Comments";
2 |
3 | export default function Home() {
4 | return (
5 |
6 |
Home Page
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/app-simple/src/app/users/page.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "../components/Comments";
2 | import Users from "../components/Users";
3 |
4 | export default function Home() {
5 | return (
6 |
7 |
Users Page
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/app-simple/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Comment {
2 | id: number;
3 | name: string;
4 | body: string;
5 | }
6 |
7 | export interface User {
8 | id: string;
9 | email: string;
10 | name: string;
11 | phone: string;
12 | }
13 |
--------------------------------------------------------------------------------
/app-simple/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | },
17 | },
18 | plugins: [require("@tailwindcss/container-queries")],
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/app-simple/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./src/*"]
22 | }
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/app-suspense/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/app-suspense/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/app-suspense/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/app-suspense/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/app-suspense/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-comments",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "14.1.0",
13 | "react": "^18",
14 | "react-dom": "^18"
15 | },
16 | "devDependencies": {
17 | "@tailwindcss/container-queries": "^0.1.1",
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.1.0",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app-suspense/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/app-suspense/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-suspense/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app-suspense/src/app/components/Comments.tsx:
--------------------------------------------------------------------------------
1 | import { COMMENTS_DELAY } from "@/constants";
2 |
3 | export default async function Comments() {
4 | await new Promise((resolve) => setTimeout(resolve, COMMENTS_DELAY));
5 | const res = await fetch("https://jsonplaceholder.typicode.com/comments", {
6 | cache: "no-cache",
7 | });
8 | const comments = (await res.json()) as {
9 | id: number;
10 | name: string;
11 | body: string;
12 | }[];
13 |
14 | return (
15 |
16 |
Comments
17 |
18 | {comments.slice(0, 20).map((comment) => (
19 |
20 |
21 |
{comment.name}
22 |
{comment.body}
23 |
24 |
25 | ))}
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/app-suspense/src/app/components/Users.tsx:
--------------------------------------------------------------------------------
1 | import { USERS_DELAY } from "@/constants";
2 |
3 | export default async function Users() {
4 | await new Promise((resolve) => setTimeout(resolve, USERS_DELAY));
5 | const res = await fetch("https://jsonplaceholder.typicode.com/users", {
6 | cache: "no-cache",
7 | });
8 | const users = (await res.json()) as {
9 | id: string;
10 | email: string;
11 | name: string;
12 | phone: string;
13 | }[];
14 |
15 | return (
16 |
17 |
Users
18 |
19 | {users.slice(0, 20).map((user) => (
20 |
21 |
22 |
{user.name}
23 |
{user.phone}
24 |
25 |
26 | ))}
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/app-suspense/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/app-suspense/src/app/favicon.ico
--------------------------------------------------------------------------------
/app-suspense/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app-suspense/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { Inter } from "next/font/google";
3 | import "./globals.css";
4 |
5 | const inter = Inter({ subsets: ["latin"] });
6 |
7 | export const metadata: Metadata = {
8 | title: "Create Next App",
9 | description: "Generated by create next app",
10 | };
11 |
12 | export default function RootLayout({
13 | children,
14 | }: Readonly<{
15 | children: React.ReactNode;
16 | }>) {
17 | return (
18 |
19 |
20 | {children}
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/app-suspense/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | import { Suspense } from "react";
2 | import Comments from "./components/Comments";
3 |
4 | export default function Home() {
5 | return (
6 |
7 |
Home Page
8 | Loading...}>
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/app-suspense/src/app/users/page.tsx:
--------------------------------------------------------------------------------
1 | import { Suspense } from "react";
2 | import Comments from "../components/Comments";
3 | import Users from "../components/Users";
4 |
5 | export default function Home() {
6 | return (
7 |
8 |
Users Page
9 |
10 |
11 | Loading users...
}>
12 |
13 |
14 |
15 |
16 | Loading comments...
}>
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/app-suspense/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const USERS_DELAY = 3000;
2 | export const COMMENTS_DELAY = 3000;
3 |
--------------------------------------------------------------------------------
/app-suspense/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | },
17 | },
18 | plugins: [require("@tailwindcss/container-queries")],
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/app-suspense/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./src/*"]
22 | }
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/pages-search/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/pages-search/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/pages-search/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
20 |
21 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
22 |
23 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
24 |
25 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
26 |
27 | ## Learn More
28 |
29 | To learn more about Next.js, take a look at the following resources:
30 |
31 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
32 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
33 |
34 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
35 |
36 | ## Deploy on Vercel
37 |
38 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
39 |
40 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
41 |
--------------------------------------------------------------------------------
/pages-search/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | };
5 |
6 | export default nextConfig;
7 |
--------------------------------------------------------------------------------
/pages-search/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pages-simple",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "14.1.0",
13 | "react": "^18",
14 | "react-dom": "^18"
15 | },
16 | "devDependencies": {
17 | "@tailwindcss/container-queries": "^0.1.1",
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.1.0",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/pages-search/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/pages-search/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/pages-search/public/favicon.ico
--------------------------------------------------------------------------------
/pages-search/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages-search/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages-search/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "@/styles/globals.css";
2 | import type { AppProps } from "next/app";
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/pages-search/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/pages-search/src/pages/api/comment-search.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from "next";
3 | import { Comment } from "@/types";
4 |
5 | export default async function handler(
6 | req: NextApiRequest,
7 | res: NextApiResponse
8 | ) {
9 | let search = "";
10 | if (typeof req.query.q === "string") {
11 | search = req.query.q;
12 | }
13 |
14 | const cres = await fetch("https://jsonplaceholder.typicode.com/comments");
15 | const comments = (await cres.json()) as Comment[];
16 |
17 | res
18 | .status(200)
19 | .json(
20 | comments
21 | .filter(
22 | (comment) =>
23 | comment.name.toLowerCase().includes(search) ||
24 | comment.body.toLowerCase().includes(search)
25 | )
26 | .slice(0, 20)
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/pages-search/src/pages/components/Comments.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useState } from "react";
3 |
4 | export default function Comments({
5 | comments,
6 | }: {
7 | comments: {
8 | id: number;
9 | name: string;
10 | body: string;
11 | }[];
12 | }) {
13 | const [searchTerm, setSearchTerm] = useState("");
14 | const [searchResults, setSearchResults] = useState(comments);
15 |
16 | const handleChange = async (e: React.ChangeEvent) => {
17 | setSearchTerm(e.target.value);
18 | fetch(`/api/comment-search?q=${encodeURIComponent(e.target.value)}`, {
19 | method: "GET",
20 | headers: {
21 | "Content-Type": "application/json",
22 | },
23 | })
24 | .then((res) => res.json())
25 | .then((data) => {
26 | setSearchResults(data);
27 | });
28 | };
29 |
30 | return (
31 |
32 |
33 |
39 |
42 |
43 |
Comments
44 |
45 | {searchResults.map((comment) => (
46 |
47 |
48 |
{comment.name}
49 |
{comment.body}
50 |
51 |
52 | ))}
53 |
54 |
55 | );
56 | }
57 |
--------------------------------------------------------------------------------
/pages-search/src/pages/components/Users.tsx:
--------------------------------------------------------------------------------
1 | export default function Users({
2 | users,
3 | }: {
4 | users: {
5 | id: number;
6 | name: string;
7 | phone: string;
8 | }[];
9 | }) {
10 | return (
11 |
12 |
Users
13 |
14 | {users.map((user) => (
15 |
16 |
17 |
{user.name}
18 |
{user.phone}
19 |
20 |
21 | ))}
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/pages-search/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "./components/Comments";
2 | import { Comment } from "@/types";
3 |
4 | export async function getServerSideProps() {
5 | const res = await fetch("https://jsonplaceholder.typicode.com/comments");
6 | const comments = (await res.json()) as Comment[];
7 |
8 | return {
9 | props: {
10 | comments: comments.slice(0, 20),
11 | },
12 | };
13 | }
14 |
15 | export default function Home({ comments }: { comments: Comment[] }) {
16 | return (
17 |
18 |
Home Page
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/pages-search/src/pages/users.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "./components/Comments";
2 | import Users from "./components/Users";
3 | import { Comment, User } from "@/types";
4 |
5 | export async function getServerSideProps() {
6 | const cres = await fetch("https://jsonplaceholder.typicode.com/comments");
7 | const comments = (await cres.json()) as Comment[];
8 |
9 | const ures = await fetch("https://jsonplaceholder.typicode.com/users");
10 | const users = (await ures.json()) as Comment[];
11 |
12 | return {
13 | props: {
14 | users: users.slice(0, 20),
15 | comments: comments.slice(0, 20),
16 | },
17 | };
18 | }
19 |
20 | export default function Home({
21 | users,
22 | comments,
23 | }: {
24 | comments: Comment[];
25 | users: User[];
26 | }) {
27 | return (
28 |
29 |
Users Page
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/pages-search/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/pages-search/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Comment {
2 | id: number;
3 | name: string;
4 | body: string;
5 | }
6 |
7 | export interface User {
8 | id: number;
9 | name: string;
10 | phone: string;
11 | }
12 |
--------------------------------------------------------------------------------
/pages-search/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | },
17 | },
18 | plugins: [require("@tailwindcss/container-queries")],
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/pages-search/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "paths": {
16 | "@/*": ["./src/*"]
17 | }
18 | },
19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------
/pages-simple/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/pages-simple/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/pages-simple/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
20 |
21 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
22 |
23 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
24 |
25 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
26 |
27 | ## Learn More
28 |
29 | To learn more about Next.js, take a look at the following resources:
30 |
31 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
32 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
33 |
34 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
35 |
36 | ## Deploy on Vercel
37 |
38 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
39 |
40 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
41 |
--------------------------------------------------------------------------------
/pages-simple/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | };
5 |
6 | export default nextConfig;
7 |
--------------------------------------------------------------------------------
/pages-simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pages-simple",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "14.1.0",
13 | "react": "^18",
14 | "react-dom": "^18"
15 | },
16 | "devDependencies": {
17 | "@tailwindcss/container-queries": "^0.1.1",
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.1.0",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/pages-simple/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/pages-simple/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/pages-simple/public/favicon.ico
--------------------------------------------------------------------------------
/pages-simple/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages-simple/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "@/styles/globals.css";
2 | import type { AppProps } from "next/app";
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from "next";
3 |
4 | type Data = {
5 | name: string;
6 | };
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse,
11 | ) {
12 | res.status(200).json({ name: "John Doe" });
13 | }
14 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/components/Comments.tsx:
--------------------------------------------------------------------------------
1 | import { Comment } from "@/types";
2 |
3 | export default function Comments({ comments }: { comments: Comment[] }) {
4 | return (
5 |
6 |
Comments
7 |
8 | {comments.map((comment) => (
9 |
10 |
11 |
{comment.name}
12 |
{comment.body}
13 |
14 |
15 | ))}
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/components/Users.tsx:
--------------------------------------------------------------------------------
1 | import { User } from "@/types";
2 |
3 | export default function Users({ users }: { users: User[] }) {
4 | return (
5 |
6 |
Users
7 |
8 | {users.map((user) => (
9 |
10 |
11 |
{user.name}
12 |
{user.phone}
13 |
14 |
15 | ))}
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "./components/Comments";
2 | import { Comment } from "@/types";
3 |
4 | export async function getServerSideProps() {
5 | const res = await fetch("https://jsonplaceholder.typicode.com/comments");
6 | const comments = (await res.json()) as Comment[];
7 |
8 | return {
9 | props: {
10 | comments: comments.slice(0, 20),
11 | },
12 | };
13 | }
14 |
15 | export default function Home({ comments }: { comments: Comment[] }) {
16 | return (
17 |
18 |
Home Page
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/pages-simple/src/pages/users.tsx:
--------------------------------------------------------------------------------
1 | import Comments from "./components/Comments";
2 | import Users from "./components/Users";
3 | import { Comment, User } from "@/types";
4 |
5 | export async function getServerSideProps() {
6 | const cres = await fetch("https://jsonplaceholder.typicode.com/comments");
7 | const comments = (await cres.json()) as Comment[];
8 |
9 | const ures = await fetch("https://jsonplaceholder.typicode.com/users");
10 | const users = (await ures.json()) as Comment[];
11 |
12 | return {
13 | props: {
14 | users: users.slice(0, 20),
15 | comments: comments.slice(0, 20),
16 | },
17 | };
18 | }
19 |
20 | export default function Home({
21 | users,
22 | comments,
23 | }: {
24 | comments: Comment[];
25 | users: User[];
26 | }) {
27 | return (
28 |
29 |
Users Page
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/pages-simple/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/pages-simple/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Comment {
2 | id: number;
3 | name: string;
4 | body: string;
5 | }
6 |
7 | export interface User {
8 | id: number;
9 | name: string;
10 | phone: string;
11 | }
12 |
--------------------------------------------------------------------------------
/pages-simple/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | },
17 | },
18 | plugins: [require("@tailwindcss/container-queries")],
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/pages-simple/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "paths": {
16 | "@/*": ["./src/*"]
17 | }
18 | },
19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------
/pages-suspense/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/pages-suspense/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/pages-suspense/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
20 |
21 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
22 |
23 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
24 |
25 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
26 |
27 | ## Learn More
28 |
29 | To learn more about Next.js, take a look at the following resources:
30 |
31 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
32 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
33 |
34 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
35 |
36 | ## Deploy on Vercel
37 |
38 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
39 |
40 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
41 |
--------------------------------------------------------------------------------
/pages-suspense/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | };
5 |
6 | export default nextConfig;
7 |
--------------------------------------------------------------------------------
/pages-suspense/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pages-simple",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "14.1.0",
13 | "react": "^18",
14 | "react-dom": "^18"
15 | },
16 | "devDependencies": {
17 | "@tailwindcss/container-queries": "^0.1.1",
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.1.0",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/pages-suspense/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/pages-suspense/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jherr/nextjs-killed-react/553f306153084c97f4dbb820c3f569e562be9eea/pages-suspense/public/favicon.ico
--------------------------------------------------------------------------------
/pages-suspense/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages-suspense/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pages-suspense/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const USERS_DELAY = 3000;
2 | export const COMMENTS_DELAY = 20;
3 | export const SSR_THRESHOLD = 200;
4 |
--------------------------------------------------------------------------------
/pages-suspense/src/getCommentsServer.ts:
--------------------------------------------------------------------------------
1 | import { Comment } from "./types";
2 |
3 | import { COMMENTS_DELAY, SSR_THRESHOLD } from "./constants";
4 |
5 | export async function getCommentsServer() {
6 | return new Promise((resolve) => {
7 | let comments: Comment[] | null = null;
8 |
9 | try {
10 | let timedOut = false;
11 |
12 | setTimeout(() => {
13 | if (!comments) {
14 | timedOut = true;
15 | resolve(null);
16 | }
17 | }, SSR_THRESHOLD);
18 |
19 | new Promise((resolve) => {
20 | setTimeout(() => {
21 | resolve(null);
22 | }, COMMENTS_DELAY);
23 | })
24 | .then(() => fetch("https://jsonplaceholder.typicode.com/comments"))
25 | .then((res) => res.json())
26 | .then((c) => {
27 | if (!timedOut) {
28 | comments = c;
29 | resolve(c.slice(0, 20));
30 | }
31 | })
32 | .catch((e) => {
33 | console.error(e);
34 | });
35 | } catch (e) {}
36 | });
37 | }
38 |
--------------------------------------------------------------------------------
/pages-suspense/src/getUsersServer.ts:
--------------------------------------------------------------------------------
1 | import { User } from "./types";
2 |
3 | import { USERS_DELAY, SSR_THRESHOLD } from "./constants";
4 |
5 | export async function getUsersServer() {
6 | return new Promise((resolve) => {
7 | try {
8 | let users: User[] | null = null;
9 | let timedOut = false;
10 |
11 | setTimeout(() => {
12 | if (!users) {
13 | timedOut = true;
14 | resolve(null);
15 | }
16 | }, SSR_THRESHOLD);
17 |
18 | new Promise((resolve) => {
19 | setTimeout(() => {
20 | resolve(null);
21 | }, USERS_DELAY);
22 | })
23 | .then(() => fetch("https://jsonplaceholder.typicode.com/users"))
24 | .then((res) => res.json())
25 | .then((c) => {
26 | if (!timedOut) {
27 | users = c;
28 | resolve(c.slice(0, 20));
29 | }
30 | })
31 | .catch((e) => {
32 | console.error(e);
33 | });
34 | } catch (e) {}
35 | });
36 | }
37 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "@/styles/globals.css";
2 | import type { AppProps } from "next/app";
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/api/comments.ts:
--------------------------------------------------------------------------------
1 | import type { NextApiRequest, NextApiResponse } from "next";
2 |
3 | import { Comment } from "@/types";
4 | import { COMMENTS_DELAY } from "@/constants";
5 |
6 | export default async function handler(
7 | req: NextApiRequest,
8 | res: NextApiResponse
9 | ) {
10 | await new Promise((resolve) => setTimeout(resolve, COMMENTS_DELAY));
11 | const creq = await fetch("https://jsonplaceholder.typicode.com/comments");
12 | const comments = (await creq.json()) as Comment[];
13 |
14 | res.status(200).json(comments.slice(0, 20));
15 | }
16 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/api/users.ts:
--------------------------------------------------------------------------------
1 | import type { NextApiRequest, NextApiResponse } from "next";
2 |
3 | import { User } from "@/types";
4 | import { USERS_DELAY } from "@/constants";
5 |
6 | export default async function handler(
7 | req: NextApiRequest,
8 | res: NextApiResponse
9 | ) {
10 | await new Promise((resolve) => setTimeout(resolve, USERS_DELAY));
11 | const ures = await fetch("https://jsonplaceholder.typicode.com/users");
12 | const users = (await ures.json()) as User[];
13 |
14 | res.status(200).json(users.slice(0, 20));
15 | }
16 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/components/Comments.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import { Comment } from "@/types";
3 |
4 | export default function Comments({
5 | comments: initialComments,
6 | }: {
7 | comments: Comment[] | null;
8 | }) {
9 | const [comments, setComments] = useState(initialComments);
10 |
11 | useEffect(() => {
12 | async function fetchComments() {
13 | const res = await fetch("/api/comments");
14 | const comments = (await res.json()) as Comment[];
15 | setComments(comments);
16 | }
17 | if (!initialComments) {
18 | fetchComments();
19 | }
20 | }, [initialComments]);
21 |
22 | if (!comments) return Loading comments from client...
;
23 |
24 | return (
25 |
26 |
Comments
27 |
28 | {(comments ?? []).map((comment) => (
29 |
30 |
31 |
{comment.name}
32 |
{comment.body}
33 |
34 |
35 | ))}
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/components/Users.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | import { User } from "@/types";
4 |
5 | export default function Users({
6 | users: initialUsers,
7 | }: {
8 | users: User[] | null;
9 | }) {
10 | const [users, setUsers] = useState(initialUsers);
11 |
12 | useEffect(() => {
13 | async function fetchUsers() {
14 | const res = await fetch("/api/users");
15 | const users = (await res.json()) as User[];
16 | setUsers(users);
17 | }
18 | if (!initialUsers) {
19 | fetchUsers();
20 | }
21 | }, [initialUsers]);
22 |
23 | if (!users) return Loading users from client...
;
24 |
25 | return (
26 |
27 |
Users
28 |
29 | {(users ?? []).map((user) => (
30 |
31 |
32 |
{user.name}
33 |
{user.phone}
34 |
35 |
36 | ))}
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Comment } from "@/types";
2 | import { getCommentsServer } from "@/getCommentsServer";
3 |
4 | import Comments from "./components/Comments";
5 |
6 | export async function getServerSideProps() {
7 | const comments = await getCommentsServer();
8 |
9 | return {
10 | props: {
11 | comments,
12 | },
13 | };
14 | }
15 |
16 | export default function Home({ comments }: { comments: Comment[] | null }) {
17 | return (
18 |
19 |
Home Page
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/pages-suspense/src/pages/users.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | import { getCommentsServer } from "@/getCommentsServer";
4 | import { getUsersServer } from "@/getUsersServer";
5 |
6 | import { Comment, User } from "@/types";
7 | import { USERS_DELAY } from "@/constants";
8 |
9 | import Comments from "./components/Comments";
10 | import Users from "./components/Users";
11 |
12 | export async function getServerSideProps() {
13 | const comments = await getCommentsServer();
14 | const users = await getUsersServer();
15 |
16 | return {
17 | props: {
18 | users,
19 | comments,
20 | },
21 | };
22 | }
23 |
24 | export default function Home({
25 | users,
26 | comments,
27 | }: {
28 | comments: Comment[] | null;
29 | users: User[] | null;
30 | }) {
31 | return (
32 |
33 |
Users Page
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/pages-suspense/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
29 | @layer utilities {
30 | .text-balance {
31 | text-wrap: balance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/pages-suspense/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Comment {
2 | id: number;
3 | name: string;
4 | body: string;
5 | }
6 |
7 | export interface User {
8 | id: number;
9 | name: string;
10 | phone: string;
11 | }
12 |
--------------------------------------------------------------------------------
/pages-suspense/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | const config: Config = {
4 | content: [
5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | },
17 | },
18 | plugins: [require("@tailwindcss/container-queries")],
19 | };
20 | export default config;
21 |
--------------------------------------------------------------------------------
/pages-suspense/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "paths": {
16 | "@/*": ["./src/*"]
17 | }
18 | },
19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------