diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 23629c0..0000000 --- a/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - ["@babel/preset-env"], - ["@babel/preset-react", { "runtime": "automatic" }], - ["@babel/preset-typescript"] - ] -} diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e79a6bc..1350274 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,6 +1,6 @@ module.exports = { root: true, - ignorePatterns: ["dist/", "node_modules/", "*.config.js", "webpack.config.js"], + ignorePatterns: ["dist/", "node_modules/", "*.config.js"], env: { browser: true, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e8071c..6d2fa29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,10 +22,10 @@ jobs: - name: Install dependencies run: npm ci --include=dev - - name: Verify core framework dependencies + - name: Verify Next.js + SWC setup run: | node -e "const pkgs=['next','react','react-dom']; for (const pkg of pkgs){const path=require.resolve(pkg + '/package.json'); const version=require(path).version; console.log(pkg + '@' + version)}" - test -f node_modules/next/dist/bin/next + test ! -f .babelrc - name: Lockfile reproducibility check run: git diff --exit-code package-lock.json diff --git a/Dockerfile b/Dockerfile index 95c4b08..dfc2687 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,27 @@ -# ----- build stage ----- FROM node:20-alpine AS build WORKDIR /app +ENV NEXT_TELEMETRY_DISABLED=1 COPY package*.json ./ RUN npm ci COPY . . +# Next.js compiles with SWC by default when no Babel config is present RUN npm run build -# ----- runtime stage ----- -FROM nginx:1.27-alpine -COPY --from=build /app/dist /usr/share/nginx/html +FROM node:20-alpine AS runtime +WORKDIR /app +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +COPY package*.json ./ +RUN npm ci --omit=dev -# SPA routing support -RUN rm /etc/nginx/conf.d/default.conf -COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/.next ./.next +COPY --from=build /app/pages ./pages +COPY --from=build /app/src ./src +COPY --from=build /app/next-env.d.ts ./next-env.d.ts +COPY --from=build /app/tsconfig.json ./tsconfig.json -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] +EXPOSE 4173 +CMD ["npm", "run", "start"] diff --git a/Makefile b/Makefile index 4b1ce4b..807ffd6 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ dev: build: npm run build -preview: - npm run preview +start: + npm run start lint: npm run lint @@ -34,4 +34,11 @@ docker-down: docker compose down docker-e2e: - docker compose -f docker-compose.e2e.yml run --rm e2e \ No newline at end of file + docker compose -f docker-compose.e2e.yml run --rm e2e + +ci: + npm ci + npm run typecheck + npm run lint + npm run test:run + npm run build diff --git a/README.md b/README.md index bf4759f..7beba09 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,25 @@ # ProjectSparks -TypeScript + React app built with Webpack. +TypeScript + React application built with **Next.js (SWC compiler)**. ## Tech Stack +- Next.js 15 (Pages Router) - React 18 - TypeScript -- Webpack 5 -- Babel (TS/React presets) -- Docker + Docker Compose (dev + production-style builds) +- SWC (Next.js built-in compiler/minifier; no Babel pipeline) - ESLint + Prettier -- Vitest +- Vitest + Testing Library - Playwright + start-server-and-test -- Husky +- Docker + Docker Compose +- Husky + lint-staged +- GitHub Actions CI ## Getting Started ### Requirements -- Node (see `.nvmrc`) +- Node.js 20+ - npm ### Install @@ -27,7 +28,7 @@ TypeScript + React app built with Webpack. npm ci ``` -### Run Dev Server +### Run the Development Server ```bash npm run dev @@ -35,7 +36,7 @@ npm run dev Open: -- [http://localhost:5173](http://localhost:5173) +- [http://localhost:3000](http://localhost:3000) ### Typecheck @@ -69,54 +70,43 @@ npm run e2e:ci npm run build ``` -Output is written to dist/ +Next.js build output is written to `.next/`. -### Preview Production Build Locally +### Run Production Server Locally ```bash -npm run preview +npm run start ``` Open: -- [http://localhost:5173](http://localhost:5173) - -## Analyze bundle -```bash -npm run analyze -``` +- [http://localhost:4173](http://localhost:4173) ## Docker -### Production (Docker Compose) +### Development (Docker Compose) -Run the production nginx container (no dev server): +Runs `next dev` in a container with your local source mounted for live edits. ```bash -docker compose -f docker-compose.yml up --build +docker compose up --build ``` Open: -- [http://localhost:5173](http://localhost:5173) +- [http://localhost:4173](http://localhost:4173) -### Dev (Docker Compose) +### Production (Docker Compose) -This runs the webpack dev server inside a container and mounts your local source code into it. +Builds and runs `next start` on port `4173`. ```bash -docker compose up --build +docker compose -f docker-compose.yml up --build ``` Open: -- [http://localhost:5173](http://localhost:5173) - -Stop: - -```bash -docker compose down -``` +- [http://localhost:4173](http://localhost:4173) ### Production-style Container @@ -129,57 +119,49 @@ docker build -t projectsparks-web . Run it: ```bash -docker run --rm -p 8080:80 projectsparks-web +docker run --rm -p 4173:4173 projectsparks-web ``` Open: -- [http://localhost:8080](http://localhost:8080) - -## Git Hooks (Husky) +- [http://localhost:4173](http://localhost:4173) -This repo uses Husky + lint-staged to enforce formatting and linting on commit. +## CI -- Prettier runs on staged files -- ESLint runs on staged JS/TS files +GitHub Actions runs: -If hooks don’t run after cloning, make sure you’ve installed dependencies: +- `npm ci` +- `npm run typecheck` +- `npm run lint` +- `npm run test:run` +- `npm run build` +- `npm run e2e:ci` -```bash -npm ci -``` +CI also verifies there is no project Babel configuration so Next.js compiles with SWC. ## Project Layout -- `src/` — React + TypeScript application source -- `public/` — HTML template and static assets -- `dist/` — production build output (generated) +- `pages/` — Next.js Pages Router routes +- `src/` — shared React/TypeScript components, styles, and test setup +- `.next/` — Next.js build output (generated) - `e2e/` — Playwright end-to-end tests -- `webpack.config.cjs` — Webpack configuration (dev + prod) +- `.github/workflows/ci.yml` — CI pipeline +- `Dockerfile` — production Next.js container build +- `docker-compose.yml` — production container config +- `docker-compose.override.yml` — development container overrides +- `docker-compose.e2e.yml` — Playwright tests inside Docker + - `tsconfig.json` — TypeScript compiler settings - `vitest.config.ts` — Vitest configuration - `playwright.config.ts` — Playwright configuration - -- `Dockerfile` — multi-stage build (Node build → Nginx runtime) -- `nginx.conf` — Nginx SPA routing config -- `docker-compose.yml` — production-style container (Nginx runtime) -- `docker-compose.override.yml` — dev overrides (bind mounts + dev server) -- `docker-compose.e2e.yml` - Playwright end-to-end tests inside docker container - -- `.github/` — CI workflow + Dependabot configuration - `commitlint.config.cjs` — commit message lint rules - `CHANGELOG.md` — release notes / project history - - `package.json` / `package-lock.json` — dependencies + scripts -- `node_modules/` — installed dependencies (not committed) -- `Makefile` - convenience shortcuts for common tasks +- `Makefile` — convenience shortcuts for common tasks ### Notes -- `dist/` is generated output and should not be committed. +- `.next/` is generated output and should not be committed. +- This repo intentionally does **not** include a Babel config file, so Next.js uses SWC end-to-end. - `package-lock.json` must be generated by npm commands (`npm install` / `npm ci`) and never hand-edited. -- CI validates lockfile reproducibility after install; any unintended lockfile changes should fail the build. -- CI runs `npm ci`, `npm run typecheck`, and `npm run build` on every PR/push. -- Git hooks are managed by Husky and installed automatically on `npm ci`. - diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 39074e6..3ffff54 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -3,12 +3,11 @@ services: build: context: . target: build - command: npm run dev + command: npm run dev -- -p 4173 ports: - - "4173:8080" + - "4173:4173" volumes: - .:/app - /app/node_modules environment: - - WATCHPACK_POLLING=true - CHOKIDAR_USEPOLLING=true diff --git a/docker-compose.yml b/docker-compose.yml index 5c806fe..17ed7d1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,4 +3,4 @@ services: image: projectsparks-web build: . ports: - - "8080:80" + - "4173:4173" diff --git a/pages/about.tsx b/pages/about.tsx index feface5..1a9afe0 100644 --- a/pages/about.tsx +++ b/pages/about.tsx @@ -2,7 +2,7 @@ export default function AboutPage() { return (

About

-

This repo is intentionally “from scratch” (Webpack, Docker, CI) to show the full pipeline.

+

This repo is intentionally “from scratch” (Next.js + SWC, Docker, CI) to show the full pipeline.

); } diff --git a/pages/projects.tsx b/pages/projects.tsx index 2015c39..f304d38 100644 --- a/pages/projects.tsx +++ b/pages/projects.tsx @@ -9,7 +9,7 @@ const PROJECTS: Project[] = [ { id: "starter", title: "Starter Template", - description: "This repo itself: Webpack + TS + Docker + CI + tests.", + description: "This repo itself: Next.js + SWC + TS + Docker + CI + tests.", }, ];