Skip to content

Commit

Permalink
Update from template repo: PRs 15, 24, 26 (#31)
Browse files Browse the repository at this point in the history
* Copy over application-template-nextjs at ca2cc15.

Install and configure storybook, sass, and USWDS 3.0 [#15](navapbc/template-application-nextjs#15)

- Install and configure storybook
- Create the first story
- Install and configure [USWDS 3.0](https://designsystem.digital.gov/) as the design system
- Modify `Dockerfile` and `docker-compose.yml` to support USWDS and storybook
- Gitignore storybook, uswds assets, and compiled css
- Prettier ignore uswds assets
- Use postinstall hook to copy uswds static assets
- Stop using CSS modules
- Update some package dependencies
- Switch Docker base image to use alpine for increased speed

* Copy over application-template-nextjs at cd06ba6.

Setup i18n for next.js, jest, and storybook [#24](navapbc/template-application-nextjs#24)

- Install and configure [next-i18next](https://github.com/i18next/next-i18next) for Next.js internationalization
- Move next.js i18n config out of `next.config.js` and into `next-i18next.config.js`
- Modify `pages/_app.tsx` and `pages/index.tsx` to support i18n
- Move jest i18n config into `/tests/jest-i18n.ts`
- Install and configure [storybook-react-i18next](https://storybook.js.org/addons/storybook-react-i18next) for storybook internationalization
- Add support for `<em>` tags in react-i18next in both next.js and storybook.

Extras:
- Remove `space-before-function-paren` eslint rule
- Update eslint to follow prettier's rules
- Rename `test` dir to `tests` (plural)

* Copy over application-template-nextjs at cfe7c3d.

Adds a src dir, layout component, alphabetizes imports [#26](navapbc/template-application-nextjs#26)

- adds `src/` directory for project's webpack compilable JS and JSON files (this update is supported out of the box by [NextJS](https://nextjs.org/docs/advanced-features/src-directory) and pfml also uses this folder structure)
   - moves `api/`, `pages/` and `messages/` directories to `src/`
   - creates `components` directory and adds template `Layout` component

Extras:
- sets up prettier alphabetize imports
- adds storybook-static to prettier ignore
- sets $theme-show-compile-warnings to true for uswds

* Copy over application-template-nextjs at 0a349fa.

Enable dependabot version updates and codeql security scanning as CI jobs [#29](navapbc/template-application-nextjs#29)

- Enable and configure [dependabot version updates](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates)
- Enable and configure [codeql security scanning](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning)

Note: These features were already enabled in this repo, so this commit
is just bringing in stylistic updates to make the two repos identical.

* Copy over application-template-nextjs at f59d2ac.

 Add layout styles missing from PR #26.
[#37](navapbc/template-application-nextjs#37)

* Also addresses:
- #29 
- #26 
- #25 
- #12 
- #11
  • Loading branch information
rocketnova committed Jul 19, 2022
1 parent 9da4fae commit b322ede
Show file tree
Hide file tree
Showing 41 changed files with 10,688 additions and 1,323 deletions.
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
version: 2
updates:
# Maintain dependencies for yarn (uses `npm`)
- package-ecosystem: "npm"
directory: "/app"
- package-ecosystem: "npm"
directory: "/app"
schedule:
interval: "daily"
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ jobs:
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality


# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
Expand All @@ -61,7 +61,7 @@ jobs:
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

# If the Autobuild fails above, remove it and uncomment the following three lines.
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

# - run: |
Expand Down
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,33 @@ This template includes setup for:

## How to Run

The Next.js application is dockerized. Take a look at `./app/Dockerfile` to see how it works.
### Without Docker

You can run the Next.js app without docker as follows:

1. `yarn install`
2. `yarn dev`
3. Navigate to `localhost:3000` in your browser to view the application

A very simple `docker-compose.yml` has been included to support local development and deployment. Take a look at `./docker-compose.yml` for more information.
You can run storybook without docker by running:

How to run:
1. `yarn storybook`
2. Navigate to `localhost:6006` in your browser to view storybook

### With Docker

The Next.js application is dockerized. Take a look at `./app/Dockerfile` to see how it works.

A `docker-compose.yml` has been included to support local development and deployment. Take a look at `./docker-compose.yml` for more information.

1. In your terminal, `cd` to this repo.
2. Make sure you have [Docker Desktop](https://www.docker.com/products/docker-desktop/) installed & running.
3. Run `docker-compose up -d --build` to build the image and start the container.
4. Navigate to `localhost:3000` in your browser to view the application.
5. Run `docker-compose down` when you are done to delete the container.
4. Navigate to `localhost:3000` in your browser to view the application. Note that it takes a few minutes for the initial sass compiling to complete and load.
5. Run `docker-compose exec nextjs yarn storybook` to build and run storybook. Note that the initial sass compiling for storybook also takes a few minutes to complete and load
5. Navigate to `localhost:6006` in your browser to view storybook.
6. Run `docker-compose down` when you are done to delete the container.

To support local development, the `docker-compose.yml` runs the `nextjs` container in development mode (i.e. `yarn dev`) instead of production mode (i.e. `yarn start`). This allows Next.js to do things like hot reload.

The docker-compose file bind mounts `app` on the host machine to `/srv` in the guest machine. However, to ensure that the container uses the correct packages in `node_modules`, we use a named docker volume for the `node_modules` dir. The named volume will take precedence over the bind mount, so that the `node_modules` dir in the guest machine will not be overwritten with the host machine's `node_modules` dir. This also means that if you run `yarn add <package>` on the host machine in development (which will update `yarn.lock`), you'll also need to run `docker-compose exec nextjs yarn install --frozen-lockfile` to update `node_modules` in the guest machine.
5 changes: 5 additions & 0 deletions app/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# The docker container should install its own packages.
node_modules

# The docker container should ignore next builds.
.next
9 changes: 4 additions & 5 deletions app/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"prettier",
"next",
"nava"
"nava",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
Expand All @@ -16,9 +16,8 @@
},
"plugins": ["@typescript-eslint", "jest"],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "error",
"react/react-in-jsx-scope": "off",
"space-before-function-paren": ["error", "never"]
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "error"
}
}
9 changes: 9 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ yarn-error.log*

# typescript
*.tsbuildinfo

# storybook
/storybook-static

# compiled css
/public/css

# uswds assets
/public/uswds
4 changes: 4 additions & 0 deletions app/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Ignoring generated files
.next/
node_modules/
storybook-static/

# Ignore USWDS static assets
public/uswds
3 changes: 3 additions & 0 deletions app/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"importOrder": ["^components/(.*)$", "^[./]"],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"semi": false,
"singleQuote": true
}
30 changes: 30 additions & 0 deletions app/.storybook/i18next.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Configure i18next for storybook addon storybook-react-i18next
// See https://storybook.js.org/addons/storybook-react-i18next
import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import Backend from 'i18next-http-backend'
import { initReactI18next } from 'react-i18next'

const ns = ['common']
const supportedLngs = ['en', 'es']
const resources = ns.reduce((acc, n) => {
supportedLngs.forEach((lng) => {
if (!acc[lng]) acc[lng] = {}
acc[lng] = {
...acc[lng],
[n]: require(`../public/locales/${lng}/${n}.json`),
}
})
return acc
}, {})

i18n.use(initReactI18next).use(LanguageDetector).use(Backend).init({
lng: 'en',
fallbackLng: 'en',
defaultNS: 'common',
ns,
supportedLngs,
resources,
})

export default i18n
53 changes: 53 additions & 0 deletions app/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const nextConfig = require('../next.config')

module.exports = {
stories: ['../stories/**/*.stories.@(mdx|js|jsx|ts|tsx)'],
addons: ['@storybook/addon-essentials', 'storybook-react-i18next'],
framework: '@storybook/react',
core: {
// Use webpack5 instead of webpack4.
builder: 'webpack5',
disableTelemetry: true,
},
// Tell storybook where to find USWDS static assets
staticDirs: ['../public'],

// Configure Storybook's final Webpack configuration in order to re-use the Next.js config/dependencies.
webpackFinal: (config) => {
config.module?.rules?.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
/**
* Next.js sets this automatically for us, but we need to manually set it here for Storybook.
* The main thing this enables is autoprefixer, so any experimental CSS properties work.
*/
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['postcss-preset-env'],
},
},
},
{
loader: 'sass-loader',
options: {
sassOptions: nextConfig.sassOptions,
},
},
],
exclude: /node_modules/,
})

// Required for i18next.
config.resolve.fallback = {
fs: false,
path: false,
os: false,
}

return config
},
}
21 changes: 21 additions & 0 deletions app/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Apply global styling to our stories
import '../styles/styles.scss'
// Import i18next config.
import i18n from './i18next.js'

