create-lumen 2.0.0-alpha.2 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -6
- package/bin/cli.js +2 -1
- package/package.json +2 -2
- package/schema/lumen.config.v2.json +29 -0
- package/src/agent-context.js +71 -47
- package/src/cleanup.js +19 -1
- package/src/cli-args.js +131 -5
- package/src/configure.js +8 -4
- package/src/dependencies.js +46 -13
- package/src/engine/capabilities.js +71 -1
- package/src/engine/composition.js +334 -17
- package/src/engine/providers/base-provider.js +4 -4
- package/src/env.js +24 -6
- package/src/main.js +38 -15
- package/src/manifest/emit.js +14 -1
- package/src/manifest/schema.js +30 -0
- package/src/prompts.js +227 -23
- package/templates/bases/next/app-router/js/.provenance.json +19 -0
- package/templates/bases/next/app-router/js/README.md +36 -0
- package/templates/bases/next/app-router/js/jsconfig.json +7 -0
- package/templates/bases/next/app-router/js/next.config.mjs +6 -0
- package/templates/bases/next/app-router/js/package.json +15 -0
- package/templates/bases/next/app-router/js/public/file.svg +1 -0
- package/templates/bases/next/app-router/js/public/globe.svg +1 -0
- package/templates/bases/next/app-router/js/public/next.svg +1 -0
- package/templates/bases/next/app-router/js/public/vercel.svg +1 -0
- package/templates/bases/next/app-router/js/public/window.svg +1 -0
- package/templates/bases/next/app-router/js/src/app/api/hello/route.js +5 -0
- package/templates/bases/next/app-router/js/src/app/blog/[slug]/page.js +33 -0
- package/templates/bases/next/app-router/js/src/app/favicon.ico +0 -0
- package/templates/bases/next/app-router/js/src/app/globals.css +49 -0
- package/templates/bases/next/app-router/js/src/app/layout.js +25 -0
- package/templates/bases/next/app-router/js/src/app/loading.js +15 -0
- package/templates/bases/next/app-router/js/src/app/not-found.js +29 -0
- package/templates/bases/next/app-router/js/src/app/page.js +69 -0
- package/templates/bases/next/app-router/js/src/app/page.module.css +150 -0
- package/templates/bases/next/app-router/ts/.provenance.json +19 -0
- package/templates/bases/next/app-router/ts/README.md +36 -0
- package/templates/bases/next/app-router/ts/next.config.ts +7 -0
- package/templates/bases/next/app-router/ts/package.json +21 -0
- package/templates/bases/next/app-router/ts/public/file.svg +1 -0
- package/templates/bases/next/app-router/ts/public/globe.svg +1 -0
- package/templates/bases/next/app-router/ts/public/next.svg +1 -0
- package/templates/bases/next/app-router/ts/public/vercel.svg +1 -0
- package/templates/bases/next/app-router/ts/public/window.svg +1 -0
- package/templates/bases/next/app-router/ts/src/app/api/hello/route.ts +5 -0
- package/templates/bases/next/app-router/ts/src/app/blog/[slug]/page.tsx +38 -0
- package/templates/bases/next/app-router/ts/src/app/favicon.ico +0 -0
- package/templates/bases/next/app-router/ts/src/app/globals.css +49 -0
- package/templates/bases/next/app-router/ts/src/app/layout.tsx +30 -0
- package/templates/bases/next/app-router/ts/src/app/loading.tsx +15 -0
- package/templates/bases/next/app-router/ts/src/app/not-found.tsx +29 -0
- package/templates/bases/next/app-router/ts/src/app/page.module.css +150 -0
- package/templates/bases/next/app-router/ts/src/app/page.tsx +69 -0
- package/templates/bases/next/app-router/ts/tsconfig.json +34 -0
- package/templates/bases/next/pages-router/js/.provenance.json +19 -0
- package/templates/bases/next/pages-router/js/README.md +40 -0
- package/templates/bases/next/pages-router/js/jsconfig.json +7 -0
- package/templates/bases/next/pages-router/js/next.config.mjs +7 -0
- package/templates/bases/next/pages-router/js/package.json +15 -0
- package/templates/bases/next/pages-router/js/public/favicon.ico +0 -0
- package/templates/bases/next/pages-router/js/public/file.svg +1 -0
- package/templates/bases/next/pages-router/js/public/globe.svg +1 -0
- package/templates/bases/next/pages-router/js/public/next.svg +1 -0
- package/templates/bases/next/pages-router/js/public/vercel.svg +1 -0
- package/templates/bases/next/pages-router/js/public/window.svg +1 -0
- package/templates/bases/next/pages-router/js/src/pages/404.js +35 -0
- package/templates/bases/next/pages-router/js/src/pages/500.js +35 -0
- package/templates/bases/next/pages-router/js/src/pages/_app.js +20 -0
- package/templates/bases/next/pages-router/js/src/pages/_document.js +15 -0
- package/templates/bases/next/pages-router/js/src/pages/api/hello.js +5 -0
- package/templates/bases/next/pages-router/js/src/pages/blog/[slug].js +41 -0
- package/templates/bases/next/pages-router/js/src/pages/index.js +77 -0
- package/templates/bases/next/pages-router/js/src/styles/Home.module.css +149 -0
- package/templates/bases/next/pages-router/js/src/styles/globals.css +42 -0
- package/templates/bases/next/pages-router/ts/.provenance.json +19 -0
- package/templates/bases/next/pages-router/ts/README.md +40 -0
- package/templates/bases/next/pages-router/ts/next.config.ts +8 -0
- package/templates/bases/next/pages-router/ts/package.json +21 -0
- package/templates/bases/next/pages-router/ts/public/favicon.ico +0 -0
- package/templates/bases/next/pages-router/ts/public/file.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/globe.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/next.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/vercel.svg +1 -0
- package/templates/bases/next/pages-router/ts/public/window.svg +1 -0
- package/templates/bases/next/pages-router/ts/src/pages/404.tsx +35 -0
- package/templates/bases/next/pages-router/ts/src/pages/500.tsx +35 -0
- package/templates/bases/next/pages-router/ts/src/pages/_app.tsx +21 -0
- package/templates/bases/next/pages-router/ts/src/pages/_document.tsx +15 -0
- package/templates/bases/next/pages-router/ts/src/pages/api/hello.ts +13 -0
- package/templates/bases/next/pages-router/ts/src/pages/blog/[slug].tsx +46 -0
- package/templates/bases/next/pages-router/ts/src/pages/index.tsx +77 -0
- package/templates/bases/next/pages-router/ts/src/styles/Home.module.css +149 -0
- package/templates/bases/next/pages-router/ts/src/styles/globals.css +42 -0
- package/templates/bases/next/pages-router/ts/tsconfig.json +29 -0
- package/templates/conditional/database/prisma/db.js +14 -0
- package/templates/conditional/database/prisma/db.ts +16 -0
- package/templates/conditional/database/prisma/schema.prisma +9 -0
- package/templates/conditional/database/prisma/seed.js +16 -0
- package/templates/conditional/database/prisma/seed.ts +16 -0
- package/templates/conditional/docker/.dockerignore +10 -0
- package/templates/conditional/docker/Dockerfile +57 -0
- package/templates/conditional/docker/docker-compose.yml +35 -0
- package/templates/conditional/linting/biome/biome.json +31 -0
- package/templates/conditional/next/config/cloudflare/next.config.mjs +6 -0
- package/templates/conditional/next/config/cloudflare/next.config.ts +7 -0
- package/templates/conditional/next/config/node/next.config.mjs +6 -0
- package/templates/conditional/next/config/node/next.config.ts +7 -0
- package/templates/conditional/next/config/static/next.config.mjs +6 -0
- package/templates/conditional/next/config/static/next.config.ts +7 -0
- package/templates/conditional/next/config/turbopack/next.config.mjs +7 -0
- package/templates/conditional/next/config/turbopack/next.config.ts +8 -0
- package/templates/conditional/next/config/vercel/next.config.mjs +6 -0
- package/templates/conditional/next/config/vercel/next.config.ts +7 -0
- package/templates/conditional/next/config/webpack/next.config.mjs +9 -0
- package/templates/conditional/next/config/webpack/next.config.ts +10 -0
- package/templates/conditional/next/font/BUILD_SIZE_NOTE.md +17 -0
- package/templates/conditional/next/font/app-router/src/app/layout.js +25 -0
- package/templates/conditional/next/font/app-router/src/app/layout.tsx +30 -0
- package/templates/conditional/next/font/pages-router/src/pages/_app.js +20 -0
- package/templates/conditional/next/font/pages-router/src/pages/_app.tsx +21 -0
- package/templates/conditional/next/font/pages-router/src/pages/_document.js +18 -0
- package/templates/conditional/next/font/pages-router/src/pages/_document.tsx +18 -0
- package/templates/conditional/next/font/src/app/layout.js +25 -0
- package/templates/conditional/next/font/src/app/layout.tsx +30 -0
- package/templates/conditional/next/font/src/lib/fonts.js +11 -0
- package/templates/conditional/next/font/src/lib/fonts.ts +11 -0
- package/templates/conditional/next/font/src/pages/_app.js +20 -0
- package/templates/conditional/next/font/src/pages/_app.tsx +21 -0
- package/templates/conditional/next/font/src/pages/_document.js +18 -0
- package/templates/conditional/next/font/src/pages/_document.tsx +18 -0
- package/templates/conditional/next/image/BUILD_SIZE_NOTE.md +15 -0
- package/templates/conditional/next/image/app-router/src/components/ImageExample.jsx +34 -0
- package/templates/conditional/next/image/app-router/src/components/ImageExample.tsx +44 -0
- package/templates/conditional/next/image/pages-router/src/components/ImageExample.jsx +34 -0
- package/templates/conditional/next/image/pages-router/src/components/ImageExample.tsx +44 -0
- package/templates/conditional/next/image/src/components/ImageExample.jsx +44 -0
- package/templates/conditional/next/image/src/components/ImageExample.tsx +54 -0
- package/templates/conditional/next/image/src/components/image/index.js +1 -0
- package/templates/conditional/next/image/src/components/image/index.ts +2 -0
- package/templates/conditional/next/route-groups/js/src/app/(admin)/layout.jsx +23 -0
- package/templates/conditional/next/route-groups/js/src/app/(auth)/layout.jsx +17 -0
- package/templates/conditional/next/route-groups/js/src/app/(private)/layout.jsx +27 -0
- package/templates/conditional/next/route-groups/js/src/app/(public)/layout.jsx +28 -0
- package/templates/conditional/next/route-groups/js/src/app/(public)/page.jsx +38 -0
- package/templates/conditional/next/route-groups/js/src/middleware.js +48 -0
- package/templates/conditional/next/route-groups/ts/src/app/(admin)/layout.tsx +28 -0
- package/templates/conditional/next/route-groups/ts/src/app/(auth)/layout.tsx +22 -0
- package/templates/conditional/next/route-groups/ts/src/app/(private)/layout.tsx +32 -0
- package/templates/conditional/next/route-groups/ts/src/app/(public)/layout.tsx +33 -0
- package/templates/conditional/next/route-groups/ts/src/app/(public)/page.tsx +38 -0
- package/templates/conditional/next/route-groups/ts/src/middleware.ts +49 -0
- package/templates/conditional/next/server-components/README.md +13 -0
- package/templates/conditional/next/server-components/eslint.config.mjs +47 -0
- package/templates/conditional/next/server-components/rules/no-server-imports-in-client.js +89 -0
- package/templates/conditional/next/server-components/rules/no-server-imports-in-client.mjs +88 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ClientCounter.jsx +48 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ClientCounter.tsx +53 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ServerCard.jsx +41 -0
- package/templates/conditional/next/server-components/src/components/boundaries/ServerCard.tsx +46 -0
- package/templates/conditional/next/server-components/src/components/boundaries/index.js +2 -0
- package/templates/conditional/next/server-components/src/components/boundaries/index.ts +4 -0
- package/templates/conditional/testing/jest/next/app-router/src/__tests__/page.test.jsx +10 -0
- package/templates/conditional/testing/jest/next/app-router/src/__tests__/page.test.tsx +10 -0
- package/templates/conditional/testing/jest/next/jest.config.mjs +20 -0
- package/templates/conditional/testing/jest/next/jest.config.ts +20 -0
- package/templates/conditional/testing/jest/next/pages-router/src/__tests__/index.test.jsx +10 -0
- package/templates/conditional/testing/jest/next/pages-router/src/__tests__/index.test.tsx +10 -0
- package/templates/conditional/testing/vitest/next/app-router/src/__tests__/page.test.jsx +11 -0
- package/templates/conditional/testing/vitest/next/app-router/src/__tests__/page.test.tsx +11 -0
- package/templates/conditional/testing/vitest/next/pages-router/src/__tests__/index.test.jsx +11 -0
- package/templates/conditional/testing/vitest/next/pages-router/src/__tests__/index.test.tsx +11 -0
- package/templates/conditional/testing/vitest/next/vitest.config.js +16 -0
- package/templates/conditional/testing/vitest/next/vitest.config.ts +16 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
FROM node:22-alpine AS base
|
|
2
|
+
|
|
3
|
+
# Install dependencies only when needed
|
|
4
|
+
FROM base AS deps
|
|
5
|
+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
|
6
|
+
RUN apk add --no-cache libc6-compat
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
# Install dependencies based on the preferred package manager
|
|
10
|
+
COPY package.json package-lock.json* yarn.lock* pnpm-lock.yaml* bun.lockb* bun.lock* ./
|
|
11
|
+
RUN \
|
|
12
|
+
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
|
13
|
+
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
|
|
14
|
+
elif [ -f package-lock.json ]; then npm ci; \
|
|
15
|
+
elif [ -f bun.lockb ] || [ -f bun.lock ]; then corepack enable bun && bun install --frozen-lockfile; \
|
|
16
|
+
else npm i; \
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Rebuild the source code only when needed
|
|
20
|
+
FROM base AS builder
|
|
21
|
+
WORKDIR /app
|
|
22
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
23
|
+
COPY . .
|
|
24
|
+
|
|
25
|
+
# Next.js collects completely anonymous telemetry data about general usage.
|
|
26
|
+
# Learn more here: https://nextjs.org/telemetry
|
|
27
|
+
# Uncomment the following line in case you want to disable telemetry during the build.
|
|
28
|
+
ENV NEXT_TELEMETRY_DISABLED=1
|
|
29
|
+
|
|
30
|
+
RUN npm run build
|
|
31
|
+
|
|
32
|
+
# Production image, copy all the files and run next
|
|
33
|
+
FROM base AS runner
|
|
34
|
+
WORKDIR /app
|
|
35
|
+
|
|
36
|
+
ENV NODE_ENV=production
|
|
37
|
+
# Uncomment the following line in case you want to disable telemetry during runtime.
|
|
38
|
+
ENV NEXT_TELEMETRY_DISABLED=1
|
|
39
|
+
|
|
40
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
41
|
+
RUN adduser --system --uid 1001 nextjs
|
|
42
|
+
|
|
43
|
+
COPY --chown=nextjs:nodejs public ./public
|
|
44
|
+
|
|
45
|
+
# Automatically leverage output traces to reduce image size
|
|
46
|
+
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
|
47
|
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
48
|
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
49
|
+
|
|
50
|
+
USER nextjs
|
|
51
|
+
|
|
52
|
+
EXPOSE 3000
|
|
53
|
+
|
|
54
|
+
ENV PORT=3000
|
|
55
|
+
ENV HOSTNAME="0.0.0.0"
|
|
56
|
+
|
|
57
|
+
CMD ["node", "server.js"]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
build:
|
|
4
|
+
context: .
|
|
5
|
+
dockerfile: Dockerfile
|
|
6
|
+
restart: always
|
|
7
|
+
ports:
|
|
8
|
+
- "3000:3000"
|
|
9
|
+
environment:
|
|
10
|
+
- NODE_ENV=production
|
|
11
|
+
- PORT=3000
|
|
12
|
+
- DATABASE_URL=postgresql://postgres:postgres@db:5432/app?schema=public
|
|
13
|
+
depends_on:
|
|
14
|
+
db:
|
|
15
|
+
condition: service_healthy
|
|
16
|
+
|
|
17
|
+
db:
|
|
18
|
+
image: postgres:16-alpine
|
|
19
|
+
restart: always
|
|
20
|
+
environment:
|
|
21
|
+
POSTGRES_USER: postgres
|
|
22
|
+
POSTGRES_PASSWORD: postgres
|
|
23
|
+
POSTGRES_DB: app
|
|
24
|
+
ports:
|
|
25
|
+
- "5432:5432"
|
|
26
|
+
volumes:
|
|
27
|
+
- postgres_data:/var/lib/postgresql/data
|
|
28
|
+
healthcheck:
|
|
29
|
+
test: ["CMD-SHELL", "pg_isready -U postgres -d app"]
|
|
30
|
+
interval: 5s
|
|
31
|
+
timeout: 5s
|
|
32
|
+
retries: 5
|
|
33
|
+
|
|
34
|
+
volumes:
|
|
35
|
+
postgres_data:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": false,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"ignoreUnknown": false,
|
|
10
|
+
"ignore": []
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"indentStyle": "space",
|
|
15
|
+
"indentWidth": 2
|
|
16
|
+
},
|
|
17
|
+
"organizeImports": {
|
|
18
|
+
"enabled": true
|
|
19
|
+
},
|
|
20
|
+
"linter": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"rules": {
|
|
23
|
+
"recommended": true
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"javascript": {
|
|
27
|
+
"formatter": {
|
|
28
|
+
"quoteStyle": "double"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# next/font Build Size and Performance Impact
|
|
2
|
+
|
|
3
|
+
## Zero Layout Shift & Self-Hosting
|
|
4
|
+
`next/font` (specifically `Geist` and `Geist_Mono` via `next/font/google`) automatically optimizes font loading:
|
|
5
|
+
1. **Self-Hosting at Build Time**: Google Fonts are downloaded during `next build` and hosted alongside your static assets directly from the same domain. No external requests are made to Google Fonts servers by the browser at runtime, improving privacy and removing DNS/TLS negotiation latency.
|
|
6
|
+
2. **Zero Cumulative Layout Shift (CLS)**: Uses CSS `size-adjust` to match fallback fonts automatically while custom fonts are loading.
|
|
7
|
+
3. **Preloaded Subsets**: Automatically subsets font glyphs (defaulting to `latin`) to reduce file weight.
|
|
8
|
+
|
|
9
|
+
## Bundle Footprint
|
|
10
|
+
- **Runtime JavaScript**: ~0 bytes (compiled away into CSS variables and HTML classes).
|
|
11
|
+
- **Static Assets**: ~20-30 KB compressed WOFF2 font payload served statically with aggressive caching (`Cache-Control: public, max-age=31536000, immutable`).
|
|
12
|
+
- **HTML/CSS Injection**: Inline CSS variable definitions (`--font-geist-sans`, `--font-geist-mono`) attached to root wrappers, eliminating render-blocking external stylesheet links.
|
|
13
|
+
|
|
14
|
+
## Parity Across Routers
|
|
15
|
+
- **App Router**: Wired into root `app/layout.tsx` (or `app/layout.js`) via `className={`${geistSans.variable} ${geistMono.variable}`}` on `<html>`.
|
|
16
|
+
- **Pages Router**: Wired into root `pages/_app.tsx` (or `pages/_app.js`) wrapping the page tree with `${geistSans.variable} ${geistMono.variable}`. (Note: Per Next.js compiler specifications, `next/font` is strictly prohibited inside `pages/_document.js` with a compile-time error and must be loaded in `_app.js` or page components).
|
|
17
|
+
- Both routers expose identical CSS custom properties for global and modular CSS styling.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
|
|
4
|
+
const geistSans = Geist({
|
|
5
|
+
variable: "--font-geist-sans",
|
|
6
|
+
subsets: ["latin"],
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const geistMono = Geist_Mono({
|
|
10
|
+
variable: "--font-geist-mono",
|
|
11
|
+
subsets: ["latin"],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const metadata = {
|
|
15
|
+
title: "Create Lumen App",
|
|
16
|
+
description: "Generated by create-lumen",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function RootLayout({ children }) {
|
|
20
|
+
return (
|
|
21
|
+
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
22
|
+
<body className="antialiased">{children}</body>
|
|
23
|
+
</html>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
|
|
5
|
+
const geistSans = Geist({
|
|
6
|
+
variable: "--font-geist-sans",
|
|
7
|
+
subsets: ["latin"],
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const geistMono = Geist_Mono({
|
|
11
|
+
variable: "--font-geist-mono",
|
|
12
|
+
subsets: ["latin"],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const metadata: Metadata = {
|
|
16
|
+
title: "Create Lumen App",
|
|
17
|
+
description: "Generated by create-lumen",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default function RootLayout({
|
|
21
|
+
children,
|
|
22
|
+
}: Readonly<{
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}>) {
|
|
25
|
+
return (
|
|
26
|
+
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
27
|
+
<body className="antialiased">{children}</body>
|
|
28
|
+
</html>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "@/styles/globals.css";
|
|
2
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
+
|
|
4
|
+
const geistSans = Geist({
|
|
5
|
+
variable: "--font-geist-sans",
|
|
6
|
+
subsets: ["latin"],
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const geistMono = Geist_Mono({
|
|
10
|
+
variable: "--font-geist-mono",
|
|
11
|
+
subsets: ["latin"],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default function App({ Component, pageProps }) {
|
|
15
|
+
return (
|
|
16
|
+
<div className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
17
|
+
<Component {...pageProps} />
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import "@/styles/globals.css";
|
|
2
|
+
import type { AppProps } from "next/app";
|
|
3
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
4
|
+
|
|
5
|
+
const geistSans = Geist({
|
|
6
|
+
variable: "--font-geist-sans",
|
|
7
|
+
subsets: ["latin"],
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const geistMono = Geist_Mono({
|
|
11
|
+
variable: "--font-geist-mono",
|
|
12
|
+
subsets: ["latin"],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
16
|
+
return (
|
|
17
|
+
<div className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
18
|
+
<Component {...pageProps} />
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Html, Head, Main, NextScript } from "next/document";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pages Router Custom Document.
|
|
5
|
+
* Note: Per Next.js compiler specifications, next/font loaders are configured
|
|
6
|
+
* in pages/_app to avoid the 'Cannot be used within pages/_document' compile error.
|
|
7
|
+
*/
|
|
8
|
+
export default function Document() {
|
|
9
|
+
return (
|
|
10
|
+
<Html lang="en">
|
|
11
|
+
<Head />
|
|
12
|
+
<body className="antialiased">
|
|
13
|
+
<Main />
|
|
14
|
+
<NextScript />
|
|
15
|
+
</body>
|
|
16
|
+
</Html>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Html, Head, Main, NextScript } from "next/document";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pages Router Custom Document.
|
|
5
|
+
* Note: Per Next.js compiler specifications, next/font loaders are configured
|
|
6
|
+
* in pages/_app to avoid the 'Cannot be used within pages/_document' compile error.
|
|
7
|
+
*/
|
|
8
|
+
export default function Document() {
|
|
9
|
+
return (
|
|
10
|
+
<Html lang="en">
|
|
11
|
+
<Head />
|
|
12
|
+
<body className="antialiased">
|
|
13
|
+
<Main />
|
|
14
|
+
<NextScript />
|
|
15
|
+
</body>
|
|
16
|
+
</Html>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
|
|
4
|
+
const geistSans = Geist({
|
|
5
|
+
variable: "--font-geist-sans",
|
|
6
|
+
subsets: ["latin"],
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const geistMono = Geist_Mono({
|
|
10
|
+
variable: "--font-geist-mono",
|
|
11
|
+
subsets: ["latin"],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const metadata = {
|
|
15
|
+
title: "Create Lumen App",
|
|
16
|
+
description: "Generated by create-lumen",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function RootLayout({ children }) {
|
|
20
|
+
return (
|
|
21
|
+
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
22
|
+
<body className="antialiased">{children}</body>
|
|
23
|
+
</html>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
|
|
5
|
+
const geistSans = Geist({
|
|
6
|
+
variable: "--font-geist-sans",
|
|
7
|
+
subsets: ["latin"],
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const geistMono = Geist_Mono({
|
|
11
|
+
variable: "--font-geist-mono",
|
|
12
|
+
subsets: ["latin"],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const metadata: Metadata = {
|
|
16
|
+
title: "Create Lumen App",
|
|
17
|
+
description: "Generated by create-lumen",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default function RootLayout({
|
|
21
|
+
children,
|
|
22
|
+
}: Readonly<{
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}>) {
|
|
25
|
+
return (
|
|
26
|
+
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
27
|
+
<body className="antialiased">{children}</body>
|
|
28
|
+
</html>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "@/styles/globals.css";
|
|
2
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
+
|
|
4
|
+
const geistSans = Geist({
|
|
5
|
+
variable: "--font-geist-sans",
|
|
6
|
+
subsets: ["latin"],
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const geistMono = Geist_Mono({
|
|
10
|
+
variable: "--font-geist-mono",
|
|
11
|
+
subsets: ["latin"],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default function App({ Component, pageProps }) {
|
|
15
|
+
return (
|
|
16
|
+
<div className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
17
|
+
<Component {...pageProps} />
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import "@/styles/globals.css";
|
|
2
|
+
import type { AppProps } from "next/app";
|
|
3
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
4
|
+
|
|
5
|
+
const geistSans = Geist({
|
|
6
|
+
variable: "--font-geist-sans",
|
|
7
|
+
subsets: ["latin"],
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const geistMono = Geist_Mono({
|
|
11
|
+
variable: "--font-geist-mono",
|
|
12
|
+
subsets: ["latin"],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
16
|
+
return (
|
|
17
|
+
<div className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
18
|
+
<Component {...pageProps} />
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Html, Head, Main, NextScript } from "next/document";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pages Router Custom Document.
|
|
5
|
+
* Note: Per Next.js compiler specifications, next/font loaders are configured
|
|
6
|
+
* in pages/_app to avoid the 'Cannot be used within pages/_document' compile error.
|
|
7
|
+
*/
|
|
8
|
+
export default function Document() {
|
|
9
|
+
return (
|
|
10
|
+
<Html lang="en">
|
|
11
|
+
<Head />
|
|
12
|
+
<body className="antialiased">
|
|
13
|
+
<Main />
|
|
14
|
+
<NextScript />
|
|
15
|
+
</body>
|
|
16
|
+
</Html>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Html, Head, Main, NextScript } from "next/document";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pages Router Custom Document.
|
|
5
|
+
* Note: Per Next.js compiler specifications, next/font loaders are configured
|
|
6
|
+
* in pages/_app to avoid the 'Cannot be used within pages/_document' compile error.
|
|
7
|
+
*/
|
|
8
|
+
export default function Document() {
|
|
9
|
+
return (
|
|
10
|
+
<Html lang="en">
|
|
11
|
+
<Head />
|
|
12
|
+
<body className="antialiased">
|
|
13
|
+
<Main />
|
|
14
|
+
<NextScript />
|
|
15
|
+
</body>
|
|
16
|
+
</Html>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# next/image Build Size and Performance Impact
|
|
2
|
+
|
|
3
|
+
## Built-In Optimization
|
|
4
|
+
`next/image` extends standard HTML `<img>` elements with automatic visual stability and performance optimizations:
|
|
5
|
+
1. **Zero Cumulative Layout Shift (CLS)**: Enforces explicit `width` and `height` dimensions or fills the parent container with `fill`, reserving geometric space before the bitmap payload loads.
|
|
6
|
+
2. **Modern Format Negotiation**: Serves WebP and AVIF modern formats dynamically when supported by the requesting browser, yielding 30–50% bandwidth reduction compared to legacy JPEG/PNG.
|
|
7
|
+
3. **Native Lazy Loading**: Viewport-aware on-demand loading so off-screen images do not delay initial page interactivity. The `priority` property allows opting into preloading for Largest Contentful Paint (LCP) elements.
|
|
8
|
+
|
|
9
|
+
## Bundle Footprint
|
|
10
|
+
- **Runtime JavaScript Overhead**: ~5 KB gzipped client-side runtime handling IntersectionObserver and responsive `srcSet` generation.
|
|
11
|
+
- **Build Impact**: Zero additional build time overhead during static compilation when referencing local SVGs or remote URLs; image transformations are handled on-demand by the Next.js server image optimizer.
|
|
12
|
+
|
|
13
|
+
## Router Parity
|
|
14
|
+
- **App Router**: Fully compatible with both Server Components (static rendering) and Client Components (`"use client"`).
|
|
15
|
+
- **Pages Router**: Fully compatible with all page and component hierarchies.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Image from "next/image";
|
|
3
|
+
|
|
4
|
+
export function ImageExample({
|
|
5
|
+
src = "/next.svg",
|
|
6
|
+
alt = "Next.js logo",
|
|
7
|
+
width = 180,
|
|
8
|
+
height = 37,
|
|
9
|
+
priority = false,
|
|
10
|
+
className = "",
|
|
11
|
+
caption = "Optimized with next/image",
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<figure className={`inline-flex flex-col items-center gap-2 p-4 rounded-xl border border-gray-200 dark:border-gray-800 bg-white/50 dark:bg-black/20 ${className}`}>
|
|
15
|
+
<div className="relative flex items-center justify-center p-2">
|
|
16
|
+
<Image
|
|
17
|
+
src={src}
|
|
18
|
+
alt={alt}
|
|
19
|
+
width={width}
|
|
20
|
+
height={height}
|
|
21
|
+
priority={priority}
|
|
22
|
+
className="dark:invert transition-transform hover:scale-105"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
{caption && (
|
|
26
|
+
<figcaption className="text-xs text-gray-500 dark:text-gray-400 text-center font-mono">
|
|
27
|
+
{caption}
|
|
28
|
+
</figcaption>
|
|
29
|
+
)}
|
|
30
|
+
</figure>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default ImageExample;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Image from "next/image";
|
|
3
|
+
|
|
4
|
+
export interface ImageExampleProps {
|
|
5
|
+
src?: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
priority?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
caption?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ImageExample({
|
|
15
|
+
src = "/next.svg",
|
|
16
|
+
alt = "Next.js logo",
|
|
17
|
+
width = 180,
|
|
18
|
+
height = 37,
|
|
19
|
+
priority = false,
|
|
20
|
+
className = "",
|
|
21
|
+
caption = "Optimized with next/image",
|
|
22
|
+
}: ImageExampleProps) {
|
|
23
|
+
return (
|
|
24
|
+
<figure className={`inline-flex flex-col items-center gap-2 p-4 rounded-xl border border-gray-200 dark:border-gray-800 bg-white/50 dark:bg-black/20 ${className}`}>
|
|
25
|
+
<div className="relative flex items-center justify-center p-2">
|
|
26
|
+
<Image
|
|
27
|
+
src={src}
|
|
28
|
+
alt={alt}
|
|
29
|
+
width={width}
|
|
30
|
+
height={height}
|
|
31
|
+
priority={priority}
|
|
32
|
+
className="dark:invert transition-transform hover:scale-105"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
{caption && (
|
|
36
|
+
<figcaption className="text-xs text-gray-500 dark:text-gray-400 text-center font-mono">
|
|
37
|
+
{caption}
|
|
38
|
+
</figcaption>
|
|
39
|
+
)}
|
|
40
|
+
</figure>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default ImageExample;
|