Skip to main content
Version: 2023sp

Lecture 2

Homework: Assignment 1: JS, TS, and Basic React, is due 3/11 by 11:59pm

Slides: Here

Explore more:

  • tRPC: End-to-end type safety for a full-stack TypeScript app
  • Turborepo: A monorepo tool for TypeScript, to keep all libraries, backend, and frontend code in one place

Today's Lecture 2/27

By the end of today, you should be able to:

  • Understand the evolution of web development
  • Understand how websites work under the hood
  • Understand the difference between Node.js and Browser JS
  • Understand the ecosystem of modern web development tools (Yarn, JS Frameworks, Linting, etc.), how each tool fits into the development process, why each is present, and how to use them.

How to build a web app

Intro to Node.js and Yarn

How do websites work?

There are two main models of websites: static and dynamic. The difference between the two is how the content is generated.

Static websites

When we originally conceived of the "website", it was a static little bundle of HTML, CSS, and JavaScript. In essence, when you access a URL, your browser asks the server at the other end for that bundle via an HTTP request. The server then sends back the bundle, and your browser renders it.

This is the traditional static website, and it adheres cleanly to the server-client model. However, as webpages got more complex, we needed a way to make them more dynamic. We needed a way to store data, and to send it back to the client when they requested it. This is where the dynamic website comes in.

Dynamic websites

Dynamic websites are websites that are generated on the fly. They are not static bundles of HTML, CSS, and JavaScript. Instead, they are generated by a server-side language, such as PHP, Python, or Ruby. When a user requests a page, the server runs the code to generate the page, and then sends it back to the client.

In reality...

In reality, most websites are a mix of static and dynamic content. The static content is the HTML, CSS, and JavaScript that is sent to the client. The dynamic content is the data that is sent to the client when they request it.

This led to the rise of all kinds of rendering models and JavaScript frameworks, which we'll cover shortly. First, however, you need to know Node and Yarn.

Node.js

Node.js is an open source, cross platform JavaScript V8 runtime environment using a single-threaded event loop.

Let's break it down...

Open Source

All of the code is available to you to view on Github! Anyone can contribute-- this democratizes the development process!

Cross Platform JavaScript Runtime Environment

  • Historically you were only able to run JavaScript on the browser or client
  • Node.js takes the V8 JavaScript engine powering Google Chrome outside of the browser allowing you to run Node.js anywhere
    • V8 JavaScript engine is a fast JavaScript engine created by Google. Learn more about it here!
  • Can run Node.js on your terminal as well
  • Now, we can use JavaScript as a universal language!

Single-threaded

  • Threads are a separate line of execution and can be ran in parallel - i.e. several at the same time.
  • However, Node.js uses a single-threaded event loop
    • Run in a single process
    • Requests do not spawn new threads
  • Non-blocking

How does Node.js handle multiple requests?

  • Node.js is asynchronous
  • When a request is sent, it is dispatched to the server
  • Instead of blocking the thread and wasting CPU cycles waiting for the request to finish, Node.js continues its operations
  • Once the request is complete, a callback is triggered and information is sent back

Event Loop

  • Client can send requests into the event loop
  • We can register callbacks to server when doing things that might take time (ie. search, query, intensive computation)
  • After operation completes, callback will fire and return to requests
info

A callback is a function that you can pass to another function to be executed later. This is a common pattern in web development, since lots of data goes from the client to the server, and we want to implement certain behavior that fires after the data is received.

Why Node.js?

  • Unites front-end and back-end in one language/framework
    • TypeScript/JavaScript
    • Frontend and backend in the same language
  • Extremely performant
  • Asynchronous and non-blocking
  • NPM (Node Package Manager)
    • a directory of many libraries and packages
    • access to huge libraries to use in projects and build upon
    • similar to pip in Python, Gradle/Maven in Java, etc (it's okay if you've never heard of these!)

Conceptual Overview: Node.js vs Browser JS

