COSC-499-W2023 / year-long-project-team-1

PrivacyPal: A secure messaging and video sharing service (COSC499 Team 1)
Apache License 2.0
18 stars 3 forks source link

[Analysis] Using Next.js for our front end environment #2

Closed connordoman closed 11 months ago

connordoman commented 11 months ago

There has been some discussion about what framework should be used for our front end environment.

Some concerns that need to be addressed in regards to this include:

Multiple people on our team are eager for a chance to try front end development with React. There are many modern frameworks that use React or similar component-based systems (Angular, Vue, Astro) for building web applications.

Historically, React has been deployed client side as a JavaScript bundle that intelligently composes elements and manages their states. This has the benefits of being mostly backwards compatible and requiring little to no back end setup. Downsides to this approach are reliance on older React code patterns, interpreter setup, and outdated bootstrapping tools. Additionally, sending React to the client and rendering the DOM at page load increases load times and slows user experience.

The popularity of Webpack along with TypeScript and JSX have done much to solve these problems. Webpack transpiles, bundles, and minifies all JavaScript code into chunks, decreasing page load times, old code patterns, and tooling setup. However, Webpack itself is getting older and its setup process also has challenges.

This is where server-side frameworks like PHP, Django, Next.js, and more recently Astro, have stood out.

While PHP and Django are more skeletal they allow writing code that allows data security as well as server control. This gives flexibility to the progammer and dynamism to pages and user data.

Taking into account server-side control and data access combined with the use of the web's most popular tools—React, TypeScript, and Node—Next.js solves all of these problems at once.

Next.js

When looking at our projects requirements along with our personal desires in terms of learning outcomes and using new technologies, Next.js fulfills these needs fully:

  1. React with JSX/TSX out of the box
    • Does not require Babel setup for JSX
  2. TypeScript compilation out of the box
    • Does not require tsc setup
  3. Webpack-like bundling out of the box
    • Does not require Webpack expertise
    • 1. and 2. rely on Webpack's configuration
    • Live reloading is a major time saver and prevents confusion
    • Allows use of npm packages, key for staying open source while speeding up developement
    • Modern ES6 import syntax, even server-side
  4. Server-side rendering out of the box
    • Speeds up page load times
  5. API endpoints out of the box
    • No need to set up middleware or server routing rules. Just place API endpoints in /api/
  6. Image optimization out of the box
    • Intelligently pre-scales and caches images to reduce load times

That being said, anything pre-configured by Next.js is also able to overridden and modified as necessary.

Concerns

To reiterate main concerns:

Containerization

Our project requires us to coordinate multiple services running simultaneously on AWS. This naturally draws us to Kubernetes as it is highly scalable, well integrated with AWS, and an industry-standard.

With this, it is a must that all of our services are containerizable so that they may be properly deployed.

Since Next.js is a Node server, containerizing is well documented but does require some additional work from us. Essentially, we take the extra step of defining a new expressjs server that uses Next.js as it's primary app. This makes our deployment more Node-agnostic. Here is an example Dockerfile:

FROM node:12

ENV PORT 3000

# Create app directory
RUN mkdir /var/movable/ && mkdir /var/movable/app
WORKDIR /var/movable/app

RUN rm -rf .next*
# Installing dependencies
COPY package*.json /var/movable/app/
RUN npm install

# Copying source files
COPY . /var/movable/app

# Building app
RUN npm run build
EXPOSE 3000

# Running the app
CMD "npm" "run" "start_prod"

This Dockerfile, along with an overview of the rest of the containerization process, can be found here. This article is part of a series that later includes Ansible and Kubernetes integration, though simply having a container is the minimum we need to begin our own integration.

Docker containers aren't exactly the same as Kubernetes standard containers but for our purposes the "cost" of not having a "perfect" k8s deployment is made up for by how much easier front end development will be. Docker containers are also well supported and allow for some atomicity in development.

Server Load

Since Next.js is a server-side rendering framework this naturally leads to concerns about the server having to do too much work. Obviously, this could undo any benefit to load times and would increase cost as compute time increases.

Next.js uses a build-deploy pipeline where pages are precompiled as much as possible before deployment and then static HTML is served to the user. These builds are also cached so rebuilds take less time. Most pages, even those with outgoing API calls, render statically since data fetched by API calls can simply be populated at request time.

Pages that must render at request time are those:

The newest version of Next.js (13) also includes server-side components, where a component that does not rely on external data at runtime can be prerendered and used on many pages.

Another consideration is that our app, a medical/professional service that is largely appointment based with little random access, may see little to no concurrent users within a single deployment, so the server will not be burdened with constant rerenders.

Learning Outcomes

The matter of React as a desired learning outcome is settled. In my opinion, there is no better way for a beginner to start with React than to deploy a Next.js app since JSX syntax with TypeScript is immediately available and from an empty folder to a running development server is just 2 terminal commands (npm).

This also gives us a chance to work with JavaScript/TypeScript, the industry-standard languages for front end web development and a necessary experience in 2023. Since the server is Node, this also means the entire front end app will be written in TypeScript.

Conclusion

The speed with which we can develop the front end along with use of popular web tools and the chance to learn widely-used frameworks with modern JavaScript tooling and little to no extraneous server-side compute cost makes up for any eccentricities in the deployment pipeline.

Additional Notes

I have historically used yarn as the package manager for JavaScript projects as I prefer its syntax but npm is catching up and looks like it might have some useful CI tools: https://stackoverflow.com/questions/40027819/when-to-use-yarn-over-npm-what-are-the-differences. I am open to whatever the team decides, plus npm is more widely supported and should work out of the box within containers.

tthvo commented 11 months ago

Thanks for explaining so detailed!! This sounds good and makes sense to me. However, there are only 3 issues I am concerned about:

  1. Server-rendering is good but will take up the resources that can be allocated for video/image processing.
  2. Server-rendering will help in fast first load. Subsequent page fetch might be slow if network bandwidth is low while client-rendering already has the react code fetched.
  3. Server and client codes are in the same repo (I believe?) can be a pain for dependencies management. And as always, monorepo never played well in open source community.

In the view of devOps and maintenance, not a big fan. But as this project won't be too big, I don't mind going with this direction.

connordoman commented 11 months ago

Awesome, I think the simplicity of this platform is a great fit for the size of our project.

Just to put some of your worries at ease: