Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from Next.js Pages Router to App Router #255

Merged
merged 36 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cc425f0
Add next-intl
sawyerh Nov 30, 2023
7f6cd30
Remove i18next
sawyerh Nov 30, 2023
d391826
Automated changes due to app router being enabled
sawyerh Nov 30, 2023
42c8b02
Migrate pages and layout to app directory
sawyerh Nov 30, 2023
ccecc89
Use next-intl in components
sawyerh Nov 30, 2023
825292a
Remove unused ts-jest file
sawyerh Nov 30, 2023
4c9de34
Fix i18n type safety
sawyerh Dec 2, 2023
1fadabd
Migrate tests
sawyerh Dec 2, 2023
d6de227
Docs progress
sawyerh Dec 4, 2023
e4ac258
Merge remote-tracking branch 'origin/main' into sawyerh/66-app-router…
sawyerh Dec 6, 2023
fff60ce
Setup middleware
sawyerh Dec 6, 2023
b82e14d
Fix layout rendering in Storybook
sawyerh Dec 6, 2023
022740f
Remove dupe files
sawyerh Dec 6, 2023
447a4c5
Fix story import
sawyerh Dec 6, 2023
739900c
Reduce diff size
sawyerh Dec 6, 2023
9e20c82
Restructure i18n directory to support client components
sawyerh Dec 6, 2023
d79bb65
Revert todo
sawyerh Dec 6, 2023
6af1c77
Rename to getMessagesWithFallbacks
sawyerh Dec 6, 2023
79ca32b
Use dynamic import for getting messages
sawyerh Dec 7, 2023
c611f43
Merge branch 'main' into sawyerh/66-app-router-migration
sawyerh Dec 7, 2023
6e759ea
Fix config path
sawyerh Dec 7, 2023
2672191
Cleanup
sawyerh Dec 8, 2023
6fd126a
Migrate API route
sawyerh Dec 8, 2023
b4c4c21
Update docs
sawyerh Dec 8, 2023
02e2d93
Update doc
sawyerh Dec 8, 2023
2acda08
Reduce diff
sawyerh Dec 8, 2023
43e9695
Fix sticky footer
sawyerh Dec 8, 2023
02b0546
Use timeZone
sawyerh Dec 8, 2023
3bebef7
Restore transpilePackages
sawyerh Dec 8, 2023
1bbc39e
Restore comment
sawyerh Dec 8, 2023
c2a1c3f
Merge remote-tracking branch 'origin/main' into sawyerh/66-app-router…
sawyerh Dec 13, 2023
6c42256
Missed merge changes
sawyerh Dec 13, 2023
06cd838
Merge remote-tracking branch 'origin/main' into sawyerh/66-app-router…
sawyerh Dec 13, 2023
bd0c2de
Seperate controller and view logic, fix tests and story
sawyerh Dec 13, 2023
2d73ff6
Demonstate test of async server component
sawyerh Dec 13, 2023
ac211f2
Fix named export limitation of page files
sawyerh Dec 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 25 additions & 10 deletions app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
```
├── .storybook # Storybook configuration
├── public # Static assets
│ └── locales # Internationalized content
├── src # Source code
│ ├── app # Routes, layouts, and loading screens
│ │ ├── api # Custom request handlers
│ │ ├── layout.tsx # Root layout, wraps every page
│ │ └── page.tsx # Homepage
│ ├── components # Reusable UI components
│ ├── i18n # Internationalization
│ │ ├── config.ts # Supported locales, timezone, and formatters
│ │ └── messages # Translated strings
│ ├── pages # Page routes and data fetching
│   │ ├── api # API routes (optional)
│   │ └── _app.tsx # Global entry point
│ ├── styles # Sass & design system settings
│ └── types # TypeScript type declarations
├── stories # Storybook pages
Expand All @@ -27,9 +27,7 @@

## 💻 Development

[Next.js](https://nextjs.org/docs) provides the React framework for building the web application. Pages are defined in the `pages/` directory. Pages are automatically routed based on the file name. For example, `pages/index.tsx` is the home page.

Files in the `pages/api` are treated as [API routes](https://nextjs.org/docs/api-routes/introduction). An example can be accessed at [localhost:3000/api/hello](http://localhost:3000/api/hello) when running locally.
[Next.js](https://nextjs.org/docs) provides the React framework for building the web application. Routes are defined in the `app/` directory. Pages are automatically routed based on the directory name. For example, `app/[locale]/about/page.tsx` would render at `/about` (for English) or `/es-US/about` (for Spanish).

[**Learn more about developing Next.js applications** ↗️](https://nextjs.org/docs)

Expand Down Expand Up @@ -106,9 +104,7 @@ From the `app/` directory:

## 🐛 Testing

[Jest](https://jestjs.io/docs/getting-started) is used as the test runner and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro) provides React testing utilities.

Tests are manged as `.test.ts` (or `.tsx`) files in the the `tests/` directory.
[Jest](https://jestjs.io/docs/getting-started) is used as the test runner. Tests are manged as `.test.ts` (or `.tsx`) files in the the `tests/` directory.

To run tests:

Expand All @@ -122,6 +118,25 @@ A subset of tests can be ran by passing a pattern to the script. For example, to
npm run test-watch -- pages
```

