Low-Level Documentation

choir241

Richard Choi

Posted on November 5, 2024

Low-Level Documentation

Frontend: TypeScript

Problem:

We need to decide what frontend technology stack we want to use alongside Next.

Solution Requirements:

  • The technology stack needs to be compatible with Next

  • The technology stack needs to offer features that will make development more smooth

Solution:

TypeScript will be used to check the types of all possible data types within the code without having to write any additional code for conditional statements to check for data types.  Also, Typescript provides an easier debugging experience, as it always catches errors in the code without having to run it.

TypeScript is a bit more complex when going in deeper, but on the surface level, it is quite easy to pick up if you already know React; if you know HTML and JS already, you are halfway there.

Detailed Design:

The intent is to use TypeScript for components and elements of the code that would benefit greatly from the type-checking nature of TypeScript.

import {countContext} from "../components/Context"
import {useStore} from "../components/Zustand"
import api from "../api/api"
import {Test} from "../components/Test"
import {Values} from "../components/Values.tsx"

export default function Home(){
    return(
        <main>
            {Test({firstName: "Mumei", lastName: "Nanshi", "email": "mumei@email.com", age: 26})}
            {Values({firstName: "Mumei", lastName: "Nanshi", "email": "mumei@email.com", age: 26})}
        </main>
    )
}
Enter fullscreen mode Exit fullscreen mode

The Test and Values components have identical arguments passed through them to demonstrate the similarities and differences between React and TypeScript components.

React Component