Node.js runs on the server (aka not in your browser), while browser JS runs on the client (in your browser). They are both JavaScript, but since JavaScript is a standard, not a single unified language, there are differences between the two (some native functions that exist in a browser, such as accessing a window's URL, obviously have no meaning in Node.js).

Keep this in mind! If you install a package meant for Node.js and try to use it in the browser, it might behave unexpectedly. If you install a package meant for the browser and try to use it in Node.js, it might not behave unexpectedly. These are two entirely separate runtime environments!

Node Package Manager (NPM)

NPM is a dependency manager, like pip for python or maven for java. Think of node packages as recipes made by other people you want to use in your site. Also part of the open sourced community!

package.json

The package.json is kind of like a directory for your Node project. It contains various metadata and information about it, as well as details on what it depends on, so others can reproduce the behavior of your project.

  • Tracks which node packages you use
  • Dependencies: packages needed at run-time
npm install --save <pkg_name>
yarn add <pkg_name>
  • devDependencies: packages used during development (before pushing to production). When a "production" or real version gets built prior to deployment, these dependencies will not be included. Only install certain tools that ease development in this manner.
npm install --save-dev <pkg_name>
yarn add --dev <pkg_name>

We will use Yarn!

  • Faster at installing dependencies in practice
  • More optimized

NPM vs Yarn commands

  • NPM
npm init
npm install <pkg_name>
npm uninstall <pkg_name>
npm update <pkg_name>
npm audit
  • Yarn
yarn init
yarn add <pkg_name>
yarn remove <pkg_name>
yarn upgrade <pkg_name>
yarn audit
  • Very similar
  • Audit: checks for vulnerabilities in dependencies

JavaScript Frameworks, Rendering Models, and more.

Because of the rise of Node.js, there has been a rise in JavaScript frameworks and rendering models. These frameworks are either client-side or full-stack frameworks, and they are used to make the development process easier. Now, JS can run in your client's browser and on your server, meaning we have unified the front-end and back-end in one language! With this power comes ... more power, as we can manipulate how the user renders a website in different ways. This led to the rise of correpsonding JavaScript Frameworks, each of which embraces a slightly different rendering model. Here's a brief overview of all the main ways:

Static websites are pre-built and served to the client without the need for any server-side processing. They are fast and simple, but lack dynamic functionality. We covered this above.

Progressive Web Apps (PWAs) are web applications that can be "installed" on a user's device and run offline. They can be built using a variety of technologies, including **React.js**. These are entirely client-side frameworks that run in the browser, and are in reality singular empty HTML shells with a massive JS bundle that pushes in all the content on-the-fly as the user navigates the site.

Server-side rendering with hydration is a technique where the initial render of a web application is done on the server, and then "hydrated" on the client with JavaScript to add dynamic functionality. This improves the initial load time and SEO of the application, while still allowing the application to be dynamic. The most famous framework in this category, and the one we'll be using, is **Next.js**.

Incremental static regeneration is a technique where a web application is rendered statically, but certain parts of the application are periodically re-rendered on the server to ensure that the content is up-to-date (we check if the content has turned "stale" and then refresh from the server when that happens). This is a technique used by Next.js to improve the performance of certain parts of the interface, as well as by other frameworks.

Partial hydration is a technique where only certain parts of a web application are hydrated, rather than the entire application. This can improve the performance of the application by reducing the amount of JavaScript that needs to be executed on the client. Unlike the previous rendering models, this is less of the basis of an existing framework, and more of a technique that different frameworks can use.

Islands is a technique where a web application is divided into "islands" of functionality, each with its own hydration and JavaScript execution, isolated in a sea of very-performant and lightweight, but static HTML. This can improve the performance of the application by reducing the amount of JavaScript that needs to be executed on the client. The team behind this architecture is the **Astro.js** framework.

Streaming SSR is a technique where the server sends the initial HTML of a web application to the client in chunks, allowing the browser to start rendering the application before all of the JavaScript has been loaded. Like...a lot of this list, Vercel's **Next.js** framework is pioneering this technique, with their newly released Next.js 13 (beta).

Resumability is a technique where a web application serializes all of its JavaScript into HTML, and then loads JS in in as tiny of chunks as possible, allowing the browser to start rendering the application before all of the JavaScript has been loaded. This is the fastest and most performant framework, being pioneered by the team at Qwik. I won't pretend to understand exactly how this works.

Then, at the end of the day, all of this fancy code has to be compiled down into bundles that the browser can understand anyway. Towards this end, the industry heavyweight is Webpack, which is a bundler written in JS that can be used to compile all of your code into a single file that can be served to the client. Recent challengers, however, include Vercel's Turbopack, which is written in Rust and offers a much faster build time. Vite also exists -- an extremely lightweight and performant bundler, normally used in development environments.

Other stuff (linting, resources, etc.)

Why Linters Are Necessary

Remember all the weird quirks of JavaScript from last lesson? Unfortunately, we're stuck with JS because it's the only language that can be understood by browser (for now). To mitigate the problem, people wrote linters that try to automatically find common problems in written JS. They are well integrated with editors so you can directly see the warnings. If you follow the 'Setup your editor' section, you are good to go. You will see warnings when you accidentally write some wrong code.

Resources

I recommend the You Don't Know JS series by Kyle Simpson. The ebooks are available for free on GitHub. The series is comprehensive and will teach you everything you want to know.

Additionally, the MDN Web Docs are a great resource for quickly looking up the documentation for various features in Javascript, complete with examples.

JavaScript

We mentioned Mozilla Developer Network as a site for documentation about the JavaScript language, but it's also a great way to get familiar with the language.

Here is their JavaScript guide: JavaScript Guide - JavaScript | MDN (mozilla.org)

It's a bit long, so I recommend skimming through the first few parts, up to and including the Objects section (Working with objects - JavaScript | MDN (mozilla.org)).

JavaScript objects will show up a good amount in this course, so make sure you understand the basics!

TypeScript

The official TypeScript website is a great resource to get familiar with the language. There are different guides that assume different programming backgrounds. Choose the article that best suits your background.

Take a look at the Get Started section here: TypeScript: The starting point for learning TypeScript (typescriptlang.org)

If you've gone through the MDN JavaScript guide, fill in your TypeScript knowledge with this: TypeScript: Documentation - TypeScript for JavaScript Programmers (typescriptlang.org)

There is also a Handbook that you can chug through if interested (not necessary at all): TypeScript: Handbook - The TypeScript Handbook (typescriptlang.org)

Hope this is helpful for you all! This will be the language you'll be working with all-semester, so being comfortable with the language will pay off.

In-Class Demo 1: Executing Javascript in node and in the browser

TODO: @daniel

  • Walk them through using node to execute javascript line by line, as well as using the console to execute javascript line-by-line.
  • Specifically,