📝
marcyannotes
  • Welcome
  • Student Guidelines & Policies
    • Student Handbook
    • AI Policy
    • Academic Calendar
  • Environment Setup
    • Local Environment Setup - Mac
    • Local Environment Setup - Windows
    • GitHub Setup
    • Postgres Setup
  • Fullstack Software Engineering Curriculum
    • Overview
    • How-Tos
      • How To Code at Marcy: Code Style Guide
      • How to Do Short Response and Coding Assignments
      • How to Debug
      • How to PEDAC
      • How to Create Projects with Vite
      • How to Deploy on GitHub Pages
      • How to Deploy on Render
    • Mod 0 - Command Line Interfaces, Git, and GitHub
      • Mod 0 Overview
      • Command Line Interfaces
      • Git & GitHub
      • Git Pulling & Merging
      • Git Branching & PRs
      • Pair Programming: BONUS
    • Mod 1 - JavaScriptFundamentals
      • Mod 1 Overview
      • Intro to Programming
      • Errors
      • Node & Node Modules
      • Variables, Functions & String Methods
      • Control Flow, typeof, and Math
      • Loops
      • Arrays
      • Objects
      • Higher Order Functions: Callbacks
      • Higher Order Functions: Array Methods
      • Regex
    • Mod 2 - HTML, CSS & the DOM
      • Mod 2 Overview
      • HTML
      • CSS
      • Accessibility (a11y)
      • The DOM
      • Events
      • Forms
      • The Box Model and Positioning
      • Flexbox
      • Grid & Media Queries
      • ESModules
      • LocalStorage
    • Mod 3 - Async & APIs
      • Mod 3 Overview
      • Promises
      • Fetch
      • Building a Fetching App
      • Async & Await
    • Mod 4 - Project Week!
      • Project Week Overview
    • Mod 5 - Object-Oriented Programming
      • Mod 5 Overview
      • Intro to OOP, Encapsulation, Factory Functions, and Closure
      • Classes
      • Private & Static
      • Has Many/Belongs To
      • Polymorphism
    • Mod 6 - Data Structures & Algorithms
      • Mod 6 Overview
      • Stacks & Queues
      • Nodes & Linked Lists
      • Singly & Doubly Linked Lists
      • Recursion
      • Trees
    • Mod 7 - React
      • Mod 7 Overview
      • Intro to React
      • Events, State, and Forms
      • Fetching with useEffect
      • Building a Flashcards App
      • React Context
      • Global Context Pattern
      • React Router
    • Mod 8 - Backend
      • Mod 8 Overview
      • Intro to Express
      • Building a Static Web Server with Middleware
      • Securing API Keys with Environment Variables
      • Building a RESTful API with MVC
      • SQL and Databases
      • JOIN (Association) SQL Queries
      • Knex
      • Your First Fullstack App!
      • Migrations & Seeds
      • Schema Design & Normalization
      • Hashing Passwords with Bcrypt
  • Code Challenge Curriculum
    • Unit 0
      • Lecture: Functions in JS
      • CC-00: Functions and Console Logs
      • CC-01: Conditionals
      • CC-02: Conditionals 2
    • Unit 1
      • CC-03: For Loops
      • CC-04: For Loops and Conditionals
      • CC-05: For Loops and Conditionals 2
    • Unit 2
      • CC-06: String Mutations
      • CC-07: Array Iteration
      • CC-08: String Mutation and Array Iteration
      • CC-09: Array Mutations
      • CC-10: Reading Objects
      • CC-11: Objects
      • CC-12: Objects
      • Unit 2 Diagnostic
    • Unit 3
      • Intro to PEDAC (and Algorithms)
      • validTime
      • fizzBuzz (array)
      • digitSumDifference
      • firstNotRepeating
      • compareEvenAndOddSum
      • countVowelConsonants
      • finalHP
      • canMakeTriangle
    • Unit 4
    • Unit 5
    • Unit 6
    • Unit 7
    • Unit 8
    • Sorting
Powered by GitBook
On this page
  • Terms
  • Loading JavaScript into our HTML
  • DOMContentLoaded
  • Dealing with Multiple JavaScript Files
  • Remember Node Exports and Imports?
  • Importing and Exporting with ESModules
  • CORS
  • Live Server To the Rescue!
  • Challenge
  1. Fullstack Software Engineering Curriculum
  2. Mod 2 - HTML, CSS & the DOM