export function Test(values){
  return(
    <main>
      {values.firstName}
      {values.lastName}
      {values.email}
      {values.age}
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

TypeScript Component

import React from "react"

interface Test{
firstName: string,
lastName: string,
age: number,
email: string
}

export function Test(values: Test){
  return(
    <main>
      {values.firstName}
      {values.lastName}
      {values.email}
      {values.age}
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

The Test component here demonstrates what it would look like to use a component in React, and the Values component demonstrates what it would look like to use the same component in TypeScript.

See Figma Example of using Typescript in the Gridiron Survivor application

Here, a simple design has been created to demonstrate a use-case for TypeScript, where the type-checking in TypeScript is used to ensure that all the data values are the appropriate data types.

Tests

TypeScript detects errors in code without running it, otherwise known as static checking.  It also checks the types of any data type (obj, string, number, etc), making sure to send warnings when the wrong data type is being used or passed through.  There is also the option of printing the code output to the console to ensure that the code is working as intended.

Sources

TypeScript Official Documentation

Module Builder: Webpack 5

Problem:

  • We need a module builder that will handle the bundling of our JS application and allow us to configure the particular type of build.

Solution Requirements:

  • The module builder needs to be compatible with Next.js

  • The module builder needs to be able to handle the bundling of our JS application

  • The module builder needs to allow the configuration of the type of build

Solution:

Webpack 5 is included upon installation of Next, and it let you bundle your JavaScript applications, supporting both ESM and CommonJS.  They also allow the configuration of the type of build for your application.

Detailed Design:

Upon creating a new Next application using the create-next-app@latest command, the following default configurations for Webpack 5 will be shown in the tsconfig.json file.

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "jest.config.ts"],
  "exclude": ["node_modules"]
}
Enter fullscreen mode Exit fullscreen mode

What each property means for Webpack 5:

Next Create App Features

Target: tells runtime code to generate in a specific environment

Lib: defines the libraries that will be included in the compilation process

AllowJs: enables the compilation of JavaScript files

SkipLibCheck: skips the type checking of declaration files (files with .d.ts extensions)

Strict: enables strict type-checking options mode for TypeScript

Noemit: prevents TypeScript from emitting output files

Esmoduleinterop: enables the compatibility between ESmodules and commonJS

Module: specifies the module code generation

Module resolution: determines how Webpack will resolve modules

ResolveJsonModule: allows TypeScript to import JSON modules directly

Isolated Modules: ensures each file is treated as a separate module. This can improve build performance

JSX: specifies JSX factory function to use.

Incremental: enables incremental compilation, allowing TypeScript to cache compilation results and speed up subsequent builds

Plugins: an array of TypeScript plugins

Paths: defines path mapping for module imports

Include: specifies files to include in TypeScript compilation

Exclude: specifies files to exclude in TypeScript compilation

Resources:

Next official documentation on Webpack 5 Adoption

Next official documentation on configuring your custom webpack

Webpack official website

Routing: Next App Routing

Problem:

  • We need a way to create different pages so the user can navigate through the application

Problem Requirements:

  • The feature needs to be able to allow the creation of new pages, where each new page will represent a new route domain within the application

Solution:

Next Routing moves to different pages of the application while remaining a single-page application.  It is also automatically available upon installing Next, and there is a simple setup available upon creating a new Next application using the create-next-app@latest command.

The goal is to assign different pages to different elements of the application.  Not only to be able to organize the code into separate pages but also to find a way to host an API and/or HTTP requests for the application.

Detailed Design:

Without requiring a separate application to host the backend and receive the HTML requests that will be made, the API Routes will allow us to define our API routes in our application.  Not only will this be more convenient, but this will also save time and make collaboration between the backend team and the frontend/functional team more smooth and streamlined.

Figma Design Example of using Next Routing in the Gridiron Survivor Application

The idea is to have a separate page for the main component, ie. a page for authentication called pages/authentication, a page for the user profile called pages/userProfile, etc.

App Router Setup:

Github Repository Example of using Next App Routing

Page Router Setup:

Github Repository Example of using Next Page Routing

Testing:

For the API routes, print to the console to make sure that each API route is being registered properly and it was set up properly.

Resources:

Next official documentation on building your application routing

State Management: Context API and Zustand

Authors: Richard Choi

Problem:

  • We need a way to manage all of our states while avoiding the pitfall of prop drilling

  • We need a way to re-render our entire application upon successful authentication to prepare the authenticated content post-authentication

Problem Requirements:

  • It needs to be able to not only store the state and the state values but also make them available on every level of the application to prevent prop drilling

  • It needs to be able to cause the entire application to re-render for authentication and post-authentication

Solution:

Context API and Zustand manage your states, making them available at any level of the application.  If set up correctly, Context API can cause the entire application to re-render and make the data globally available throughout the application, while Zustand focuses more on the individual level of making the states and state values available in the application.

Both solutions avoid the pitfall of using prop drilling, as they can be made available at any level of the application.  They make states more organized, giving the other team members a better understanding of each state's usage, and functionality, and it makes it easier for them to navigate through.

Detailed Design:

They handle state changes, mostly from input, and they also allow us to access all kinds of data from any level of the application using Zutand and Context API.

Zutand: Setup state store in a separate file, and categorize each store object into the respective components, creating nested stores when/if necessary. Access the necessary store(s) from the file path including the Zutand stores, and reinitialize variables to access the necessary states/functions/values from the Zutand store objects.

Context: Setup context middleware file/folder, accessing the created context to wrap the context provider around the components that need to access the respective data/states.  Implement the states/values/functions using the value property, and access them from your controlled child components using the useContext hook.

Figma Design Example of using Zustand States and local States in the Gridiron Survivor Application

Next App Zustand Setup

Github repository example of using Zustand in a Next application

Tests

Upon creating a state and path for them, we intend to print to the console to test if the states work properly by printing the values that correspond to the state.  We will know when these features stop working when the console prints out undefined/null/falsy values.

Launch

To launch these features, one must change/update the state value that corresponds to the state manager.  To monitor the state managers, the React Developer Tools are a good way to determine what is being re-rendered upon a state update.

Resources

Zustand Official Documentation

Documentation about the React hook useContext

React official documentation on Passing Data Deeply with Context

Caching: Session Storage and Local State

Authors: Richard Choi

Problem:

  • We need a way to persist our data so that when the user leaves the application tab or refreshes the screen, the data will remain upon returning

Problem Requirements:

  • This feature needs to be able to persist data regardless of refresh or exiting the tab

  • This feature also needs to be able to be timed out after a certain amount of time to ensure the data does not persist forever

Solution:

Session storage only maintains the session/data of the current tab/page. A new one is created every time a new tab is created.  Local state only maintains the data when exiting the tab, not the window, and does not maintain the data upon refreshing the screen.

They help us maintain the data on screen/for code despite other circumstances.  They also provide convenience to the user, so if they input something, but they accidentally exit out of the program, their “place” is “saved” thanks to cache storage.  It gives a kind of safety net for other team members when testing the application, preventing them from “losing” their “saved data” from an accidental click/exit.  Context API can be used to re-render the entire application to implement localization and to ensure content is rendered upon successful authentication.

Detailed Design:

Figma Design Example of using Cache in the Gridiron Survivor Project

Have objects to represent all the session storage/local storage we plan to use, using unique names for each object and key name, and store them all in one file called cache.  Export those objects, and import them into components that need to access those cache data to implement more clean and organized code.

Testing:

Print to the console for session storage to make sure that the values are being saved properly, or you can also use the inspect tool, and under the application tab under storage, you can visibly see the different properties you have to check the values of them all.

Resources:

MDN documentation about session storage

💖 💪 🙅 🚩
choir241
Richard Choi

Posted on November 5, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related