export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
// Configure i18next and locale/dropdown options.
i18n,
locale: 'en',
locales: {
en: 'English',
es: 'Español',
},
}
21 changes: 12 additions & 9 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# Use the Active LTS version of Node.
# See https://nodejs.org/en/about/releases/
FROM node:16
FROM node:16-alpine
# Keep container packages up-to-date.
RUN apt update \
&& apt upgrade -y
# Copy all the application files to a working directory.
COPY . /srv
# -U runs both apk update and apk upgrade.
RUN apk -U upgrade
# Copy just the package data to the working directory.
COPY yarn.lock /srv
COPY package.json /srv
WORKDIR /srv
# Install application dependencies and build the applicatian.
# See package.json for yarn commands.
RUN yarn install --frozen-lockfile \
&& yarn build
# Install application dependencies.
RUN yarn install --frozen-lockfile
# Copy all the remaining application files (ignoring files in .dockerignore) to the working directory.
COPY . /srv
# Build the application.
RUN yarn build
# Run the application.
CMD yarn start
41 changes: 38 additions & 3 deletions app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ Note: make sure TypeScript and Javascript Language Features are enabled in VS Co
- Disallows usage of `any` type. The usage of `any` defeats the purpose of typescript. Consider using `unknown` type instead instead.
- "react/resct-in-jsx-scope": "off"
- suppress errors for missing 'import React' in files because NextJS does this for us.
- "space-before-function-paren": ["error", "never"]
- suppresses errors for lack of space before function parenthesis to allow for `function()`

