|
|
@@ -1,320 +0,0 @@
|
|
|
-# Design Document: Next.js v16 Upgrade
|
|
|
-
|
|
|
-## Overview
|
|
|
-
|
|
|
-**Purpose**: This feature upgrades the GROWI main application from Next.js 15.5.12 to Next.js 16, preserving all custom webpack configurations and module reduction achievements from the `reduce-modules-loaded` feature.
|
|
|
-
|
|
|
-**Users**: GROWI developers benefit from continued framework support, security patches, and a clear path to Turbopack adoption. End users experience no visible changes.
|
|
|
-
|
|
|
-**Impact**: Changes the build toolchain configuration while maintaining identical runtime behavior. The `--webpack` flag opts out of Turbopack as the default bundler, preserving all 5 custom loaders/plugins and 7 null-loader rules.
|
|
|
-
|
|
|
-### Goals
|
|
|
-- Upgrade Next.js from v15 to v16 with zero functional regression
|
|
|
-- Preserve all module reduction achievements (895 initial modules, 67% reduction)
|
|
|
-- Update build scripts for v16 Turbopack-default behavior
|
|
|
-- Prepare codebase for future Turbopack migration (Sass tilde fix)
|
|
|
-
|
|
|
-### Non-Goals
|
|
|
-- Turbopack migration (separate initiative — requires null-loader rewrites, custom loader testing)
|
|
|
-- React 19 upgrade (no benefit for Pages Router; separate initiative)
|
|
|
-- App Router migration
|
|
|
-- Performance optimization beyond maintaining current metrics
|
|
|
-
|
|
|
-## Architecture
|
|
|
-
|
|
|
-### Existing Architecture Analysis
|
|
|
-
|
|
|
-GROWI uses a custom Express server that programmatically initializes Next.js via `next({ dev })`. The build pipeline consists of:
|
|
|
-
|
|
|
-- **Client build**: `next build` (webpack, Pages Router)
|
|
|
-- **Server build**: `tspc` (TypeScript Project Compiler, separate from Next.js)
|
|
|
-- **Dev mode**: Express server starts Next.js dev server internally
|
|
|
-
|
|
|
-Custom webpack configuration (established in `reduce-modules-loaded`):
|
|
|
-1. **superjson-ssr-loader**: Auto-wraps `getServerSideProps` with SuperJSON serialization
|
|
|
-2. **null-loader rules** (7): Exclude server-only packages from client bundle
|
|
|
-3. **I18NextHMRPlugin**: i18n hot module replacement in dev mode
|
|
|
-4. **ChunkModuleStatsPlugin**: Module count analysis in dev mode
|
|
|
-5. **source-map-loader**: Source map extraction in dev builds
|
|
|
-6. **resolve.fallback**: `{ fs: false }` for client-side
|
|
|
-
|
|
|
-### Architecture Pattern & Boundary Map
|
|
|
-
|
|
|
-```mermaid
|
|
|
-graph TB
|
|
|
- subgraph BuildPipeline
|
|
|
- PKG[package.json scripts]
|
|
|
- NC[next.config.ts]
|
|
|
- WP[webpack config fn]
|
|
|
- end
|
|
|
-
|
|
|
- subgraph WebpackPlugins
|
|
|
- SSL[superjson-ssr-loader]
|
|
|
- NL[null-loader x7]
|
|
|
- I18N[I18NextHMRPlugin]
|
|
|
- CMS[ChunkModuleStatsPlugin]
|
|
|
- SML[source-map-loader]
|
|
|
- end
|
|
|
-
|
|
|
- subgraph V16Changes
|
|
|
- FLAG[--webpack flag]
|
|
|
- DEVDIR[.next-dev directory]
|
|
|
- SASS[Sass tilde fix]
|
|
|
- BA[bundle-analyzer bump]
|
|
|
- end
|
|
|
-
|
|
|
- PKG -->|adds --webpack| FLAG
|
|
|
- FLAG --> NC
|
|
|
- NC --> WP
|
|
|
- WP --> SSL
|
|
|
- WP --> NL
|
|
|
- WP --> I18N
|
|
|
- WP --> CMS
|
|
|
- WP --> SML
|
|
|
- DEVDIR -->|update| MCS[measure-chunk-stats.sh]
|
|
|
- SASS -->|single file| TOASTR[toastr.scss]
|
|
|
- BA -->|version bump| PKG
|
|
|
-```
|
|
|
-
|
|
|
-**Architecture Integration**:
|
|
|
-- Selected pattern: In-place upgrade with webpack opt-out (see `research.md` Decision: Webpack-Only Upgrade Strategy)
|
|
|
-- Domain boundaries: Build configuration only — no runtime logic changes
|
|
|
-- Existing patterns preserved: Phase-based config, custom webpack function, all loaders/plugins
|
|
|
-- New components: None
|
|
|
-- Steering compliance: Maintains existing monorepo build patterns
|
|
|
-
|
|
|
-### Technology Stack
|
|
|
-
|
|
|
-| Layer | Choice / Version | Role in Feature | Notes |
|
|
|
-|-------|------------------|-----------------|-------|
|
|
|
-| Framework | Next.js ^16.0.0 | Core upgrade target | From ^15.0.0 |
|
|
|
-| Bundler | webpack (via `--webpack`) | Client build | Turbopack opt-out |
|
|
|
-| Runtime | React ^18.2.0 | No change | Pages Router supports React 18 in v16 |
|
|
|
-| Analysis | @next/bundle-analyzer ^16.0.0 | Bundle analysis | Version bump from ^15.0.0 |
|
|
|
-| Node.js | ^24 | No change | Exceeds v16 minimum (20.9+) |
|
|
|
-| TypeScript | ~5.0.0 | No change | Exceeds v16 minimum (5.1+) |
|
|
|
-
|
|
|
-## System Flows
|
|
|
-
|
|
|
-### Upgrade Execution Flow
|
|
|
-
|
|
|
-```mermaid
|
|
|
-flowchart TD
|
|
|
- A[Bump next to v16] --> B[Bump bundle-analyzer to v16]
|
|
|
- B --> C[Add --webpack to build scripts]
|
|
|
- C --> D[Add --webpack to dev and measurement scripts]
|
|
|
- D --> E[Fix Sass tilde import]
|
|
|
- E --> F[Update measure-chunk-stats.sh for .next-dev]
|
|
|
- F --> G[Verify ts-node hook preservation]
|
|
|
- G --> H{Run quality checks}
|
|
|
- H -->|typecheck pass| I{Run tests}
|
|
|
- H -->|typecheck fail| J[Fix type errors]
|
|
|
- J --> H
|
|
|
- I -->|tests pass| K{Production build}
|
|
|
- I -->|tests fail| L[Fix test failures]
|
|
|
- L --> I
|
|
|
- K -->|build pass| M[Measure module counts]
|
|
|
- K -->|build fail| N[Fix build errors]
|
|
|
- N --> K
|
|
|
- M --> O[Compare with baseline]
|
|
|
- O --> P[Document results]
|
|
|
-```
|
|
|
-
|
|
|
-## Requirements Traceability
|
|
|
-
|
|
|
-| Requirement | Summary | Components | Interfaces | Flows |
|
|
|
-|-------------|---------|------------|------------|-------|
|
|
|
-| 1.1 | Upgrade next dependency | PackageUpgrade | — | Upgrade step A |
|
|
|
-| 1.2 | --webpack flag for build | BuildScriptUpdate | — | Upgrade step C |
|
|
|
-| 1.3 | --webpack flag for dev | BuildScriptUpdate | — | Upgrade step D |
|
|
|
-| 1.4 | Type compatibility | PackageUpgrade | — | Upgrade step H |
|
|
|
-| 1.5 | Quality checks pass | RegressionValidation | — | Upgrade steps H-K |
|
|
|
-| 2.1 | null-loader preservation | WebpackConfigPreservation | — | — |
|
|
|
-| 2.2 | superjson-ssr-loader preservation | WebpackConfigPreservation | — | — |
|
|
|
-| 2.3 | I18NextHMRPlugin preservation | WebpackConfigPreservation | — | — |
|
|
|
-| 2.4 | ChunkModuleStatsPlugin preservation | WebpackConfigPreservation | — | — |
|
|
|
-| 2.5 | source-map-loader preservation | WebpackConfigPreservation | — | — |
|
|
|
-| 2.6 | Module count baseline | MetricsValidation | ChunkModuleStats output | Upgrade step M |
|
|
|
-| 3.1 | build:client script update | BuildScriptUpdate | — | Upgrade step C |
|
|
|
-| 3.2 | dev script update | BuildScriptUpdate | — | Upgrade step D |
|
|
|
-| 3.3 | measure-chunk-stats.sh update | MeasurementToolUpdate | — | Upgrade step F |
|
|
|
-| 3.4 | Root commands functional | RegressionValidation | — | Upgrade step K |
|
|
|
-| 4.1 | Sass without tilde prefix | SassTildeFixup | — | Upgrade step E |
|
|
|
-| 4.2 | toastr.scss fix | SassTildeFixup | — | Upgrade step E |
|
|
|
-| 4.3 | No other tilde imports | SassTildeFixup | — | Upgrade step E |
|
|
|
-| 4.4 | Identical rendering | RegressionValidation | — | Upgrade step K |
|
|
|
-| 5.1 | bundlePagesRouterDependencies works | NextConfigValidation | — | Upgrade step K |
|
|
|
-| 5.2 | optimizePackageImports works | NextConfigValidation | — | Upgrade step K |
|
|
|
-| 5.3 | transpilePackages works | NextConfigValidation | — | Upgrade step K |
|
|
|
-| 5.4 | New v16 options evaluation | NextConfigValidation | — | — |
|
|
|
-| 5.5 | Deprecated options updated | NextConfigValidation | — | — |
|
|
|
-| 6.1 | ts-node hook preservation | TsNodeHookPreservation | — | Upgrade step G |
|
|
|
-| 6.2 | v16 transpiler behavior check | TsNodeHookPreservation | — | Upgrade step G |
|
|
|
-| 6.3 | Dev mode TypeScript loading | TsNodeHookPreservation | — | Upgrade step G |
|
|
|
-| 7.1 | Unit tests pass | RegressionValidation | — | Upgrade step I |
|
|
|
-| 7.2 | TypeScript typecheck passes | RegressionValidation | — | Upgrade step H |
|
|
|
-| 7.3 | Biome lint passes | RegressionValidation | — | Upgrade step H |
|
|
|
-| 7.4 | Production build succeeds | RegressionValidation | — | Upgrade step K |
|
|
|
-| 7.5 | SuperJSON round-trip works | RegressionValidation | — | Upgrade step I |
|
|
|
-| 7.6 | Catch-all page compiles | RegressionValidation | — | Upgrade step M |
|
|
|
-| 7.7 | Before/after metrics documented | MetricsValidation | — | Upgrade steps M-P |
|
|
|
-
|
|
|
-## Components and Interfaces
|
|
|
-
|
|
|
-| Component | Domain/Layer | Intent | Req Coverage | Key Dependencies | Contracts |
|
|
|
-|-----------|-------------|--------|--------------|-----------------|-----------|
|
|
|
-| PackageUpgrade | Build | Bump next and bundle-analyzer versions | 1.1, 1.4 | package.json (P0) | — |
|
|
|
-| BuildScriptUpdate | Build | Add --webpack flag to scripts | 1.2, 1.3, 3.1, 3.2, 3.4 | package.json (P0) | — |
|
|
|
-| MeasurementToolUpdate | Tooling | Update shell script for v16 | 3.3 | measure-chunk-stats.sh (P0) | — |
|
|
|
-| SassTildeFixup | Styles | Remove node_modules tilde prefix | 4.1, 4.2, 4.3, 4.4 | toastr.scss (P0) | — |
|
|
|
-| WebpackConfigPreservation | Build | Verify webpack config unchanged | 2.1–2.5 | next.config.ts (P0) | — |
|
|
|
-| NextConfigValidation | Build | Verify v16 config compatibility | 5.1–5.5 | next.config.ts (P0) | — |
|
|
|
-| TsNodeHookPreservation | Server | Verify ts-node hook survives v16 | 6.1–6.3 | crowi/index.ts (P0) | — |
|
|
|
-| MetricsValidation | Tooling | Measure and compare module counts | 2.6, 7.7 | ChunkModuleStatsPlugin (P0) | — |
|
|
|
-| RegressionValidation | QA | Full quality check suite | 1.5, 7.1–7.6 | turbo CLI (P0) | — |
|
|
|
-
|
|
|
-### Build Layer
|
|
|
-
|
|
|
-#### PackageUpgrade
|
|
|
-
|
|
|
-| Field | Detail |
|
|
|
-|-------|--------|
|
|
|
-| Intent | Bump `next` and `@next/bundle-analyzer` to v16 in `apps/app/package.json` |
|
|
|
-| Requirements | 1.1, 1.4 |
|
|
|
-
|
|
|
-**Responsibilities & Constraints**
|
|
|
-- Update `next` from `^15.0.0` to `^16.0.0`
|
|
|
-- Update `@next/bundle-analyzer` from `^15.0.0` to `^16.0.0`
|
|
|
-- Verify `@types/react` and `@types/react-dom` remain compatible (React 18 types work with v16)
|
|
|
-- Run `pnpm install` to resolve dependency tree
|
|
|
-
|
|
|
-**Dependencies**
|
|
|
-- External: next@^16.0.0 — core framework (P0)
|
|
|
-- External: @next/bundle-analyzer@^16.0.0 — analysis tool (P1)
|
|
|
-
|
|
|
-**Implementation Notes**
|
|
|
-- React stays at ^18.2.0 — v16 peer dependency range includes `^18.2.0`
|
|
|
-- `babel-plugin-superjson-next` stays as-is — not used by custom loader approach
|
|
|
-- The `next-i18next` package compatibility should be verified against Next.js 16
|
|
|
-
|
|
|
-#### BuildScriptUpdate
|
|
|
-
|
|
|
-| Field | Detail |
|
|
|
-|-------|--------|
|
|
|
-| Intent | Add `--webpack` flag to client build and dev scripts |
|
|
|
-| Requirements | 1.2, 1.3, 3.1, 3.2, 3.4 |
|
|
|
-
|
|
|
-**Responsibilities & Constraints**
|
|
|
-- Update `build:client` script: `next build` → `next build --webpack`
|
|
|
-- The `dev` script runs the Express server (not `next dev` directly), so `--webpack` cannot be added to the npm script
|
|
|
-- The Express server calls `next({ dev })` programmatically — webpack usage is determined by the absence of Turbopack config, not a CLI flag
|
|
|
-- Verify root-level commands: `pnpm run app:build`, `turbo run build`
|
|
|
-
|
|
|
-**Implementation Notes**
|
|
|
-- Integration: The `next({ dev })` API may need investigation to determine if v16 defaults to Turbopack when called programmatically. If so, a config option may be needed.
|
|
|
-- Risk: Programmatic `next()` call may behave differently from CLI `next dev --webpack`. Must test thoroughly.
|
|
|
-
|
|
|
-#### MeasurementToolUpdate
|
|
|
-
|
|
|
-| Field | Detail |
|
|
|
-|-------|--------|
|
|
|
-| Intent | Update `bin/measure-chunk-stats.sh` for v16 directory changes and webpack flag |
|
|
|
-| Requirements | 3.3 |
|
|
|
-
|
|
|
-**Responsibilities & Constraints**
|
|
|
-- Update line 27: `rm -rf .next` → `rm -rf .next/dev` (or both `.next` and `.next/dev`)
|
|
|
-- Update line 31: `npx next dev` → `npx next dev --webpack`
|
|
|
-- Verify log output path still works with `.next/dev` directory
|
|
|
-
|
|
|
-**Dependencies**
|
|
|
-- Inbound: ChunkModuleStatsPlugin — provides log output (P0)
|
|
|
-
|
|
|
-### Styles Layer
|
|
|
-
|
|
|
-#### SassTildeFixup
|
|
|
-
|
|
|
-| Field | Detail |
|
|
|
-|-------|--------|
|
|
|
-| Intent | Remove Sass tilde prefix from node_modules imports |
|
|
|
-| Requirements | 4.1, 4.2, 4.3, 4.4 |
|
|
|
-
|
|
|
-**Responsibilities & Constraints**
|
|
|
-- Change `@import '~react-toastify/scss/main'` → `@import 'react-toastify/scss/main'` in `src/styles/molecules/toastr.scss`
|
|
|
-- The `~/...` pattern (path alias) used throughout other SCSS files is NOT the node_modules tilde prefix and requires no changes
|
|
|
-- Verify style compilation produces identical output
|
|
|
-
|
|
|
-**Implementation Notes**
|
|
|
-- Scope is minimal: only 1 file affected
|
|
|
-- webpack Sass resolution already supports non-tilde imports for node_modules
|
|
|
-
|
|
|
-### Server Layer
|
|
|
-
|
|
|
-#### TsNodeHookPreservation
|
|
|
-
|
|
|
-| Field | Detail |
|
|
|
-|-------|--------|
|
|
|
-| Intent | Verify the ts-node `.ts` extension hook survives Next.js v16 initialization |
|
|
|
-| Requirements | 6.1, 6.2, 6.3 |
|
|
|
-
|
|
|
-**Responsibilities & Constraints**
|
|
|
-- Existing defensive pattern in `src/server/crowi/index.ts` (lines 557-566) saves and restores `require.extensions['.ts']`
|
|
|
-- v16 may change its config transpiler behavior — the save/restore pattern handles this generically
|
|
|
-- Must verify by starting dev server and confirming TypeScript files load correctly
|
|
|
-
|
|
|
-**Dependencies**
|
|
|
-- External: ts-node — TypeScript execution (P0)
|
|
|
-- Inbound: Next.js config transpiler — may deregister hooks (P0)
|
|
|
-
|
|
|
-**Implementation Notes**
|
|
|
-- The comment already references "Next.js 15's next.config.ts transpiler" — update comment to note v16 if behavior changes
|
|
|
-- If v16 no longer deregisters the hook, the defensive code becomes a no-op (safe to keep)
|
|
|
-
|
|
|
-## Error Handling
|
|
|
-
|
|
|
-### Error Strategy
|
|
|
-
|
|
|
-| Error Type | Scenario | Response |
|
|
|
-|------------|----------|----------|
|
|
|
-| Build failure | `next build` fails without `--webpack` | Hard error from Next.js — add `--webpack` flag |
|
|
|
-| Type errors | New v16 types break existing code | Fix type annotations, check `@types/react` compatibility |
|
|
|
-| Module count regression | Initial modules exceed 940 (895 + 5%) | Investigate webpack config changes, check null-loader rules |
|
|
|
-| ts-node hook loss | Next.js v16 removes `.ts` extension hook | Existing save/restore pattern handles this |
|
|
|
-| Dev server failure | `.next/dev` directory causes issues | Fall back to `isolatedDevBuild: false` |
|
|
|
-
|
|
|
-## Testing Strategy
|
|
|
-
|
|
|
-### Unit Tests
|
|
|
-- Run existing superjson-ssr.spec.ts (10 tests) — verifies serialization round-trip
|
|
|
-- Run existing mongo-id.spec.ts (8 tests) — verifies client utility
|
|
|
-- Run existing locale-utils.spec.ts (18 tests) — verifies date-fns imports
|
|
|
-- Run existing HotkeysManager.spec.tsx (3 tests) — verifies tinykeys integration
|
|
|
-- Run existing PageContentRenderer.spec.tsx (3 tests) — verifies dynamic import
|
|
|
-
|
|
|
-### Integration Tests
|
|
|
-- Full test suite: `turbo run test --filter @growi/app` (1,375+ tests, 127+ files)
|
|
|
-- TypeScript check: `turbo run lint:typecheck --filter @growi/app`
|
|
|
-- Biome lint: `turbo run lint:biome --filter @growi/app`
|
|
|
-
|
|
|
-### Build Tests
|
|
|
-- Production build: `turbo run build --filter @growi/app`
|
|
|
-- Bundle analysis: `ANALYZE=1 next build --webpack` (verify analyzer works)
|
|
|
-
|
|
|
-### Manual Verification
|
|
|
-- Start dev server, compile `[[...path]]`, record ChunkModuleStats output
|
|
|
-- Compare initial/async-only/total module counts with baseline (895/4,775/5,670)
|
|
|
-- Verify page renders correctly in browser
|
|
|
-
|
|
|
-## Performance & Scalability
|
|
|
-
|
|
|
-### Target Metrics
|
|
|
-
|
|
|
-| Metric | Baseline (v15) | Target (v16) | Tolerance |
|
|
|
-|--------|---------------|--------------|-----------|
|
|
|
-| Initial modules | 895 | 895 | ±5% (850–940) |
|
|
|
-| Async-only modules | 4,775 | 4,775 | ±10% |
|
|
|
-| Total modules | 5,670 | 5,670 | ±10% |
|
|
|
-| Compilation time | ~30s | ~30s | ±20% |
|
|
|
-
|
|
|
-### Measurement Approach
|
|
|
-- Use `bin/measure-chunk-stats.sh` (after v16 updates) for standardized measurement
|
|
|
-- Record before/after in `analysis-ledger.md` or commit message
|