### Testing React components

[React Testing Library (RTL)](https://testing-library.com/docs/react-testing-library/intro) provides the utilities for rendering and querying, and [`jest-axe`](https://www.npmjs.com/package/jest-axe) is used for accessibility testing. Refer to their docs to learn more about their APIs, or view an existing test for examples.

`@testing-library/react` methods should be imported from `tests/react-utils` in order for internationalization to work within your tests:

```diff
- import { render, screen } from '@testing-library/react';
+ import { render, screen } from 'tests/react-utils';

it("renders submit button", () => {
render(<Page />)

expect(
screen.getByRole("button", { name: "Submit" })
).toBeInTheDocument()
})
```

## 🤖 Type checking, linting, and formatting

- [TypeScript](https://www.typescriptlang.org/) is used for type checking.
Expand Down
5 changes: 1 addition & 4 deletions app/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ const createJestConfig = nextJest({
// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const customJestConfig = {
setupFilesAfterEnv: [
"<rootDir>/tests/jest.setup.ts",
"<rootDir>/tests/jest-i18n.ts",
],
setupFilesAfterEnv: ["<rootDir>/tests/jest.setup.ts"],
testEnvironment: "jsdom",
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ["node_modules", "<rootDir>/"],
Expand Down
1 change: 1 addition & 0 deletions app/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Automatically added by Next.js when using App Router


// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
6 changes: 1 addition & 5 deletions app/next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-check
const withNextIntl = require("next-intl/plugin")("./src/i18n/config.ts");
const withNextIntl = require("next-intl/plugin")("./src/i18n/server.ts");
const sassOptions = require("./scripts/sassOptions");

/**
Expand All @@ -15,10 +15,6 @@ const appSassOptions = sassOptions(basePath);
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath,
i18n: {
locales: ["en-US", "es-US"],
defaultLocale: "en-US",
},
reactStrictMode: true,
// Output only the necessary files for a deployment, excluding irrelevant node_modules
// https://nextjs.org/docs/app/api-reference/next-config-js/output
Expand Down
104 changes: 49 additions & 55 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
"ts:check": "tsc --noEmit"
},
"dependencies": {
"@trussworks/react-uswds": "^6.0.0",
"@trussworks/react-uswds": "^6.1.0",
"@uswds/uswds": "3.7.0",
"lodash": "^4.17.21",
"next": "^14.0.0",
"next-intl": "^3.2.0",
"next": "^14.0.3",
"next-intl": "^3.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand All @@ -40,8 +40,8 @@
"@types/jest-axe": "^3.5.5",
"@types/lodash": "^4.14.202",
"@types/node": "^20.0.0",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react": "^18.2.42",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.36.0",
Expand Down
3 changes: 3 additions & 0 deletions app/src/app/[locale]/health/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the /health/ page an aspect of next.js that's built in to handle some particular functionality? I couldn't find it looking in the docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is it's required by the infra template in order to know if the container is healthy, otherwise it spins up a new ECS task.

return <>healthy</>;
}
32 changes: 32 additions & 0 deletions app/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Root layout component, wraps all pages.
* @see https://nextjs.org/docs/app/api-reference/file-conventions/layout
*/
import { Metadata } from "next";

import Layout from "src/components/Layout";

import "src/styles/styles.scss";

export const metadata: Metadata = {
icons: [`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/img/logo.svg`],
};

interface LayoutProps {
children: React.ReactNode;
params: {
locale: string;
};
}

export default function RootLayout({ children, params }: LayoutProps) {
return (
<html lang={params.locale}>
<body>
{/* Separate layout component for the inner-body UI elements since Storybook
and tests trip over the fact that this file renders an <html> tag */}
<Layout locale={params.locale}>{children}</Layout>
</body>
</html>
);
}