Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .babelrc

This file was deleted.

2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 16 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ dev:
build:
npm run build

preview:
npm run preview
start:
npm run start

lint:
npm run lint
Expand Down Expand Up @@ -34,4 +34,11 @@ docker-down:
docker compose down

docker-e2e:
docker compose -f docker-compose.e2e.yml run --rm e2e
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
108 changes: 45 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -27,15 +28,15 @@ TypeScript + React app built with Webpack.
npm ci
```

### Run Dev Server
### Run the Development Server

```bash
npm run dev
```

Open:

- [http://localhost:5173](http://localhost:5173)
- [http://localhost:3000](http://localhost:3000)

### Typecheck

Expand Down Expand Up @@ -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

Expand All @@ -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`.

5 changes: 2 additions & 3 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ services:
image: projectsparks-web
build: .
ports:
- "8080:80"
- "4173:4173"
2 changes: 1 addition & 1 deletion pages/about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export default function AboutPage() {
return (
<section>
<h1>About</h1>
<p>This repo is intentionally “from scratch” (Webpack, Docker, CI) to show the full pipeline.</p>
<p>This repo is intentionally “from scratch” (Next.js + SWC, Docker, CI) to show the full pipeline.</p>
</section>
);
}
2 changes: 1 addition & 1 deletion pages/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
},
];

Expand Down