### Tsconfig additions to auto-generated file

Expand Down Expand Up @@ -92,7 +90,44 @@ Note: make sure TypeScript and Javascript Language Features are enabled in VS Co
- `eslint`: This [module](https://www.npmjs.com/package/eslint) provides linting. Configuration implemented in .eslintrc.
- `eslint-config-nava`: This [module](https://github.com/navapbc/eslint-config-nava) contains nava's preferred configurations for eslint. It is implemented in .eslintrc > extensions > nava.
- `eslint-config-next`: This [module](https://nextjs.org/docs/basic-features/eslint) is automatically installed by nextJS, it includes out of the eslint configuration. Implemented in .eslintrc.json > extends > next.
- `eslint-config-prettier`: This [module](https://github.com/prettier/eslint-config-prettier) turns off eslint rules that may conflict with prettier. Implemented in .eslintrc > extends > prettier.
- `eslint-config-prettier`: This [module](https://github.com/prettier/eslint-config-prettier) turns off eslint rules that may conflict with prettier. Implemented in .eslintrc > extends > prettier. This module requires that we list `prettier` as the last element of the `extends` object in `eslintrc.json`.
- `jest-environment-jsdom`: This [module](https://www.npmjs.com/package/jest-environment-jsdom) simulates the DOM for testing. Implemented in jest.config.js > testEnvironment.
- `prettier`: This [module](https://prettier.io/) is used for code formatting. Implemented in .prettierrc.json.
- `ts-jest`: This [module](https://www.npmjs.com/package/ts-jest) lets ys yse hest to test our project written in TypeScript. Implemented in jest.config.js > preset > ts-jest

## Design System

We are using the [USWDS 3.0](https://designsystem.digital.gov) design system.

We did not follow their [install directions](https://designsystem.digital.gov/documentation/getting-started/developers), which require using gulp as a task runner. Instead, we configured `next.config.js` such that we could leverage Next.js's built-in sass compiling and we configured `.storybook/main.js` such that we could leverage Storybook's built-in sass compiling and re-use the same Next.js configuration.

Compiling the USWDS sass is slow, so the initial build step and subsequent sass re-compiles are slow, but after the design system is set up, we shouldn't need to be regularly re-compiling sass.

Copying the USWDS static assets into the project is handled by a [yarn postinstall](https://classic.yarnpkg.com/lang/en/docs/package-json/#toc-scripts) script in `package.json`.

## Internationalization (i18n)

### Next.js i18n

We are using [next-i18next](https://github.com/i18next/next-i18next) for Next.js internationalization. It provides a Next.js wrapper around [i18next](https://www.i18next.com/) and [react-i18next](https://github.com/i18next/react-i18next). Configuration is located in `next-i18next.config.js`. To add a language:

1. Edit `next-i18next.config.js` and add the language to `locales`
2. Add a language folder: `mkdir -p public/locales/<lang>`
3. Add a language file: `touch public/locales/<lang>/common.json` and add the translated content

Note that the json structure should be the same for each translation file. However, non-default languages can omit keys, in which case the translation content for the default language will be used.

### Jest i18n

Internationalization is setup for tests in `jest-i18next.ts`. To add a language:

1. Edit `jest-i18next.ts`, import the language file, and edit the `resources` object.

### Storybook i18n

For storybook, we are using [storybook-react-i18next](https://storybook.js.org/addons/storybook-react-i18next), which adds a globe icon to the add-ons bar for selecting the desired language. To add a language:

1. Edit `.storybook/i18next.js` and add the language to `supportedLngs`. This tells storybook-react-i18next what language files to look for.
2. Edit `.storybook/preview.js` and add the language to `locales`. This tells storybook-react-i18next the options that the globe icon dropdown should include.

Note that for storybook to support i18next, we need to to set a few webpack settings to false. See `.storybook/main.js`.
7 changes: 5 additions & 2 deletions app/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ module.exports = {
'\\.(css|scss)$': '<rootDir>/__mocks__/styleMock.js', // sets up routing to mocks style sheet
'^@pages(.*)$': '<rootDir>/pages$1', //allows module imports of page components
},
setupFilesAfterEnv: ['<rootDir>/test/jest.setup.js'],
setupFilesAfterEnv: [
'<rootDir>/tests/jest.setup.js',
'<rootDir>/tests/jest-i18n.ts',
],
transform: {
'^.+\\.tsx?$': 'ts-jest',
}, //transfrom typescript files to common js for jest compiler
Expand All @@ -17,7 +20,7 @@ module.exports = {
'^.+\\.module\\.(css|sass|scss)$',
],
testPathIgnorePatterns: ['<rootDir>/node_modules/'],
testRegex: '(/test/.*(test|spec))\\.[jt]sx?$',
testRegex: '(/tests/.*(test|spec))\\.[jt]sx?$',
globals: {
'ts-jest': {
tsconfig: 'tsconfig.ts-jest.json',
Expand Down
11 changes: 11 additions & 0 deletions app/next-i18next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'es'],
react: {
// Add support for <em>.
// See https://react.i18next.com/latest/trans-component#using-for-less-than-br-greater-than-and-other-simple-html-elements-in-translations-v-10-4-0
transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'p', 'em'],
},
},
}
17 changes: 9 additions & 8 deletions app/next.config.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
/** @type {import('next').NextConfig} */

const { i18n } = require('./next-i18next.config')

const nextConfig = {
i18n: {
// TODO: implement i18n internationalization-- look into nextJS subpath routing
locales: ['en-US', 'es-ES'],
defaultLocale: 'en-US',
localeSubpaths: {
es: 'es',
},
},
i18n,
reactStrictMode: true,
sassOptions: {
includePaths: [
'./node_modules/@uswds',
'./node_modules/@uswds/uswds/packages',
],
},
}

module.exports = nextConfig
Loading

0 comments on commit b322ede

Please sign in to comment.