ESModules

PreviousGrid & Media QueriesNextLocalStorage

Last updated 6 months ago

Follow along with code examples !

Terms

  • ESModules — the syntax for organizing code into modules in the browser.

  • Cross-Origin Resource Sharing (CORS) — a security feature implemented by web browsers to restrict webpages from making requests to a different domain than the one that served the original web page.

  • Server — a computer that shares its resources over the internet. A user's computer acts as the "client" and requests resources from the server using the https:// protocol (the hypertext transfer protocol).

  • Development Server — a server used in development to test and iterate on an application before publishing it.

  • Live Server — a tool for starting a development server.

Loading JavaScript into our HTML

So far, if we want our web applications to execute JavaScript code, we add a script tag to the end of the body of our HTML:

<body>
  <h1>Hello World!</h1>
  <script src="./index.js"></script>
</body>

Then, we can run code like this:

const main = () => {
  const h1 = document.querySelector('h1')
  h1.textContent = 'Coding is the best';
}

// Execute the main function upon loading this script
main();
Q: Why do we put the script at the end of the body?

Because our JavaScript uses the Elements in the body. If those Elements haven't loaded yet, we can't referenced them! We'll get errors like this:

Uncaught TypeError: Cannot set properties of null (setting 'textContent')

DOMContentLoaded

Organization is always important when programming and the organization of our application would be improved if we could put script tags within the head. The logic behind this is that our script isn't adding any visible content to our body. CSS files are linked in the head too, after all.

<head>
  <!-- other meta tags + scripts -->
  <script src="./index.js"></script>
</head>
<body>
  <!-- Visible content -->
</body>

However, with the script in the head, we will get errors since our JavaScript attempts to access elements that have not yet loaded.

The original solution to this was to wait for the HTML content to finish loading by adding an event listener to our JavaScript:

// Executes immediately
console.log("hello from index.js");

const main = () => {
  const h1 = document.querySelector('h1')
  h1.textContent = 'Coding is the best';
};

// Only execute main once the DOM content has been loaded
document.addEventListener('DOMContentLoaded', main);

Here, we attach an event listener to the document that waits for all of the DOM content to load before invoking our main function.

This lets us put the <script> in the <head> which means the browser will start loading that file but won't run it until the DOM is complete.

Q: Is it still possible for us to have errors in our app?

Yes! If you accidentally put some DOM code outside of the safety of the main function.

console.log("hello from index.js");

const h1 = document.querySelector('h1')

const main = () => {
  h1.textContent = 'Coding is the best';
  // ^ this will throw an error because h1 was declared before the content was loaded
};

document.addEventListener('DOMContentLoaded', main);

Dealing with Multiple JavaScript Files

Suppose I wanted to load more JavaScript files. Like this one which declares a posts variable with data about posts that I want to render:

posts.js
// this is a global variable
const posts = {
  "dd1286de": {
    id: "dd1286de",
    caption: "the cutest cat in the world",
    src: "https://images.unsplash.com/photo-1529778873920-4da4926a72c2?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8Y3V0ZSUyMGNhdHxlbnwwfHwwfHx8MA%3D%3D"
  },
  // ... more objects like this one
};

And this one which renders posts from the file above:

dom-helpers.js
const renderPosts = () => {
  const postsContainer = document.querySelector('#posts-container');

  Object.values(posts).forEach((post) => {
    const li = document.createElement('li');
    const img = document.createElement('img');
    const caption = document.createElement('p');

    li.id = post.uuid;
    img.src = post.src;
    img.alt = post.caption;
    caption.textContent = post.caption;

    li.append(img, caption);
    postsContainer.append(li);
  });
}

To utilize this code, we just add <script>s for each file:

<head>
  <!-- The order matters! -->
  <script src="./posts.js"></script>
  <script src="./dom-helpers.js"></script>
  <script src="./index.js"></script>
</head>

What happens is that the variable posts and the function renderPosts are added to the "global namespace" and can be referenced anywhere in subsequent files.

