Skip to content

Commit

Permalink
integrate Next.js
Browse files Browse the repository at this point in the history
  • Loading branch information
joernb committed Aug 26, 2022
1 parent fe4ec52 commit 0ccd0b2
Show file tree
Hide file tree
Showing 57 changed files with 12,739 additions and 4,613 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@

# Allows environment-specific monorepo behavior (e.g. only execute commands for certain packages)
LERNA_FLAGS=""

# Publicly accessible URL
PUBLIC_URL=https://example.com
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ This readme gives developers an overview over the system architecture and the de
```mermaid
graph LR
User["User"]
subgraph " "
NextApp("Next App")
end
User -.-> NextApp
```

## infrastructure/
Expand All @@ -34,10 +41,15 @@ Infrastructure contains the setup for cloud-based environments and services and

Applications are executables that are deployed to and operated on infrastructure. They use internal and external libraries as code dependencies. Applications are configured through environment variables that are passed in at runtime or compiled into the application at compile time.

- **[Next App](apps/next-app/README.md)**: Next.js web app with integrated REST API.

## libs/

Libraries are used as code dependencies by applications or other libraries. They typically implement specific functionality (e.g. utility functions, user interface components) or the network interaction between applications on the client side as a "client library" or the server side as an "api library". Libraries can be published to make them available for external applications outside the Monorepo. Libraries can define their own build process or just provide source files that are compiled by the build process of the consuming application. Libraries should not read environment variables but receive their configuration from the application through some kind of initialization.

- **[React API Client](libs/react-api-client/README.md)**: Client library that provides React Hooks to access the REST API.
- **[Express API](libs/express-api/README.md)**: Server library that implements a REST API as an Express middleware.

# 🚀 Development

## Principles
Expand Down Expand Up @@ -73,6 +85,7 @@ How to develop and debug changes locally:
```sh
npm run dev
```
- Open [http://localhost:3000](http://localhost:3000) in browser

## Build

Expand Down
3 changes: 3 additions & 0 deletions apps/next-app/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "prettier"]
}
29 changes: 29 additions & 0 deletions apps/next-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[❮ Overview](../../README.md)

<div align="center">
<h1>
Next App
</h1>
</div>

Next.js web app with integrated REST API.

# 🧬 Structure

## Code