But this is an error prone process and will quickly become problematic if we add more and more files. If we just swap the order of the scripts in HTML, we will get an error.

<head>
  <!-- other meta tags -->
  <script src="./index.js"></script>
  <script src="./dom-helpers.js"></script>
  <script src="./posts.js"></script>
</head>

We need a better solution.

Remember Node Exports and Imports?

In Node, we can share code by exporting using module.exports syntax:

1-node-commonjs/posts.js
const posts = {
  "dd1286de": {
    id: "dd1286de",
    caption: "the cutest cat in the world",
    src: "https://images.unsplash.com/photo-1529778873920-4da4926a72c2?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8Y3V0ZSUyMGNhdHxlbnwwfHwwfHx8MA%3D%3D"
  },
  // more objects
};

// use a default export
module.exports = posts;

And then we can import it using require():

1-node-commonjs/index.js
const posts = require('./posts.js')

console.log(posts);

Importing and Exporting with ESModules

In the browser, we need to use a different syntax called ESModules. To enable this functionality, we have to make a few changes.

Start by adding a type="module" to our <script>. We can also remove the other scripts since we'll be importing their code via JavaScript:

<head>
  <!-- We only need to load the "entry point". Each file will manage its own imports. -->
  <script type="module" src="./index.js"></script>
</head>

Then, we can export values as "default exports" using the export default value syntax:

2-esmodules/posts.js
const posts = {
  "dd1286de": {
    id: "dd1286de",
    caption: "the cutest cat in the world",
    src: "https://images.unsplash.com/photo-1529778873920-4da4926a72c2?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8Y3V0ZSUyMGNhdHxlbnwwfHwwfHx8MA%3D%3D"
  },
  // more objects
};

// use a default export with ESModules syntax
export default posts;

We can import that export default into dom-helpers and export a named function renderPosts:

2-esmodules/dom-helpers.js
// Import the default export of posts.js and call it `posts`
import posts from './posts.js'

// Put the `export` keyword to export a "named export"
export const renderPosts = () => {
  // ...
}

And finally we can import the named renderPosts function into index.js

2-esmodules/index.js
// Use curly braces to import a "named export"
import { renderPosts } from './dom-helpers.js'

const main = () => {
  document.querySelector('h1').textContent = 'Coding is the best';
  renderPosts();
}

// We don't need the event listener anymore. Modules automatically wait for the content to load!
main();

Try to open this and... you'll run into an error :(

CORS

The Cross-Origin Resource Sharing (CORS) policy is a security feature implemented by web browsers to restrict webpages from making requests to a different domain than the one that served the original web page.

For some reason, when you open a file using the file:// protocol (local file system) and attempt to access a resource from any other location (including your own file system), it will consider it to be a different origin.

To get around this, we need to serve our html file using the http:// protocol from a Server, not from our file system. This helps the browser see that all of the files are coming from the same origin.

Live Server To the Rescue!

A server is just a computer that shares its resources over the internet. A user's computer acts as the "client" and requests resources from the server using the https:// protocol (the hypertext transfer protocol).

However, we only get to this point once we deploy our project on a server hosting service. Until that point, we need to simulate this HTTP request and response cycle using a development server like Live Server.

With a development server, our computer acts as both the client and the server.

Do the following to add live server to your environment:

  • Go to the VS Code Extension library and find Live Server. Install it.

  • Open your index.html file and click on the Go Live button in the bottom right corner of your screen

Running your web app through a local development server will allow you to simulate a more typical web environment with http:// or https:// protocols, which should prevent CORS issues during testing.

Challenge

Take the example to the next level and insert a form to enable a user to add a new post to this page! Improve the appearance and layout of the page by modifying the styles.

().

When we visit a URL, like , our browser converts the Domain Name (google.com) into the IP Address of the server computer where the code for Google lives. Then, our computer sends a request to that server computer over the internet and the server sends a response.

Learn more about CORS here
https://www.google.com
here
Terms
Loading JavaScript into our HTML
DOMContentLoaded
Dealing with Multiple JavaScript Files
Remember Node Exports and Imports?
Importing and Exporting with ESModules
CORS
Live Server To the Rescue!
Challenge
face palm
The client server interaction
Install live server