- `📁 pages/`: Contains [pages](https://nextjs.org/docs/basic-features/pages).
- `📄 _app.tsx`: The root component for the whole [application](https://nextjs.org/docs/advanced-features/custom-app). It integrates [context providers](https://reactjs.org/docs/context.html#contextprovider).
- `📄 _app.css`: Application wide [CSS styling](https://nextjs.org/docs/basic-features/built-in-css-support).
- `📄 _document.tsx`: Customizations of the [HTML document](https://nextjs.org/docs/advanced-features/custom-document) that contains the app.
- `📁 api/`: Contains [API routes](https://nextjs.org/docs/api-routes/introduction).
- `📄 [...index].ts`: A catch all API router handler that forwards all request to the Express middleware from [`express-api`](libs/express-api/).
- `📁 components/`: Components used by pages. Components use [Component-level CSS](https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css) for styling.
- `📁 public/`: Contains [assets](https://nextjs.org/docs/basic-features/static-file-serving) (images, fonts, ...)
- `📄 robots.txt`: Influences [search engine crawler behavior](https://developers.google.com/search/docs/advanced/robots/intro).
- `📄 next.config.js`: Next.js build [config](https://nextjs.org/docs/api-reference/next.config.js/introduction). Adjusted to include source files from `libs/` into the build process.

## Interactions

- `$PUBLIC_URL/`: Serves the web application.
- `$PUBLIC_URL/api/`: Provides the REST API used by the web application.
11 changes: 11 additions & 0 deletions apps/next-app/components/footer.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.container {
flex: 0 0 auto;
display: flex;
justify-content: center;
align-items: center;
font-size: small;
}

.container > * {
margin: 1rem;
}
12 changes: 12 additions & 0 deletions apps/next-app/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styles from "./footer.module.css";

interface Props {}

/**
* Contains horizontal bar at the bottom of each page
*/
const Footer = ({}: Props) => {
return <footer className={styles.container}></footer>;
};

export default Footer;
21 changes: 21 additions & 0 deletions apps/next-app/components/header.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.container {
flex: 0 0 auto;
color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #1976d2;
box-shadow: 0px 1px 3px #000;
z-index: 1;
}

.container > nav {
display: flex;
flex-direction: row;
align-items: center;
}

.container > nav > * {
margin: 1.2rem;
cursor: pointer;
}
30 changes: 30 additions & 0 deletions apps/next-app/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Image from "next/image";
import Link from "next/link";
import logoImage from "../public/logo.png";
import styles from "./header.module.css";

interface Props {}

/**
* Contains horizontal bar at the top
*/
const Header = ({}: Props) => {
return (
<header className={styles.container}>
<nav>
<Link href="/">
<a>
<Image alt="" src={logoImage} width={32} height={32} />
</a>
</Link>
<Link href="/items">
<a>Items</a>
</Link>
</nav>
<nav></nav>
<nav></nav>
</header>
);
};

export default Header;
13 changes: 13 additions & 0 deletions apps/next-app/components/layout.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.container {
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}

.main {
flex: 1 1 0;
overflow-y: auto;
display: flex;
flex-direction: column;
}
28 changes: 28 additions & 0 deletions apps/next-app/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Head from "next/head";
import Footer from "./footer";
import Header from "./header";
import styles from "./layout.module.css";

interface Props {
children: React.ReactNode;
}

/**
* Encapsulates layout decisions for pages.
*/
const Layout = ({ children }: Props) => {
return (
<div className={styles.container}>
<Head>
<link rel="icon" href="/logo.png" />
</Head>
<Header />
<main className={styles.main}>
{children}
<Footer />
</main>
</div>
);
};

export default Layout;
10 changes: 10 additions & 0 deletions apps/next-app/components/row.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: hidden;
}

.container > * {
margin: 0.5rem;
}
20 changes: 20 additions & 0 deletions apps/next-app/components/row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { CSSProperties } from "react";
import styles from "./row.module.css";

interface Props {
children: React.ReactNode;
style?: CSSProperties;
}

/**
* Horizontal layout helper
*/
const Row = ({ children, style }: Props) => {
return (
<div className={styles.container} style={style}>
{children}
</div>
);
};

export default Row;
17 changes: 17 additions & 0 deletions apps/next-app/components/section.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.container {
flex: 1 0 0;
padding: 1rem;
display: flex;
flex-direction: row;
justify-content: center;
}

.content {
flex: 0 1 1280px;
display: flex;
flex-direction: column;
}

.colored {
background-color: #1976d2;
}
24 changes: 24 additions & 0 deletions apps/next-app/components/section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { CSSProperties } from "react";
import styles from "./section.module.css";

interface Props {
children?: React.ReactNode;
style?: CSSProperties;
colored?: boolean;
}

/**
* Sections are vertical page parts that are visually separated (border, background color/image, ...)
*/
const Section = ({ children, style, colored }: Props) => {
return (
<section
className={`${styles.container} ${colored ? styles.colored : ""}`}
style={style}
>
<div className={styles.content}>{children}</div>
</section>
);
};

export default Section;
5 changes: 5 additions & 0 deletions apps/next-app/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
17 changes: 17 additions & 0 deletions apps/next-app/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// nextjs.org/docs/api-reference/next.config.js/introduction

const path = require("path");

module.exports = {
poweredByHeader: false,
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Include certain packages into build process (inspired by next-transpile-modules)
config.module.rules.push({
test: /\.+(js|jsx|ts|tsx)$/,
use: defaultLoaders.babel,
include: [path.resolve(__dirname, "../../libs")],
type: "javascript/auto",
});
return config;
},
};
35 changes: 35 additions & 0 deletions apps/next-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@my-org/next-app",
"version": "1.0.0",
"private": true,
"engines": {
"node": ">=14.0.0"
},
"dependencies": {
"@my-org/express-api": "file:../../libs/express-api",
"@my-org/react-api-client": "file:../../libs/react-api-client",
"next": "^12.1.2",
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"devDependencies": {
"@types/express": "^4.17.13",
"@types/node": "^17.0.23",
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"browserslist": "^4.20.4",
"eslint": "8.5.0",
"eslint-config-next": "12.1.2",
"eslint-config-prettier": "^8.5.0",
"typescript": "^4.3.5"
},
"scripts": {
"dev": "next dev -p 3000",
"build": "next build",
"start": "next start",
"lint": "next lint && prettier --check '**/*.{js,jsx,ts,tsx}'"
},
"browserslist": [
"defaults"
]
}
22 changes: 22 additions & 0 deletions apps/next-app/pages/404.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Head from "next/head";
import Layout from "../components/layout";
import Section from "../components/section";

const ErrorPage = () => {
return (
<Layout>
<Head>
<title>Error</title>
</Head>
<Section
style={{
justifyContent: "center",
}}
>
<h1 style={{ textAlign: "center" }}>Not Found</h1>
</Section>
</Layout>
);
};

export default ErrorPage;
24 changes: 24 additions & 0 deletions apps/next-app/pages/_app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

html,
body,
#__next {
min-height: 100%;
height: 100%;
overflow: hidden;
}

a {
color: inherit;
text-decoration: none;
}

* {
box-sizing: border-box;
}
Loading

0 comments on commit 0ccd0b2

Please sign in to comment.