From 2fc7402a8deb159a2258b370cc62b1bfc6aa05a7 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Wed, 8 May 2024 23:12:55 +0100 Subject: [PATCH 01/24] Write intro and pre-esm section --- .../es6_modules_new.md | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 javascript/organizing_your_javascript_code/es6_modules_new.md diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md new file mode 100644 index 00000000000..fdaaf4bf101 --- /dev/null +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -0,0 +1,91 @@ +### Introduction + +We've learned about the **module pattern** in a previous lesson, and played around with using them to help organise our variables and functions. At some point in the last few projects, you may have even wondered "How would we manage more complex projects? Files would get too long! It would be great it we could split our code up into multiple files for organisation!". While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules", and thus they are often referred to as "ES6 modules". + +### Lesson overview + +This section contains a general overview of topics that you will learn in this lesson. + +- Explain what ES6 modules are, and how to import and export from them +- Describe the difference between default and named exports +- Explain the main differences between CommonJS modules and ES6 modules +- Understand what npm is + +### Before ES6 modules - the global scope problem + +
+ +Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples, as they won't change how things work regarding the global scope and the module pattern, which is the primary point. + +
+ +Let's say we have 2 scripts, `one.js` and `two.js`, and we link them in our HTML as separate scripts. + +```html + + +``` + +```javascript +// one.js +const greeting = "Hello, odinite!"; +``` + +```javascript +// two.js +console.log(greeting); +``` + +When we open the HTML, we see `"Hello, odinite!"` getting logged to the console, even though `greeting` was never defined in `two.js`! That's because the two scripts were loaded one after the other into the same global scope, as if we wrote only one file with the two lines in that order. If we put the `two.js` script tag first, we would instead get an error that `greeting is not defined`, as it would try to do the console log before we define the variable. + +This means that even if we use multiple JavaScript files, they will still end up sharing the same global scope. Our top-level variables are not safe! + +Before ES6 modules, we could wrap some things in an IIFE, which would cause it to run just the same, but now any variables inside them are scoped to that function and not globally. + +```javascript +// one.js +(() => { + const greeting = "Hello, odinite!"; +})(); +``` + +Now, we get an error in the console that `greeting is not defined`, because there is no global variable called `greeting` for us to log! But what if we wanted only *some* things to be exposed to other files? We can return those things from our IIFE into the global scope, and keep the other things private! + +```javascript +// one.js +const greeting = (() => { + const greetingString = "Hello, odinite!"; + const farewellString = "Bye bye, odinite!"; + return greetingString; +})(); +``` + +Now, the global variable `greeting` will contain `"Hello, odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to exposed from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code before we were given "real modules". + +But now with ES6 modules, we no longer need to use IIFEs for this specific purpose. + +### ES6 modules + +#### Default and named exports + +#### CommonJS + +### npm + +### Assignment + +
+ +
+ +### Knowledge check + +The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge. + +- [From inside to outside, what is the order of box-model properties?](#the-box-model) + +### Additional resources + +This section contains helpful links to related content. It isn't required, so consider it supplemental. + +- It looks like this lesson doesn't have any additional resources yet. Help us expand this section by contributing to our curriculum. From c6b5cbf12aa2201b8d7fca391669fc675ab807a0 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Wed, 8 May 2024 23:49:30 +0100 Subject: [PATCH 02/24] Write section introduce ESM and entry point concept --- .../es6_modules_new.md | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index fdaaf4bf101..e14827fe2a7 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -66,7 +66,34 @@ But now with ES6 modules, we no longer need to use IIFEs for this specific purpo ### ES6 modules -#### Default and named exports +With ES6 modules, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere - it will only be available in another file if we also explicitly import it there. Lots of control! + +#### Entry point + +When we use ES6 modules, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. + +Take our `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: + +```text + depends on +two.js <----------- one.js +``` + +Therefore, `two.js` is our entry point. When we load `two.js` as a module, the browser will see that it depends on `one.js` then load the code from that file as well. If we instead loaded `one.js` as our entry point, the browser would see that it does not depend on any other files, and so leave it at that. Our code from `two.js` would be ignored and nothing gets logged! + +You can add external scripts to HTML as ES6 modules by adding only the appropriate entry point file like so: + +```html + +``` + +Note that we did not need to link `one.js`, as the browser will handle that for us when it sees what `two.js` depends on. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. + +But how do we actually import and export? Confusingly, there are two types of importing and exporting, `default` and `named`, and they can even be mixed and matched in the same file. + +#### Default exports + + #### CommonJS From 6b874361964d7628df50164c9f5635063dd35f66 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 00:20:15 +0100 Subject: [PATCH 03/24] Write import/export sections --- .../es6_modules_new.md | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index e14827fe2a7..5e67105bcc1 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -93,9 +93,79 @@ But how do we actually import and export? Confusingly, there are two types of im #### Default exports +**We can only default export a single "thing" from a single file.** Something default exported from a file does not have a name attached to it - when you import it somewhere, you can decide what to call it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can stick `export default` at the start of the thing to export when it's declared. Either way is fine. Note that if you `export default` a variable inline, `default` replaces `let`/`const`. +Lets see about default exporting out `greeting` variable from the original `one.js` (no IIFE). -#### CommonJS +```javascript +// one.js +const greeting = "Hello, odinite!"; +export default greeting; + +// We could als default export it inline like so +export default greeting = "Hello, odinite!"; +``` + +Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want - it doesn't have to be called `greeting` if you don't want it to be. We just have to give it a name, and provide the path to the file we're importing from. + +```javascript +// two.js +import helloOdinite from "./one.js"; + +console.log(helloOdinite); // "Hello, odinite!" +``` + +But what if you had multiple separate things to export from `one.js`? + +#### Named exports + +Named exports are actually exported with the name they were declared with, which means we have to import them by their name as well. We either do it inline like before just without `default` (meaning we need the `let`/`const` here), or add to the file an `export { }`, where the curly braces contains a list of names of the things to export as named exports. + +```javascript +// one.js +const greeting = "Hello, odinite!"; +const farewell = "Bye bye, odinite!"; +export { greeting, farewell }; + +// Or inline +export const greeting = "Hello, odinite!"; +export const farewell = "Bye bye, odinite!"; +``` + +Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own! If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were exported as named exports. + +```javascript +// two.js +import { greeting, farewell } from "./one.js"; + +console.log(greeting); // "Hello, odinite!" +console.log(farewell); // "Bye bye, odinite!" +``` + +A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. Use whatever works for you, or in the future when working in a team, whatever your team prefers if they prefer a certain system. + +```javascript +// one.js +export default greeting = "Hello, odinite!"; +export const farewell = "Bye bye, odinite!"; +``` + +```javascript +// two.js +import greeting, { farewell } from "./one.js"; +``` + +
+ +#### Named import/exports aren't the same as object literals! + +Using `{ }` with named import/exports is syntax exlusive to them, and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). + +`export { greeting, farewell };` means we are named exporting the `greeting` and `farewell` variables, not exporting an object with `greeting` and `farewell` properties. Similarly, `import { greeting, farewell } from "./one.js";` means we are named importing those variables, not destructuring an object with those properties. + +
+ +### CommonJS ### npm From 1ec6fc88b2a286da87d4a6198ab5c5358024540c Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 00:35:56 +0100 Subject: [PATCH 04/24] Write short section on CJS Use ESM abbreviation in main text after first full mention. --- .../es6_modules_new.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index 5e67105bcc1..fe61de8bd06 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -1,6 +1,6 @@ ### Introduction -We've learned about the **module pattern** in a previous lesson, and played around with using them to help organise our variables and functions. At some point in the last few projects, you may have even wondered "How would we manage more complex projects? Files would get too long! It would be great it we could split our code up into multiple files for organisation!". While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules", and thus they are often referred to as "ES6 modules". +We've learned about the **module pattern** in a previous lesson, and played around with using them to help organise our variables and functions. At some point in the last few projects, you may have even wondered "How would we manage more complex projects? Files would get too long! It would be great it we could split our code up into multiple files for organisation!". While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules", and thus they are often referred to as "ES6 modules" or "ESM". ### Lesson overview @@ -40,7 +40,7 @@ When we open the HTML, we see `"Hello, odinite!"` getting logged to the console, This means that even if we use multiple JavaScript files, they will still end up sharing the same global scope. Our top-level variables are not safe! -Before ES6 modules, we could wrap some things in an IIFE, which would cause it to run just the same, but now any variables inside them are scoped to that function and not globally. +Before ESM, we could wrap some things in an IIFE, which would cause it to run just the same, but now any variables inside them are scoped to that function and not globally. ```javascript // one.js @@ -60,17 +60,17 @@ const greeting = (() => { })(); ``` -Now, the global variable `greeting` will contain `"Hello, odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to exposed from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code before we were given "real modules". +Now, the global variable `greeting` will contain `"Hello, odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to exposed from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code across multiple files before we were given "real modules". -But now with ES6 modules, we no longer need to use IIFEs for this specific purpose. +But now with ESM, we no longer need to use IIFEs for this specific purpose. ### ES6 modules -With ES6 modules, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere - it will only be available in another file if we also explicitly import it there. Lots of control! +With ESM, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere - it will only be available in another file if we also explicitly import it there. Lots of control! #### Entry point -When we use ES6 modules, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. +When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. Take our `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: @@ -81,7 +81,7 @@ two.js <----------- one.js Therefore, `two.js` is our entry point. When we load `two.js` as a module, the browser will see that it depends on `one.js` then load the code from that file as well. If we instead loaded `one.js` as our entry point, the browser would see that it does not depend on any other files, and so leave it at that. Our code from `two.js` would be ignored and nothing gets logged! -You can add external scripts to HTML as ES6 modules by adding only the appropriate entry point file like so: +You can add external scripts to HTML as ESM by adding only the appropriate entry point file like so: ```html @@ -167,6 +167,10 @@ Using `{ }` with named import/exports is syntax exlusive to them, and is not rel ### CommonJS +Along the way, you may have bumped into something called "CommonJS" (a.k.a. CJS), which uses syntax like `require` and `module.exports`. We use this for our JavaScript exercises from Foundations! This is a module system that was designed for use with NodeJS that works a little differently to ESM, and is not something that browsers will be able to understand. + +CJS is still used quite a lot in NodeJS code, though in recent years, ESM has become more popular there. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. + ### npm ### Assignment From 7bf0f28123dfee060d1d306cdea8373ed720cef3 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 00:53:27 +0100 Subject: [PATCH 05/24] Streamline verbiage and emphasise scope distinctions --- .../es6_modules_new.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index fe61de8bd06..b2d32bcf61e 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -68,6 +68,14 @@ But now with ESM, we no longer need to use IIFEs for this specific purpose. With ESM, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere - it will only be available in another file if we also explicitly import it there. Lots of control! +
+ +#### Module scope is not the global scope + +When using ESM, each module has its own private scope, where we use import/export to communicate between files. A top-level variable in a module will not be accessible in the global scope. + +
+ #### Entry point When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. @@ -159,9 +167,15 @@ import greeting, { farewell } from "./one.js"; #### Named import/exports aren't the same as object literals! -Using `{ }` with named import/exports is syntax exlusive to them, and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). +Using `{ }` with named import/exports is special syntax, and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). + +```javascript +export { greeting, farewell }; + +import { greeting, farewell } from "./one.js"; +``` -`export { greeting, farewell };` means we are named exporting the `greeting` and `farewell` variables, not exporting an object with `greeting` and `farewell` properties. Similarly, `import { greeting, farewell } from "./one.js";` means we are named importing those variables, not destructuring an object with those properties. +In the above, we are not exporting an object containing `greeting` and `farewell` keys, nor are we destructuring an object with those keys when importing. We are just using named import/export syntax. From 03c46be6ecc5983b2a8a2ce63550381f62248b7f Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 01:11:22 +0100 Subject: [PATCH 06/24] Add brief npm section --- .../organizing_your_javascript_code/es6_modules_new.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index b2d32bcf61e..67bc3408bb7 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -187,6 +187,14 @@ CJS is still used quite a lot in NodeJS code, though in recent years, ESM has be ### npm +**npm** is a package manager, a gigantic repository of plugins, libaries and other tools, which provides us a command-line tool we can use to install these tools (we call "packages") in our applications. Then we will have all our installed packages' code locally, which can then import into our own files. We can even publish our own code to npm! + +You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. + +If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. + +As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This is even more so when we consider we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will talk through bundlers, a tool that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files (that do exactly the same thing) which will be sent to the browser instead. + ### Assignment
From 0e9a91a3ad2602b60474022f9433831dc8e392ad Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 01:46:28 +0100 Subject: [PATCH 07/24] Add assignment, KC and AR content --- .../es6_modules_new.md | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index 67bc3408bb7..d04e0c1987f 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -1,6 +1,8 @@ ### Introduction -We've learned about the **module pattern** in a previous lesson, and played around with using them to help organise our variables and functions. At some point in the last few projects, you may have even wondered "How would we manage more complex projects? Files would get too long! It would be great it we could split our code up into multiple files for organisation!". While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules", and thus they are often referred to as "ES6 modules" or "ESM". +We've learned about the **module pattern** in a previous lesson, and played around with using them to help organise our variables and functions. At some point in the last few projects, you may have even wondered "How would we manage more complex projects? Files would get too long! It would be great it we could split our code up into multiple files for organisation!". Using multiple files would be extremely handy, as we could more easily separate our code into groups of related functions and values, without having to scroll through one ridiculously long file. + +While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules", and thus they are often referred to as "ES6 modules" or "ESM". ### Lesson overview @@ -11,7 +13,7 @@ This section contains a general overview of topics that you will learn in this l - Explain the main differences between CommonJS modules and ES6 modules - Understand what npm is -### Before ES6 modules - the global scope problem +### Before ES6 modules: The global scope problem
@@ -187,7 +189,7 @@ CJS is still used quite a lot in NodeJS code, though in recent years, ESM has be ### npm -**npm** is a package manager, a gigantic repository of plugins, libaries and other tools, which provides us a command-line tool we can use to install these tools (we call "packages") in our applications. Then we will have all our installed packages' code locally, which can then import into our own files. We can even publish our own code to npm! +**npm** (no capitals!) is a package manager, a gigantic repository of plugins, libaries and other tools, which provides us a command-line tool we can use to install these tools (we call "packages") in our applications. Then we will have all our installed packages' code locally, which can then import into our own files. We can even publish our own code to npm! You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. @@ -199,16 +201,31 @@ As our applications get more complex and more and more files are needed (whether
+1. As per usual, you can learn most about JavaScript keywords and concepts from the MDN docs, so check out the [docs on export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and [docs on import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). There are little extras about them we have not covered in this lesson, such as aliases and namespace imports. +1. Read a bit about npm, packages and dependencies: + 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). + 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. + 1. Any packages we install are called "dependencies", but if any package are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). +1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson. +
### Knowledge check The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge. -- [From inside to outside, what is the order of box-model properties?](#the-box-model) +- [Before ES6 modules, how would you privatise a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) +- [Before ES6 modules, how would you expose variables to be accessible in later files?](#before-es6-modules-the-global-scope-problem) +- [What are some benefits of writing code in modules?](#introduction) +- [What is an entry point?](#entry-point) +- [How do you link a module script in HTML?](#entry-point) +- [What is the difference between default and named exports?](#default-exports) +- [What is npm?](#npm) +- [What file does npm use that contains all information about dependencies?](https://docs.npmjs.com/creating-a-package-json-file) ### Additional resources This section contains helpful links to related content. It isn't required, so consider it supplemental. -- It looks like this lesson doesn't have any additional resources yet. Help us expand this section by contributing to our curriculum. +- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarises much of the ESM topics discussed in this lesson. At the end, he mentions about `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, and so you will not need to worry about browser compatibility for this. +- Here is a [brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). From 35fe7978883d76e5cee6dcca0ea4d9c6cf8b5c9a Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 02:01:57 +0100 Subject: [PATCH 08/24] Fix grammar and spelling Now uses AE spelling instead of BE. --- .../es6_modules_new.md | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md index d04e0c1987f..876db6bb99a 100644 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ b/javascript/organizing_your_javascript_code/es6_modules_new.md @@ -1,17 +1,17 @@ ### Introduction -We've learned about the **module pattern** in a previous lesson, and played around with using them to help organise our variables and functions. At some point in the last few projects, you may have even wondered "How would we manage more complex projects? Files would get too long! It would be great it we could split our code up into multiple files for organisation!". Using multiple files would be extremely handy, as we could more easily separate our code into groups of related functions and values, without having to scroll through one ridiculously long file. +We've learned about the **module pattern** in a previous lesson and played around with using them to help organize our variables and functions. At some point in the last few projects, you may have even wondered, "How would we manage more complex projects? Files would get too long! It would be great if we could split our code up into multiple files for organization!". Using multiple files would be extremely handy, as we could more easily separate our code into groups of related functions and values without having to scroll through one ridiculously long file. -While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules", and thus they are often referred to as "ES6 modules" or "ESM". +While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules" and thus they are often referred to as "ES6 modules" or "ESM". ### Lesson overview This section contains a general overview of topics that you will learn in this lesson. -- Explain what ES6 modules are, and how to import and export from them -- Describe the difference between default and named exports -- Explain the main differences between CommonJS modules and ES6 modules -- Understand what npm is +- Explain what ES6 modules are and how to import and export from them. +- Describe the difference between default and named exports. +- Explain the main differences between CommonJS modules and ES6 modules. +- Understand what npm is. ### Before ES6 modules: The global scope problem @@ -21,7 +21,7 @@ Even though `let`/`const` and arrow functions were not around before ES6, we wil
-Let's say we have 2 scripts, `one.js` and `two.js`, and we link them in our HTML as separate scripts. +Let's say we have two scripts, `one.js` and `two.js`, and we link them in our HTML as separate scripts. ```html @@ -30,7 +30,7 @@ Let's say we have 2 scripts, `one.js` and `two.js`, and we link them in our HTML ```javascript // one.js -const greeting = "Hello, odinite!"; +const greeting = "Hello, Odinite!"; ``` ```javascript @@ -38,7 +38,7 @@ const greeting = "Hello, odinite!"; console.log(greeting); ``` -When we open the HTML, we see `"Hello, odinite!"` getting logged to the console, even though `greeting` was never defined in `two.js`! That's because the two scripts were loaded one after the other into the same global scope, as if we wrote only one file with the two lines in that order. If we put the `two.js` script tag first, we would instead get an error that `greeting is not defined`, as it would try to do the console log before we define the variable. +When we open the HTML, we see `"Hello, Odinite!"` getting logged to the console, even though `greeting` was never defined in `two.js`! That's because the two scripts were loaded one after the other into the same global scope, as if we wrote only one file with the two lines in that order. If we put the `two.js` script tag first, we would instead get an error that `greeting is not defined`, as it would try to do the console log before we define the variable. This means that even if we use multiple JavaScript files, they will still end up sharing the same global scope. Our top-level variables are not safe! @@ -47,28 +47,28 @@ Before ESM, we could wrap some things in an IIFE, which would cause it to run ju ```javascript // one.js (() => { - const greeting = "Hello, odinite!"; + const greeting = "Hello, Odinite!"; })(); ``` -Now, we get an error in the console that `greeting is not defined`, because there is no global variable called `greeting` for us to log! But what if we wanted only *some* things to be exposed to other files? We can return those things from our IIFE into the global scope, and keep the other things private! +Now, we get an error in the console that `greeting is not defined`, because there is no global variable called `greeting` for us to log! But what if we wanted only *some* things to be exposed to other files? We can return those things from our IIFE into the global scope and keep the other things private! ```javascript // one.js const greeting = (() => { - const greetingString = "Hello, odinite!"; - const farewellString = "Bye bye, odinite!"; + const greetingString = "Hello, Odinite!"; + const farewellString = "Bye bye, Odinite!"; return greetingString; })(); ``` -Now, the global variable `greeting` will contain `"Hello, odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to exposed from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code across multiple files before we were given "real modules". +Now, the global variable `greeting` will contain `"Hello, Odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to expose from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code across multiple files before we were given "real modules". -But now with ESM, we no longer need to use IIFEs for this specific purpose. +But now, with ESM, we no longer need to use IIFEs for this specific purpose. ### ES6 modules -With ESM, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere - it will only be available in another file if we also explicitly import it there. Lots of control! +With ESM, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere; it will only be available in another file if we explicitly import it there. Lots of control!
@@ -82,16 +82,16 @@ When using ESM, each module has its own private scope, where we use import/expor When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. -Take our `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: +Take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: ```text depends on two.js <----------- one.js ``` -Therefore, `two.js` is our entry point. When we load `two.js` as a module, the browser will see that it depends on `one.js` then load the code from that file as well. If we instead loaded `one.js` as our entry point, the browser would see that it does not depend on any other files, and so leave it at that. Our code from `two.js` would be ignored and nothing gets logged! +Therefore, `two.js` is our entry point. When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead loaded `one.js` as our entry point, the browser would see that it does not depend on any other files, and so leave it at that. Our code from `two.js` would be ignored, and nothing gets logged! -You can add external scripts to HTML as ESM by adding only the appropriate entry point file like so: +You can add external scripts to HTML as ESM by adding only the appropriate entry point file, like this: ```html @@ -99,47 +99,47 @@ You can add external scripts to HTML as ESM by adding only the appropriate entry Note that we did not need to link `one.js`, as the browser will handle that for us when it sees what `two.js` depends on. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. -But how do we actually import and export? Confusingly, there are two types of importing and exporting, `default` and `named`, and they can even be mixed and matched in the same file. +But how do we actually import and export? Confusingly, there are two types of importing and exporting: `default` and `named`, and they can even be mixed and matched in the same file. #### Default exports -**We can only default export a single "thing" from a single file.** Something default exported from a file does not have a name attached to it - when you import it somewhere, you can decide what to call it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can stick `export default` at the start of the thing to export when it's declared. Either way is fine. Note that if you `export default` a variable inline, `default` replaces `let`/`const`. +**We can only default export a single "thing" from a single file.** Something default exported from a file does not have a name attached to it; when you import it somewhere, you can decide what to call it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can stick `export default` at the start of the thing to export when it's declared. Either way is fine. Note that if you `export default` a variable inline, `default` replaces `let`/`const`. -Lets see about default exporting out `greeting` variable from the original `one.js` (no IIFE). +Let's see about default exporting our `greeting` variable from the original `one.js` (no IIFE). ```javascript // one.js -const greeting = "Hello, odinite!"; +const greeting = "Hello, Odinite!"; export default greeting; -// We could als default export it inline like so -export default greeting = "Hello, odinite!"; +// We could also default export it inline, like this +export default greeting = "Hello, Odinite!"; ``` -Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want - it doesn't have to be called `greeting` if you don't want it to be. We just have to give it a name, and provide the path to the file we're importing from. +Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want. It doesn't have to be called `greeting` if you don't want it to be. We just have to give it a name and provide the path to the file we're importing from. ```javascript // two.js import helloOdinite from "./one.js"; -console.log(helloOdinite); // "Hello, odinite!" +console.log(helloOdinite); // "Hello, Odinite!" ``` But what if you had multiple separate things to export from `one.js`? #### Named exports -Named exports are actually exported with the name they were declared with, which means we have to import them by their name as well. We either do it inline like before just without `default` (meaning we need the `let`/`const` here), or add to the file an `export { }`, where the curly braces contains a list of names of the things to export as named exports. +Named exports are actually exported with the name they were declared with, which means we have to import them by their name as well. We either do it inline like before just without `default` (meaning we need the `let`/`const` here) or add to the file an `export { }`, where the curly braces contain a list of the names of the things to export as named exports. ```javascript // one.js -const greeting = "Hello, odinite!"; -const farewell = "Bye bye, odinite!"; +const greeting = "Hello, Odinite!"; +const farewell = "Bye bye, Odinite!"; export { greeting, farewell }; // Or inline -export const greeting = "Hello, odinite!"; -export const farewell = "Bye bye, odinite!"; +export const greeting = "Hello, Odinite!"; +export const farewell = "Bye bye, Odinite!"; ``` Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own! If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were exported as named exports. @@ -148,16 +148,16 @@ Now to import these named exports in `two.js`! Remember that we can control what // two.js import { greeting, farewell } from "./one.js"; -console.log(greeting); // "Hello, odinite!" -console.log(farewell); // "Bye bye, odinite!" +console.log(greeting); // "Hello, Odinite!" +console.log(farewell); // "Bye bye, Odinite!" ``` -A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. Use whatever works for you, or in the future when working in a team, whatever your team prefers if they prefer a certain system. +A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. Use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. ```javascript // one.js -export default greeting = "Hello, odinite!"; -export const farewell = "Bye bye, odinite!"; +export default greeting = "Hello, Odinite!"; +export const farewell = "Bye bye, Odinite!"; ``` ```javascript @@ -167,9 +167,9 @@ import greeting, { farewell } from "./one.js";
-#### Named import/exports aren't the same as object literals! +#### Named imports/exports aren't the same as object literals! -Using `{ }` with named import/exports is special syntax, and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). +Using `{ }` with named imports/exports is special syntax and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). ```javascript export { greeting, farewell }; @@ -183,29 +183,29 @@ In the above, we are not exporting an object containing `greeting` and `farewell ### CommonJS -Along the way, you may have bumped into something called "CommonJS" (a.k.a. CJS), which uses syntax like `require` and `module.exports`. We use this for our JavaScript exercises from Foundations! This is a module system that was designed for use with NodeJS that works a little differently to ESM, and is not something that browsers will be able to understand. +Along the way, you may have bumped into something called "CommonJS" (a.k.a. CJS), which uses syntax like `require` and `module.exports`. We use this for our JavaScript exercises from Foundations! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. CJS is still used quite a lot in NodeJS code, though in recent years, ESM has become more popular there. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. ### npm -**npm** (no capitals!) is a package manager, a gigantic repository of plugins, libaries and other tools, which provides us a command-line tool we can use to install these tools (we call "packages") in our applications. Then we will have all our installed packages' code locally, which can then import into our own files. We can even publish our own code to npm! +**npm** (no capitals!) is a package manager, a gigantic repository of plugins, libaries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. Then we will have all our installed packages' code locally, which we can then import into our own files. We can even publish our own code to npm! You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. -As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This is even more so when we consider we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will talk through bundlers, a tool that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files (that do exactly the same thing) which will be sent to the browser instead. +As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This is even more so when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will talk through bundlers, a tool that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files (that do exactly the same thing) which will be sent to the browser instead. ### Assignment
1. As per usual, you can learn most about JavaScript keywords and concepts from the MDN docs, so check out the [docs on export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and [docs on import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). There are little extras about them we have not covered in this lesson, such as aliases and namespace imports. -1. Read a bit about npm, packages and dependencies: +1. Read a bit about npm, packages, and dependencies: 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. - 1. Any packages we install are called "dependencies", but if any package are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). + 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). 1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson.
@@ -214,7 +214,7 @@ As our applications get more complex and more and more files are needed (whether The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge. -- [Before ES6 modules, how would you privatise a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) +- [Before ES6 modules, how would you privatize a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) - [Before ES6 modules, how would you expose variables to be accessible in later files?](#before-es6-modules-the-global-scope-problem) - [What are some benefits of writing code in modules?](#introduction) - [What is an entry point?](#entry-point) @@ -227,5 +227,5 @@ The following questions are an opportunity to reflect on key topics in this less This section contains helpful links to related content. It isn't required, so consider it supplemental. -- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarises much of the ESM topics discussed in this lesson. At the end, he mentions about `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, and so you will not need to worry about browser compatibility for this. +- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, and so you will not need to worry about browser compatibility for this. - Here is a [brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). From ba4430a50fb321e306e2fb559cf8e85b223667c2 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 02:07:01 +0100 Subject: [PATCH 09/24] Overwrite existing es6 modules lesson --- .../es6_modules.md | 267 +++++++++++------- .../es6_modules_new.md | 231 --------------- 2 files changed, 158 insertions(+), 340 deletions(-) delete mode 100644 javascript/organizing_your_javascript_code/es6_modules_new.md diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 374a59a4f5f..876db6bb99a 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -1,182 +1,231 @@ ### Introduction -Separate from the **module pattern** that we discussed in an earlier lesson, "modules" is a feature that arrived with ES6. ES6 modules are starting to appear in many code bases around the net and getting them up and running will give us a chance to explore some new parts of the JavaScript ecosystem, so it's going to be a worthy excursion! +We've learned about the **module pattern** in a previous lesson and played around with using them to help organize our variables and functions. At some point in the last few projects, you may have even wondered, "How would we manage more complex projects? Files would get too long! It would be great if we could split our code up into multiple files for organization!". Using multiple files would be extremely handy, as we could more easily separate our code into groups of related functions and values without having to scroll through one ridiculously long file. -Don't be fooled! We're going to cover much more than just the new module syntax in this lesson! Before we can really *use* these modules, we're going to have to learn about **npm** and **webpack**, which are both topics that will be *very* useful to you even beyond this lesson. In the end, the modules themselves are simple to implement, so we're going to take this chance to learn about a few other things. +While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules" and thus they are often referred to as "ES6 modules" or "ESM". ### Lesson overview This section contains a general overview of topics that you will learn in this lesson. -- Explain what npm is and where it was commonly used before being adopted on the frontend. -- Describe what `npm init` does and what `package.json` is. -- Know how to install packages using npm. -- Describe what a JavaScript module bundler like webpack is. -- Explain what the concepts "entry" and "output" mean in relation to webpack. -- Briefly explain what a development dependency is. -- Explain what "transpiling code" means and how it relates to front-end development. -- Briefly describe what a task runner is and how it's used in front-end development. -- Describe how to write an npm automation script. -- Explain one of the main benefits of writing code in modules. -- Explain "named" exports and "default" exports. +- Explain what ES6 modules are and how to import and export from them. +- Describe the difference between default and named exports. +- Explain the main differences between CommonJS modules and ES6 modules. +- Understand what npm is. -### The history of JavaScript +### Before ES6 modules: The global scope problem -Why do we even need or want this stuff? What do you gain from all of this added complexity? These are good questions... with good answers. +
-- Read this little [history lesson on JavaScript, package managers, and bundling](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). It's long, but it puts what we're doing here in great perspective. This article is a bit older, and those who have coded along with the example have frequently run into issues, so we don't suggest that you code along (you'll be following along with the official Webpack documentation later). Nevertheless, this article is extremely important conceptually and really clarifies the 'WHY' of the rest of this lesson. +Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples, as they won't change how things work regarding the global scope and the module pattern, which is the primary point. -### npm - -The **node package manager** is a command-line tool that gives you access to a gigantic repository of plugins, libraries and tools. If you have done our Fundamentals course, you will probably have encountered it when you [installed the Jest testing framework](https://github.com/TheOdinProject/javascript-exercises#how-to-use-these-exercises) to do our exercises. +
-Read through the npm links below but don't worry about running any of the commands on your computer. This section is about growing your awareness of npm. You will have an opportunity to use what you learn here in upcoming projects. +Let's say we have two scripts, `one.js` and `two.js`, and we link them in our HTML as separate scripts. -1. Take a couple minutes to read the [About npm](https://docs.npmjs.com/getting-started/what-is-npm) page - a great introduction to npm. -1. This tutorial teaches you [how to install packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). -1. This tutorial covers [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), which you can use to manage your project's dependencies. -1. Read this article on [development dependencies](https://dev.to/moimikey/demystifying-devdependencies-and-dependencies-5ege) to learn what they are and how to use them. Note that when the author says "all required dependencies are pulled together and bundled", they are referring to any dependencies needed at runtime. Dependencies like Webpack (which we will cover shortly) are only used during development to build apps and so are not required at runtime. -1. If you run into trouble at any point you can check out [the official npm docs](https://docs.npmjs.com/) for more tutorials and documentation. +```html + + +``` -### Yarn? +```javascript +// one.js +const greeting = "Hello, Odinite!"; +``` -At some point, you will probably run into [Yarn](https://yarnpkg.com/en/) - a replacement for the default `npm`. For the most part, it does the same things, though it *does* have a few more features. Recent versions of `npm` have incorporated some of the best features of Yarn, so using it won't offer you any real advantages at this point in your career. It *is* a fine package manager, however, and may be worth your consideration in the future. +```javascript +// two.js +console.log(greeting); +``` -### Webpack and bundlers +When we open the HTML, we see `"Hello, Odinite!"` getting logged to the console, even though `greeting` was never defined in `two.js`! That's because the two scripts were loaded one after the other into the same global scope, as if we wrote only one file with the two lines in that order. If we put the `two.js` script tag first, we would instead get an error that `greeting is not defined`, as it would try to do the console log before we define the variable. -So far, your projects have had relatively basic file structures. As project complexity grows, so too will the benefits of well-organized code. A project consisting of a single, long file with lots of code can be made easier to navigate and maintain by being broken down into multiple smaller files (modules). Further benefits of writing code in modules will come below when we introduce ES6 modules. +This means that even if we use multiple JavaScript files, they will still end up sharing the same global scope. Our top-level variables are not safe! -But there's a problem! The browser would need to make a separate HTTP request for each file. The more files you have, the more costly this becomes, particularly on slower networks and would only increase if you also imported third-party libraries into your app. +Before ESM, we could wrap some things in an IIFE, which would cause it to run just the same, but now any variables inside them are scoped to that function and not globally. -What if we had a way to write multiple files and/or import multiple third-party libraries but eventually combine them all into fewer files at the end so the browser did not have to make so many requests? +```javascript +// one.js +(() => { + const greeting = "Hello, Odinite!"; +})(); +``` -Enter bundlers. Give a bundler a starting file (an entry point) and it will build a dependency graph of the modules and dependencies starting from that file, then combine them into a single output file. Provide multiple entry points and it will do the same for each separately. You can read more about [why we use bundlers and how they work](https://snipcart.com/blog/javascript-module-bundler) in this short article. +Now, we get an error in the console that `greeting is not defined`, because there is no global variable called `greeting` for us to log! But what if we wanted only *some* things to be exposed to other files? We can return those things from our IIFE into the global scope and keep the other things private! -Webpack is one such tool for bundling modules. There is a lot of talk across the net about how difficult and complex it is to set up and use, but at the moment our needs are few and the setup is basic enough. In fact, you can see an example of getting it up and running on the [front page of the Webpack website](https://webpack.js.org/). +```javascript +// one.js +const greeting = (() => { + const greetingString = "Hello, Odinite!"; + const farewellString = "Bye bye, Odinite!"; + return greetingString; +})(); +``` -Webpack *is* a very powerful tool, and with that power comes a decent amount of complexity. Don't let it scare you off! The basic configuration is not difficult and proficiency with webpack looks *amazing* on resumes. +Now, the global variable `greeting` will contain `"Hello, Odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to expose from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code across multiple files before we were given "real modules". -To get us started, we are going to refer to the official documentation. +But now, with ESM, we no longer need to use IIFEs for this specific purpose. -1. Code along with all of the steps of [Webpack's "Getting Started" tutorial](https://webpack.js.org/guides/getting-started/). +### ES6 modules -Let's discuss what's going on there. After installing webpack using npm, we set up a project that required an external library ([Lodash](https://lodash.com/)) using a ` ``` -There are *many* benefits to writing your code in modules. One of the most compelling is code reuse. If, for instance, you have written some functions that manipulate the DOM in a specific way, putting all of those into their own file as a 'module' means that you can copy that file and reuse it very easily! +Note that we did not need to link `one.js`, as the browser will handle that for us when it sees what `two.js` depends on. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. -There are also the same benefits as when using factory functions or the module pattern (the module pattern and ES6 modules are not the same things; this naming convention is frustrating). With the introduction of ES6 Modules, the module pattern (IIFEs) is not needed anymore, though you might still encounter them in the wild. When using ES6 modules, only what is exported can be accessed in other modules by importing. Additionally, any declarations made in a module are not automatically added to the global scope. By using ES6 modules, you can keep different parts of your code cleanly separated, which makes writing and maintaining your code much easier and less error-prone. Keep in mind that you can *definitely* export constructors, classes and factory functions from your modules. +But how do we actually import and export? Confusingly, there are two types of importing and exporting: `default` and `named`, and they can even be mixed and matched in the same file. -To pull it all together, let's write a module and then include it in our code. We are going to continue from where the webpack tutorial left off. Before beginning, your file directory should look something like this: +#### Default exports +**We can only default export a single "thing" from a single file.** Something default exported from a file does not have a name attached to it; when you import it somewhere, you can decide what to call it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can stick `export default` at the start of the thing to export when it's declared. Either way is fine. Note that if you `export default` a variable inline, `default` replaces `let`/`const`. + +Let's see about default exporting our `greeting` variable from the original `one.js` (no IIFE). + +```javascript +// one.js +const greeting = "Hello, Odinite!"; +export default greeting; + +// We could also default export it inline, like this +export default greeting = "Hello, Odinite!"; ``` -├── dist -│   ├── main.js -│   └── index.html -├── src -│   └── index.js -├── package-lock.json -├── package.json -└── webpack.config.js + +Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want. It doesn't have to be called `greeting` if you don't want it to be. We just have to give it a name and provide the path to the file we're importing from. + +```javascript +// two.js +import helloOdinite from "./one.js"; + +console.log(helloOdinite); // "Hello, Odinite!" ``` -In addition, you should be able to bundle and run webpack by typing `npx webpack` in the terminal, (or `npm run build` if you're using the example project created on the previous section.) . +But what if you had multiple separate things to export from `one.js`? -Add a new file to the `src` directory called `myName.js` with the following contents: +#### Named exports -``` javascript -const myName = (name) => 'Hi! My name is ' + name; +Named exports are actually exported with the name they were declared with, which means we have to import them by their name as well. We either do it inline like before just without `default` (meaning we need the `let`/`const` here) or add to the file an `export { }`, where the curly braces contain a list of the names of the things to export as named exports. -export default myName; +```javascript +// one.js +const greeting = "Hello, Odinite!"; +const farewell = "Bye bye, Odinite!"; +export { greeting, farewell }; + +// Or inline +export const greeting = "Hello, Odinite!"; +export const farewell = "Bye bye, Odinite!"; ``` -Then, in `src/index.js`, import and use your new function: +Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own! If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were exported as named exports. ```javascript -// import your function -import myName from './myName'; +// two.js +import { greeting, farewell } from "./one.js"; + +console.log(greeting); // "Hello, Odinite!" +console.log(farewell); // "Bye bye, Odinite!" +``` -function component() { -  const element = document.createElement('div'); +A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. Use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. -  // use your function! -  element.textContent = myName('Cody'); -  return element; -} +```javascript +// one.js +export default greeting = "Hello, Odinite!"; +export const farewell = "Bye bye, Odinite!"; +``` -document.body.appendChild(component()); +```javascript +// two.js +import greeting, { farewell } from "./one.js"; ``` -Easy! Now, if you run `npx webpack` in your project directory, your page should show our new function being used. +
-There are two different ways to use exports in your code: named exports and default exports. Which option you use depends on what you're exporting. Take a moment to look at the [MDN documentation about the export declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and the [MDN documentation about the import declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) which give great examples for the different syntax on import and export. +#### Named imports/exports aren't the same as object literals! -Here is an example with named exports, which you will most often use when you have multiple values to export in a module: +Using `{ }` with named imports/exports is special syntax and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). ```javascript -// a file called myModule.js -const functionOne = () => 'ONE'; -const functionTwo = () => 'TWO'; - -export { - functionOne, - functionTwo -}; +export { greeting, farewell }; + +import { greeting, farewell } from "./one.js"; ``` -And to import them: +In the above, we are not exporting an object containing `greeting` and `farewell` keys, nor are we destructuring an object with those keys when importing. We are just using named import/export syntax. -```javascript -// index.js in /src folder -import {functionOne, functionTwo} from './myModule'; -``` +
+ +### CommonJS + +Along the way, you may have bumped into something called "CommonJS" (a.k.a. CJS), which uses syntax like `require` and `module.exports`. We use this for our JavaScript exercises from Foundations! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. + +CJS is still used quite a lot in NodeJS code, though in recent years, ESM has become more popular there. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. + +### npm + +**npm** (no capitals!) is a package manager, a gigantic repository of plugins, libaries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. Then we will have all our installed packages' code locally, which we can then import into our own files. We can even publish our own code to npm! + +You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. + +If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. + +As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This is even more so when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will talk through bundlers, a tool that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files (that do exactly the same thing) which will be sent to the browser instead. + +### Assignment + +
+ +1. As per usual, you can learn most about JavaScript keywords and concepts from the MDN docs, so check out the [docs on export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and [docs on import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). There are little extras about them we have not covered in this lesson, such as aliases and namespace imports. +1. Read a bit about npm, packages, and dependencies: + 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). + 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. + 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). +1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson. -Using this pattern gives you the freedom to only import the functions you need in the various files of your program. So it's perfectly fine to only import `functionOne` if that's the only one you need. +
### Knowledge check -This section contains questions for you to check your understanding of this lesson. If you’re having trouble answering the questions below on your own, review the material above to find the answer. +The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge. -- [Explain what npm is and where it was commonly used before being adopted on the frontend.](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html) -- [Describe what `npm init` does and what `package.json` is.](https://docs.npmjs.com/creating-a-package-json-file) -- [Know how to install packages using npm.](https://docs.npmjs.com/downloading-and-installing-packages-locally) -- [Describe what a JavaScript module bundler like webpack is.](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html) -- [Explain what the concepts "entry" and "output" mean in relation to webpack.](#webpack-knowledge-check) -- [Briefly explain what a development dependency is.](https://dev.to/moimikey/demystifying-devdependencies-and-dependencies-5ege) -- [Explain what "transpiling code" means and how it relates to frontend development.](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html) -- [Briefly describe what a task runner is and how it's used in frontend development.](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html) -- [Describe how to write an npm automation script.](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html) -- [Explain one of the main benefits of writing code in modules.](#module-knowledge-check) -- [Explain "named exports" and "default exports".](#exports-knowledge-check) +- [Before ES6 modules, how would you privatize a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) +- [Before ES6 modules, how would you expose variables to be accessible in later files?](#before-es6-modules-the-global-scope-problem) +- [What are some benefits of writing code in modules?](#introduction) +- [What is an entry point?](#entry-point) +- [How do you link a module script in HTML?](#entry-point) +- [What is the difference between default and named exports?](#default-exports) +- [What is npm?](#npm) +- [What file does npm use that contains all information about dependencies?](https://docs.npmjs.com/creating-a-package-json-file) ### Additional resources -This section contains helpful links to other content. It isn’t required, so consider it supplemental. +This section contains helpful links to related content. It isn't required, so consider it supplemental. -- Watch this video about [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) if you find video lessons easier to absorb. It covers the same topics as discussed in this lesson. -- Here is [a brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). +- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, and so you will not need to worry about browser compatibility for this. +- Here is a [brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). diff --git a/javascript/organizing_your_javascript_code/es6_modules_new.md b/javascript/organizing_your_javascript_code/es6_modules_new.md deleted file mode 100644 index 876db6bb99a..00000000000 --- a/javascript/organizing_your_javascript_code/es6_modules_new.md +++ /dev/null @@ -1,231 +0,0 @@ -### Introduction - -We've learned about the **module pattern** in a previous lesson and played around with using them to help organize our variables and functions. At some point in the last few projects, you may have even wondered, "How would we manage more complex projects? Files would get too long! It would be great if we could split our code up into multiple files for organization!". Using multiple files would be extremely handy, as we could more easily separate our code into groups of related functions and values without having to scroll through one ridiculously long file. - -While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules" and thus they are often referred to as "ES6 modules" or "ESM". - -### Lesson overview - -This section contains a general overview of topics that you will learn in this lesson. - -- Explain what ES6 modules are and how to import and export from them. -- Describe the difference between default and named exports. -- Explain the main differences between CommonJS modules and ES6 modules. -- Understand what npm is. - -### Before ES6 modules: The global scope problem - -
- -Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples, as they won't change how things work regarding the global scope and the module pattern, which is the primary point. - -
- -Let's say we have two scripts, `one.js` and `two.js`, and we link them in our HTML as separate scripts. - -```html - - -``` - -```javascript -// one.js -const greeting = "Hello, Odinite!"; -``` - -```javascript -// two.js -console.log(greeting); -``` - -When we open the HTML, we see `"Hello, Odinite!"` getting logged to the console, even though `greeting` was never defined in `two.js`! That's because the two scripts were loaded one after the other into the same global scope, as if we wrote only one file with the two lines in that order. If we put the `two.js` script tag first, we would instead get an error that `greeting is not defined`, as it would try to do the console log before we define the variable. - -This means that even if we use multiple JavaScript files, they will still end up sharing the same global scope. Our top-level variables are not safe! - -Before ESM, we could wrap some things in an IIFE, which would cause it to run just the same, but now any variables inside them are scoped to that function and not globally. - -```javascript -// one.js -(() => { - const greeting = "Hello, Odinite!"; -})(); -``` - -Now, we get an error in the console that `greeting is not defined`, because there is no global variable called `greeting` for us to log! But what if we wanted only *some* things to be exposed to other files? We can return those things from our IIFE into the global scope and keep the other things private! - -```javascript -// one.js -const greeting = (() => { - const greetingString = "Hello, Odinite!"; - const farewellString = "Bye bye, Odinite!"; - return greetingString; -})(); -``` - -Now, the global variable `greeting` will contain `"Hello, Odinite!"` and so our code from `two.js` successfully logs this to the console. However, our private `farewellString` variable is not global, so that cannot be accessed anywhere in `two.js`. Through this, we are able to choose what to expose from one file to be made available to all files that follow it! This is why IIFEs were often called the "module pattern", because they allowed us to write modular code across multiple files before we were given "real modules". - -But now, with ESM, we no longer need to use IIFEs for this specific purpose. - -### ES6 modules - -With ESM, we have a little more control over things. Each file has its own private scope by default, and not only can we choose what things we export from that file, we can also choose what things we import into other files. So just because we export something, it doesn't mean it's automatically available elsewhere; it will only be available in another file if we explicitly import it there. Lots of control! - -
- -#### Module scope is not the global scope - -When using ESM, each module has its own private scope, where we use import/export to communicate between files. A top-level variable in a module will not be accessible in the global scope. - -
- -#### Entry point - -When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. - -Take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: - -```text - depends on -two.js <----------- one.js -``` - -Therefore, `two.js` is our entry point. When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead loaded `one.js` as our entry point, the browser would see that it does not depend on any other files, and so leave it at that. Our code from `two.js` would be ignored, and nothing gets logged! - -You can add external scripts to HTML as ESM by adding only the appropriate entry point file, like this: - -```html - -``` - -Note that we did not need to link `one.js`, as the browser will handle that for us when it sees what `two.js` depends on. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. - -But how do we actually import and export? Confusingly, there are two types of importing and exporting: `default` and `named`, and they can even be mixed and matched in the same file. - -#### Default exports - -**We can only default export a single "thing" from a single file.** Something default exported from a file does not have a name attached to it; when you import it somewhere, you can decide what to call it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can stick `export default` at the start of the thing to export when it's declared. Either way is fine. Note that if you `export default` a variable inline, `default` replaces `let`/`const`. - -Let's see about default exporting our `greeting` variable from the original `one.js` (no IIFE). - -```javascript -// one.js -const greeting = "Hello, Odinite!"; -export default greeting; - -// We could also default export it inline, like this -export default greeting = "Hello, Odinite!"; -``` - -Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want. It doesn't have to be called `greeting` if you don't want it to be. We just have to give it a name and provide the path to the file we're importing from. - -```javascript -// two.js -import helloOdinite from "./one.js"; - -console.log(helloOdinite); // "Hello, Odinite!" -``` - -But what if you had multiple separate things to export from `one.js`? - -#### Named exports - -Named exports are actually exported with the name they were declared with, which means we have to import them by their name as well. We either do it inline like before just without `default` (meaning we need the `let`/`const` here) or add to the file an `export { }`, where the curly braces contain a list of the names of the things to export as named exports. - -```javascript -// one.js -const greeting = "Hello, Odinite!"; -const farewell = "Bye bye, Odinite!"; -export { greeting, farewell }; - -// Or inline -export const greeting = "Hello, Odinite!"; -export const farewell = "Bye bye, Odinite!"; -``` - -Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own! If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were exported as named exports. - -```javascript -// two.js -import { greeting, farewell } from "./one.js"; - -console.log(greeting); // "Hello, Odinite!" -console.log(farewell); // "Bye bye, Odinite!" -``` - -A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. Use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. - -```javascript -// one.js -export default greeting = "Hello, Odinite!"; -export const farewell = "Bye bye, Odinite!"; -``` - -```javascript -// two.js -import greeting, { farewell } from "./one.js"; -``` - -
- -#### Named imports/exports aren't the same as object literals! - -Using `{ }` with named imports/exports is special syntax and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). - -```javascript -export { greeting, farewell }; - -import { greeting, farewell } from "./one.js"; -``` - -In the above, we are not exporting an object containing `greeting` and `farewell` keys, nor are we destructuring an object with those keys when importing. We are just using named import/export syntax. - -
- -### CommonJS - -Along the way, you may have bumped into something called "CommonJS" (a.k.a. CJS), which uses syntax like `require` and `module.exports`. We use this for our JavaScript exercises from Foundations! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. - -CJS is still used quite a lot in NodeJS code, though in recent years, ESM has become more popular there. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. - -### npm - -**npm** (no capitals!) is a package manager, a gigantic repository of plugins, libaries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. Then we will have all our installed packages' code locally, which we can then import into our own files. We can even publish our own code to npm! - -You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. - -If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. - -As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This is even more so when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will talk through bundlers, a tool that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files (that do exactly the same thing) which will be sent to the browser instead. - -### Assignment - -
- -1. As per usual, you can learn most about JavaScript keywords and concepts from the MDN docs, so check out the [docs on export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and [docs on import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). There are little extras about them we have not covered in this lesson, such as aliases and namespace imports. -1. Read a bit about npm, packages, and dependencies: - 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). - 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. - 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). -1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson. - -
- -### Knowledge check - -The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge. - -- [Before ES6 modules, how would you privatize a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) -- [Before ES6 modules, how would you expose variables to be accessible in later files?](#before-es6-modules-the-global-scope-problem) -- [What are some benefits of writing code in modules?](#introduction) -- [What is an entry point?](#entry-point) -- [How do you link a module script in HTML?](#entry-point) -- [What is the difference between default and named exports?](#default-exports) -- [What is npm?](#npm) -- [What file does npm use that contains all information about dependencies?](https://docs.npmjs.com/creating-a-package-json-file) - -### Additional resources - -This section contains helpful links to related content. It isn't required, so consider it supplemental. - -- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, and so you will not need to worry about browser compatibility for this. -- Here is a [brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). From d954214810d69dcf17fda57c69f6889caf5409a0 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 02:17:23 +0100 Subject: [PATCH 10/24] Add co-author Co-authored-by: advait0603 From 2bc027739911fb24a904488f0f915f4bb7c7f25f Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 02:29:56 +0100 Subject: [PATCH 11/24] Clarify single default/named export decisions --- javascript/organizing_your_javascript_code/es6_modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 876db6bb99a..fb4f89164fb 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -152,7 +152,7 @@ console.log(greeting); // "Hello, Odinite!" console.log(farewell); // "Bye bye, Odinite!" ``` -A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. Use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. +A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. ```javascript // one.js From d517fc1eca86af6d6b7b463300878cb2226a8dac Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 06:38:10 +0100 Subject: [PATCH 12/24] Tweak verbiage, grammar and spelling. --- .../es6_modules.md | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index fb4f89164fb..5fbd6386701 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -17,7 +17,7 @@ This section contains a general overview of topics that you will learn in this l
-Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples, as they won't change how things work regarding the global scope and the module pattern, which is the primary point. +Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples, as they won't change how things work regarding the global scope and the module pattern, which is the main focus of this section.
@@ -47,7 +47,7 @@ Before ESM, we could wrap some things in an IIFE, which would cause it to run ju ```javascript // one.js (() => { - const greeting = "Hello, Odinite!"; + const greeting = "Hello, Odinite!"; })(); ``` @@ -56,9 +56,9 @@ Now, we get an error in the console that `greeting is not defined`, because ther ```javascript // one.js const greeting = (() => { - const greetingString = "Hello, Odinite!"; - const farewellString = "Bye bye, Odinite!"; - return greetingString; + const greetingString = "Hello, Odinite!"; + const farewellString = "Bye bye, Odinite!"; + return greetingString; })(); ``` @@ -78,34 +78,32 @@ When using ESM, each module has its own private scope, where we use import/expor
-#### Entry point +#### Entry points When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. -Take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: +```html + +``` + +Why is `two.js` our entry point? Take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: ```text depends on two.js <----------- one.js ``` -Therefore, `two.js` is our entry point. When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead loaded `one.js` as our entry point, the browser would see that it does not depend on any other files, and so leave it at that. Our code from `two.js` would be ignored, and nothing gets logged! - -You can add external scripts to HTML as ESM by adding only the appropriate entry point file, like this: - -```html - -``` +When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead used `one.js` as our entry point, the browser would see that it does not depend on any other files, and so would do nothing else. Our code from `two.js` would not be used, and nothing would get logged! -Note that we did not need to link `one.js`, as the browser will handle that for us when it sees what `two.js` depends on. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. +Note that we only needed the one script tag as the browser handles the additional file dependencies for us. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. -But how do we actually import and export? Confusingly, there are two types of importing and exporting: `default` and `named`, and they can even be mixed and matched in the same file. +But how do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. #### Default exports -**We can only default export a single "thing" from a single file.** Something default exported from a file does not have a name attached to it; when you import it somewhere, you can decide what to call it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can stick `export default` at the start of the thing to export when it's declared. Either way is fine. Note that if you `export default` a variable inline, `default` replaces `let`/`const`. +We can only default export a single "thing" from a single file. Something default exported from a file does not have a name attached to it; when you import it somewhere, you can decide what to name to give it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can do it inline by putting `export default` in front of the thing to export when it's declared. Either way is fine. Note that if you default export something inline, the `default` keyword replaces `let`/`const`. -Let's see about default exporting our `greeting` variable from the original `one.js` (no IIFE). +Let's see about default exporting our `greeting` variable from our original `one.js` (no IIFE). ```javascript // one.js @@ -116,7 +114,7 @@ export default greeting; export default greeting = "Hello, Odinite!"; ``` -Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want. It doesn't have to be called `greeting` if you don't want it to be. We just have to give it a name and provide the path to the file we're importing from. +Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want. It doesn't have to be called `greeting` if we don't want it to be. We just have to give it a name, then provide the path to the file we're importing from. ```javascript // two.js @@ -142,7 +140,7 @@ export const greeting = "Hello, Odinite!"; export const farewell = "Bye bye, Odinite!"; ``` -Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own! If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were exported as named exports. +Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own. If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were named exports. ```javascript // two.js @@ -152,7 +150,7 @@ console.log(greeting); // "Hello, Odinite!" console.log(farewell); // "Bye bye, Odinite!" ``` -A file can both export something as a default export and any number of named exports. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. +A file can both default export something and named export any number of other things at the same time. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. ```javascript // one.js @@ -189,13 +187,13 @@ CJS is still used quite a lot in NodeJS code, though in recent years, ESM has be ### npm -**npm** (no capitals!) is a package manager, a gigantic repository of plugins, libaries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. Then we will have all our installed packages' code locally, which we can then import into our own files. We can even publish our own code to npm! +**npm** (no capitals!) is a package manager - a gigantic repository of plugins, libraries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. We will then have all our installed packages' code locally, which we can import into our own files. We could even publish our own code to npm! You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. -As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This is even more so when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will talk through bundlers, a tool that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files (that do exactly the same thing) which will be sent to the browser instead. +As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This can get even more troublesome when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will introduce bundlers, tools that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files which will ultimately be sent to the browser instead. ### Assignment @@ -217,8 +215,8 @@ The following questions are an opportunity to reflect on key topics in this less - [Before ES6 modules, how would you privatize a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) - [Before ES6 modules, how would you expose variables to be accessible in later files?](#before-es6-modules-the-global-scope-problem) - [What are some benefits of writing code in modules?](#introduction) -- [What is an entry point?](#entry-point) -- [How do you link a module script in HTML?](#entry-point) +- [What is an entry point?](#entry-points) +- [How do you link a module script in HTML?](#entry-points) - [What is the difference between default and named exports?](#default-exports) - [What is npm?](#npm) - [What file does npm use that contains all information about dependencies?](https://docs.npmjs.com/creating-a-package-json-file) From e24ecd0e55bd415b7ecad88de10cf3e0e8cddb48 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 07:13:55 +0100 Subject: [PATCH 13/24] Switch order of named and default exports subsections Introducing named exports first allowed for a subjectively more natural flow to introducing the concepts. Named exports felt easier to introduce first, while default exports felt easier to introduce by comparing to named exports. --- .../es6_modules.md | 94 +++++++++---------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 5fbd6386701..3a176235481 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -1,6 +1,6 @@ ### Introduction -We've learned about the **module pattern** in a previous lesson and played around with using them to help organize our variables and functions. At some point in the last few projects, you may have even wondered, "How would we manage more complex projects? Files would get too long! It would be great if we could split our code up into multiple files for organization!". Using multiple files would be extremely handy, as we could more easily separate our code into groups of related functions and values without having to scroll through one ridiculously long file. +We've learned about the **module pattern** in a previous lesson and played around with using them to help organize our variables and functions. At some point in the last few projects, you may have even wondered, "How would we manage more complex projects? Files would get too long! It would be great if we could split our code up into multiple files for organization!". Using multiple files would be extremely handy for this exact reason. While the module pattern used to play a big part in helping us manage this, the release of ES6 (sometimes referred to as ES2015) gave us actual "modules" and thus they are often referred to as "ES6 modules" or "ESM". @@ -17,7 +17,7 @@ This section contains a general overview of topics that you will learn in this l
-Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples, as they won't change how things work regarding the global scope and the module pattern, which is the main focus of this section. +Even though `let`/`const` and arrow functions were not around before ES6, we will still use them in our pre-ES6 examples. They won't change how things work regarding the global scope and the module pattern, which is the main focus of this section.
@@ -86,11 +86,11 @@ When we use ESM, instead of adding every JavaScript file to our HTML in order, w ``` -Why is `two.js` our entry point? Take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: +Why is `two.js` our entry point? Let's take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: ```text - depends on -two.js <----------- one.js +importer depends on exporter +two.js <-------------- one.js ``` When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead used `one.js` as our entry point, the browser would see that it does not depend on any other files, and so would do nothing else. Our code from `two.js` would not be used, and nothing would get logged! @@ -99,91 +99,89 @@ Note that we only needed the one script tag as the browser handles the additiona But how do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. -#### Default exports - -We can only default export a single "thing" from a single file. Something default exported from a file does not have a name attached to it; when you import it somewhere, you can decide what to name to give it when importing. To export something from a file as a default export, we either add to the file `export default XXXXXX`, where `XXXXXX` is the name of the thing we want to export, or we can do it inline by putting `export default` in front of the thing to export when it's declared. Either way is fine. Note that if you default export something inline, the `default` keyword replaces `let`/`const`. +#### Named exports -Let's see about default exporting our `greeting` variable from our original `one.js` (no IIFE). +To export something as a **named export**, we can either stick the `export` keyword in front of its declaration, or add an `export { }` somewhere in the file (typically the end), where the curly braces contain a list of the names of the things to export. Either method is fine to use, and we can export as many things as we liked as named exports. ```javascript // one.js -const greeting = "Hello, Odinite!"; -export default greeting; +export const greeting = "Hello, Odinite!"; +export const farewell = "Bye bye, Odinite!"; -// We could also default export it inline, like this -export default greeting = "Hello, Odinite!"; +// Or on a separate line +const greeting = "Hello, Odinite!"; +const farewell = "Bye bye, Odinite!"; +export { greeting, farewell }; ``` -Now in our `two.js`, we can default import that string! Remember, since we're importing something that was default exported, we can name it whatever we want. It doesn't have to be called `greeting` if we don't want it to be. We just have to give it a name, then provide the path to the file we're importing from. +Now to import these variables in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own. If another file needed the `farewell` variable (or both), then that file could import what it needs. Don't import it? Can't use it. To do named imports, we must specify the names of the things we want to import inside `{ }` and provide the path to the file we're importing from. ```javascript // two.js -import helloOdinite from "./one.js"; +import { greeting, farewell } from "./one.js"; -console.log(helloOdinite); // "Hello, Odinite!" +console.log(greeting); // "Hello, Odinite!" +console.log(farewell); // "Bye bye, Odinite!" ``` -But what if you had multiple separate things to export from `one.js`? +
-#### Named exports +#### Named imports/exports aren't the same as object literals! -Named exports are actually exported with the name they were declared with, which means we have to import them by their name as well. We either do it inline like before just without `default` (meaning we need the `let`/`const` here) or add to the file an `export { }`, where the curly braces contain a list of the names of the things to export as named exports. +Using `{ }` with named imports/exports is special syntax and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). ```javascript -// one.js -const greeting = "Hello, Odinite!"; -const farewell = "Bye bye, Odinite!"; export { greeting, farewell }; -// Or inline -export const greeting = "Hello, Odinite!"; -export const farewell = "Bye bye, Odinite!"; +import { greeting, farewell } from "./one.js"; ``` -Now to import these named exports in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own. If another file needed the `farewell` variable (or both), then that file could import what it needs. The `{ }` specifies that the things inside were named exports. +In the above, we are not exporting an object containing `greeting` and `farewell` keys, nor are we destructuring an object with those keys when importing. We are just using named import/export syntax. -```javascript -// two.js -import { greeting, farewell } from "./one.js"; +
-console.log(greeting); // "Hello, Odinite!" -console.log(farewell); // "Bye bye, Odinite!" -``` +#### Default exports + +In contrast to named exports, a file can only default export a single thing. Something exported this way does not have a name attached to it, so when you import it somewhere, you can decide what name to give it. -A file can both default export something and named export any number of other things at the same time. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever works for you, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. +To export something from a file as a default export, we can also do it inline by prepending `export default` to the appropriate declaration, or we can export it at the end of the file, this time *without* any curly braces. Again, either way is perfectly fine. Note that if you do an inline default export, if you would normally declare with `let` or `const`, the `default` keyword *replaces* `let`/`const`. ```javascript // one.js export default greeting = "Hello, Odinite!"; -export const farewell = "Bye bye, Odinite!"; + +// Or on a separate line +const greeting = "Hello, Odinite!"; +export default greeting; ``` +Now in our `two.js`, we can default import that string. Remember, since we're importing something that was default exported, we can name it whatever we want. Even though the variable was called `greeting` in `one.js`, we don't have to call it that in `two.js` if we don't want to. When default importing, we don't use curly braces, which are for named importing. + ```javascript // two.js -import greeting, { farewell } from "./one.js"; -``` - -
+import helloOdinite from "./one.js"; -#### Named imports/exports aren't the same as object literals! +console.log(helloOdinite); // "Hello, Odinite!" +``` -Using `{ }` with named imports/exports is special syntax and is not related in any way to declaring object literals or [destructuring objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring). +You can use both default and named exports in the same file. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever you prefer, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. ```javascript -export { greeting, farewell }; - -import { greeting, farewell } from "./one.js"; +// one.js +export default greeting = "Hello, Odinite!"; +export const farewell = "Bye bye, Odinite!"; ``` -In the above, we are not exporting an object containing `greeting` and `farewell` keys, nor are we destructuring an object with those keys when importing. We are just using named import/export syntax. - -
+```javascript +// two.js +import greeting, { farewell } from "./one.js"; +``` ### CommonJS -Along the way, you may have bumped into something called "CommonJS" (a.k.a. CJS), which uses syntax like `require` and `module.exports`. We use this for our JavaScript exercises from Foundations! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. +Along the way, you may have bumped into something called CommonJS (CJS), which uses syntax like `require` and `module.exports`. You may remember seeing this in our JavaScript exercises in the Foundations course (you've come a long way)! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. -CJS is still used quite a lot in NodeJS code, though in recent years, ESM has become more popular there. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. +CJS is still used quite a lot in NodeJS code, though in recent years, ESM in NodeJS has been gaining popularity. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. ### npm From d3ba452d775447d52b12b02242b75f6c61f48124 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 11 May 2024 04:27:33 +0100 Subject: [PATCH 14/24] Expand dependency exmaples with >2 files --- .../organizing_your_javascript_code/es6_modules.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 3a176235481..9ac2dfa99f3 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -95,6 +95,19 @@ two.js <-------------- one.js When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead used `one.js` as our entry point, the browser would see that it does not depend on any other files, and so would do nothing else. Our code from `two.js` would not be used, and nothing would get logged! +If we had another file, `three.js`, that exported something and `two.js` imported from it, then `two.js` would still be our entry point, now depending on both `one.js` and `three.js`. + +```text +two.js <-------------- one.js + └------- three.js +``` + +Or perhaps instead of `two.js`, `one.js` imports from `three.js`. In which case, `two.js` would still be our entry point and depend on `three.js` indirectly through `one.js`. + +```text +two.js <-------------- one.js <-------------- three.js +``` + Note that we only needed the one script tag as the browser handles the additional file dependencies for us. We also did not need to add the `defer` attribute, as `type="module"` automatically defers script execution for us. But how do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. From 8c0b8211d3c3fe6ac21f7b601953e6042702419c Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 11 May 2024 04:28:50 +0100 Subject: [PATCH 15/24] Add note softening package.json assignment step Co-authored-by: advait0603 --- javascript/organizing_your_javascript_code/es6_modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 9ac2dfa99f3..4667c23ef1d 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -213,7 +213,7 @@ As our applications get more complex and more and more files are needed (whether 1. As per usual, you can learn most about JavaScript keywords and concepts from the MDN docs, so check out the [docs on export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and [docs on import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). There are little extras about them we have not covered in this lesson, such as aliases and namespace imports. 1. Read a bit about npm, packages, and dependencies: 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). - 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. + 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. Don't worry too much with the details, just know what its basic function is, as it will help with the next few lessons and beyond. 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). 1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson. From 9a64b7946f60fcd70776c9fd5a638087ee0d9f48 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sun, 26 May 2024 19:24:58 +0100 Subject: [PATCH 16/24] Add note on import module name and string type --- javascript/organizing_your_javascript_code/es6_modules.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 4667c23ef1d..aed98f438db 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -127,7 +127,9 @@ const farewell = "Bye bye, Odinite!"; export { greeting, farewell }; ``` -Now to import these variables in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own. If another file needed the `farewell` variable (or both), then that file could import what it needs. Don't import it? Can't use it. To do named imports, we must specify the names of the things we want to import inside `{ }` and provide the path to the file we're importing from. +Now to import these variables in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own. If another file needed the `farewell` variable (or both), then that file could import what it needs. Don't import it? Can't use it. To do named imports, we must specify the names of the things we want to import inside `{ }` and provide the path to the file we're importing from (when we deal with importing third-party libraries later, you can just use the name of the library instead of a full file path). + +Note that [you cannot use template strings for the file path](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#module-name), only single or double quoted strings. ```javascript // two.js From 2a900ec1e151702b05454e160fea7381f085f809 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:17:35 +0100 Subject: [PATCH 17/24] Separate export examples to individual code blocks --- .../organizing_your_javascript_code/es6_modules.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 2a4e2ec550b..4267069686a 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -120,8 +120,12 @@ To export something as a **named export**, we can either stick the `export` keyw // one.js export const greeting = "Hello, Odinite!"; export const farewell = "Bye bye, Odinite!"; +``` + +Or on a separate line: -// Or on a separate line +```javascript +// one.js const greeting = "Hello, Odinite!"; const farewell = "Bye bye, Odinite!"; export { greeting, farewell }; @@ -164,8 +168,12 @@ To export something from a file as a default export, we can also do it inline by ```javascript // one.js export default greeting = "Hello, Odinite!"; +``` + +Or on a separate line: -// Or on a separate line +```javascript +// one.js const greeting = "Hello, Odinite!"; export default greeting; ``` From 4a92245ff85d42f41069effc6a96aed281a79f6f Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:19:02 +0100 Subject: [PATCH 18/24] Use npm package link for npm name sentence --- javascript/organizing_your_javascript_code/es6_modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 4267069686a..8bdc2545c5b 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -210,7 +210,7 @@ CJS is still used quite a lot in NodeJS code, though in recent years, ESM in Nod **npm** (no capitals!) is a package manager - a gigantic repository of plugins, libraries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. We will then have all our installed packages' code locally, which we can import into our own files. We could even publish our own code to npm! -You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://twitter.com/npmjs/status/105690425242820608), though you will often see it referred to as such. +You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://www.npmjs.com/package/npm#is-npm-an-acronym-for-node-package-manager), though you will often see it referred to as such. If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. From 207b34ae969333346daa4b28cdfb16d9d2e75c57 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:24:14 +0100 Subject: [PATCH 19/24] Move npm contents to separate lesson file --- .../es6_modules.md | 20 +-------- .../organizing_your_javascript_code/npm.md | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 javascript/organizing_your_javascript_code/npm.md diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 8bdc2545c5b..5da2c16b4c2 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -11,7 +11,6 @@ This section contains a general overview of topics that you will learn in this l - Explain what ES6 modules are and how to import and export from them. - Describe the difference between default and named exports. - Explain the main differences between CommonJS modules and ES6 modules. -- Understand what npm is. ### Before ES6 modules: The global scope problem @@ -206,26 +205,11 @@ Along the way, you may have bumped into something called CommonJS (CJS), which u CJS is still used quite a lot in NodeJS code, though in recent years, ESM in NodeJS has been gaining popularity. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. -### npm - -**npm** (no capitals!) is a package manager - a gigantic repository of plugins, libraries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. We will then have all our installed packages' code locally, which we can import into our own files. We could even publish our own code to npm! - -You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://www.npmjs.com/package/npm#is-npm-an-acronym-for-node-package-manager), though you will often see it referred to as such. - -If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. - -As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This can get even more troublesome when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will introduce bundlers, tools that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files which will ultimately be sent to the browser instead. - ### Assignment
1. As per usual, you can learn most about JavaScript keywords and concepts from the MDN docs, so check out the [docs on export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and [docs on import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). There are little extras about them we have not covered in this lesson, such as aliases and namespace imports. -1. Read a bit about npm, packages, and dependencies: - 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). - 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. Don't worry too much with the details, just know what its basic function is, as it will help with the next few lessons and beyond. - 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). -1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson.
@@ -239,12 +223,10 @@ The following questions are an opportunity to reflect on key topics in this less - [What is an entry point?](#entry-points) - [How do you link a module script in HTML?](#entry-points) - [What is the difference between default and named exports?](#default-exports) -- [What is npm?](#npm) -- [What file does npm use that contains all information about dependencies?](https://docs.npmjs.com/creating-a-package-json-file) ### Additional resources This section contains helpful links to related content. It isn't required, so consider it supplemental. -- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, and so you will not need to worry about browser compatibility for this. +- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, so you will not need to worry about browser compatibility for this. - Here is a [brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). diff --git a/javascript/organizing_your_javascript_code/npm.md b/javascript/organizing_your_javascript_code/npm.md new file mode 100644 index 00000000000..85ee2923ba5 --- /dev/null +++ b/javascript/organizing_your_javascript_code/npm.md @@ -0,0 +1,45 @@ +### Introduction + +INTRO + +### Lesson overview + +This section contains a general overview of topics that you will learn in this lesson. + +- Understand what npm is. +- Understand the purpose of the `package.json` file. + +### npm + +**npm** (no capitals!) is a package manager - a gigantic repository of plugins, libraries, and other tools, which provides us with a command-line tool we can use to install these tools (that we call "packages") in our applications. We will then have all our installed packages' code locally, which we can import into our own files. We could even publish our own code to npm! + +You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://www.npmjs.com/package/npm#is-npm-an-acronym-for-node-package-manager), though you will often see it referred to as such. + +If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. + +As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This can get even more troublesome when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will introduce bundlers, tools that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files which will ultimately be sent to the browser instead. + +### Assignment + +
+ +1. Read a bit about npm, packages, and dependencies: + 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). + 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. Don't worry too much with the details, just know what its basic function is, as it will help with the next few lessons and beyond. + 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). +1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson. + +
+ +### Knowledge check + +The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge. + +- [What is npm?](#npm) +- [What file does npm use that contains all information about dependencies?](https://docs.npmjs.com/creating-a-package-json-file) + +### Additional resources + +This section contains helpful links to related content. It isn't required, so consider it supplemental. + +- It looks like this lesson doesn't have any additional resources yet. Help us expand this section by contributing to our curriculum. From ff2ab2f3aeeca14e5c36135cfde630ee701887e7 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:46:14 +0100 Subject: [PATCH 20/24] Add intro and package.json section to npm lesson --- .../organizing_your_javascript_code/npm.md | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/javascript/organizing_your_javascript_code/npm.md b/javascript/organizing_your_javascript_code/npm.md index 85ee2923ba5..f85775b8d64 100644 --- a/javascript/organizing_your_javascript_code/npm.md +++ b/javascript/organizing_your_javascript_code/npm.md @@ -1,6 +1,6 @@ ### Introduction -INTRO +In the previous lesson, we learned about ES6 modules and the syntax used for importing and exporting things between modules. As we build bigger, more complex applications, we may not want to write *everything* ourselves. We may want to import third party code to handle some things for us, which can range from helper functions other people wrote, to entire frameworks for us to build our application within. To find and import these third party packages with ease, we need the help of a package manager such as npm! ### Lesson overview @@ -15,17 +15,45 @@ This section contains a general overview of topics that you will learn in this l You may recall installing npm in the Foundations course in order to install the Jest testing framework to do the JavaScript exercises. Funnily enough, [npm does not stand for "Node Package Manager"](https://www.npmjs.com/package/npm#is-npm-an-acronym-for-node-package-manager), though you will often see it referred to as such. -If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, an alternative package manager. For this course, we will be using npm. +If you are in the Full Stack Ruby on Rails pathway, you will have already been introduced to Yarn, another JavaScript package manager. For this course, we will be using npm. -As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This can get even more troublesome when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will introduce bundlers, tools that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files which will ultimately be sent to the browser instead. +As our applications get more complex and more and more files are needed (whether they are our own files or files from packages we've installed and imported), managing many of these dependencies can become rather troublesome, especially when packages get updated. This can get even more troublesome when we consider that we may end up sending *many* JavaScript files to the browser to download. In the next lesson, we will introduce bundlers, tools that lets us write multiple files that are better for us to work with, then bundle them together into fewer smaller files which will ultimately be sent to the browser instead. + +### package.json + +npm revolves around a file called `package.json`. It's a JSON file containing information about our project, such as its name or any dependencies and their version numbers. npm can read this file and do things such as install all of the listed dependencies with the correct versions, and running commands that you've set as an npm script (we will cover npm scripts in a later lesson). + +For example, here is the `package.json` file for The Odin Project's curriculum repo that houses all of the lesson files (including this lesson you are doing right now): + +```json +{ + "name": "curriculum", + "version": "1.0.0", + "description": "[The Odin Project](https://www.theodinproject.com/) (TOP) is an open-source curriculum for learning full-stack web development. Our curriculum is divided into distinct courses, each covering the subject language in depth. Each course contains a listing of lessons interspersed with multiple projects. These projects give users the opportunity to practice what they are learning, thereby reinforcing and solidifying the theoretical knowledge learned in the lessons. Completed projects may then be included in the user's portfolio.", + "scripts": { + "lint:lesson": "markdownlint-cli2 --config lesson.markdownlint-cli2.jsonc", + "lint:project": "markdownlint-cli2 --config project.markdownlint-cli2.jsonc", + "fix:lesson": "markdownlint-cli2 --fix --config lesson.markdownlint-cli2.jsonc", + "fix:project": "markdownlint-cli2 --fix --config project.markdownlint-cli2.jsonc" + }, + "license": "CC BY-NC-SA 4.0", + "devDependencies": { + "markdownlint-cli2": "^0.12.1" + } +} +``` + +There's a lot of stuff here and we don't need to understand it all yet. The point is that if you were to clone the curriculum repo, if you ran `npm install`, npm would read this `package.json` file and see that it needs to install the `markdownlint-cli2` package. Once this package is installed, you'll be able to run any of the four npm scripts that use that package. The curriculum repo itself does not actually contain the code for the `markdownlint-cli2` package, as anyone cloning the repo can just run `npm install` to let npm grab the code for them. + +In our own projects, as we use npm to install new packages (or uninstall any!), it will automatically update our `package.json` with any new details. We will see this in action in the next lesson when we introduce module bundling using a package called Webpack. ### Assignment
-1. Read a bit about npm, packages, and dependencies: +1. Read a bit more about npm, packages, and dependencies: 1. [Installing packages with npm](https://docs.npmjs.com/downloading-and-installing-packages-locally). - 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our app, including all the packages installed in it. npm uses this file to do things like install the right packages, update to the correct versions etc. Don't worry too much with the details, just know what its basic function is, as it will help with the next few lessons and beyond. + 1. Read about [the `package.json` file](https://docs.npmjs.com/creating-a-package-json-file), the file that stores much of the information for our application. 1. Any packages we install are called "dependencies", but if any packages are only used during the development process and their code is not needed for the user-facing app (such as the Jest testing framework), we call them [development dependencies](https://dev.to/mshertzberg/demystifying-devdependencies-and-dependencies-5ege). 1. Here is a great little [history lesson about JavaScript and managing packages across multiple files](https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html). Only read up to "Using a JavaScript module bundler (webpack)", as we will cover bundlers and webpack in the next lesson. From 2d6e51215725fa54d4e3f37076aa7fbc5a5068ba Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:58:06 +0100 Subject: [PATCH 21/24] Move entry point section to after import/export sections --- .../es6_modules.md | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 5da2c16b4c2..7fca44d180a 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -77,40 +77,6 @@ When using ESM, each module has its own private scope, where we use import/expor
-#### Entry points - -When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. - -```html - -``` - -Why is `two.js` our entry point? Let's take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: - -```text -importer depends on exporter -two.js <-------------- one.js -``` - -When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead used `one.js` as our entry point, the browser would see that it does not depend on any other files, and so would do nothing else. Our code from `two.js` would not be used, and nothing would get logged! - -If we had another file, `three.js`, that exported something and `two.js` imported from it, then `two.js` would still be our entry point, now depending on both `one.js` and `three.js`. - -```text -two.js <-------------- one.js - └------- three.js -``` - -Or perhaps instead of `two.js`, `one.js` imports from `three.js`. In which case, `two.js` would still be our entry point and depend on `three.js` indirectly through `one.js`. - -```text -two.js <-------------- one.js <-------------- three.js -``` - -Note that we only needed the one script tag, as the browser will handle the additional file dependencies for us. We also did not need to add the `defer` attribute, as `type="module"` will automatically defer script execution for us. - -But how do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. - #### Named exports To export something as a **named export**, we can either stick the `export` keyword in front of its declaration, or add an `export { }` somewhere in the file (typically the end), where the curly braces contain a list of the names of the things to export. Either method is fine to use, and we can export as many things as we liked as named exports. @@ -199,6 +165,40 @@ export const farewell = "Bye bye, Odinite!"; import greeting, { farewell } from "./one.js"; ``` +### Entry points + +When we use ESM, instead of adding every JavaScript file to our HTML in order, we only need to link a single file - the **entry point**. + +```html + +``` + +Why is `two.js` our entry point? Let's take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: + +```text +importer depends on exporter +two.js <-------------- one.js +``` + +When we load `two.js` as a module, the browser will see that it depends on `one.js` and load the code from that file as well. If we instead used `one.js` as our entry point, the browser would see that it does not depend on any other files, and so would do nothing else. Our code from `two.js` would not be used, and nothing would get logged! + +If we had another file, `three.js`, that exported something and `two.js` imported from it, then `two.js` would still be our entry point, now depending on both `one.js` and `three.js`. + +```text +two.js <-------------- one.js + └------- three.js +``` + +Or perhaps instead of `two.js`, `one.js` imports from `three.js`. In which case, `two.js` would still be our entry point and depend on `three.js` indirectly through `one.js`. + +```text +two.js <-------------- one.js <-------------- three.js +``` + +Note that we only needed the one script tag, as the browser will handle the additional file dependencies for us. We also did not need to add the `defer` attribute, as `type="module"` will automatically defer script execution for us. + +But how do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. + ### CommonJS Along the way, you may have bumped into something called CommonJS (CJS), which uses syntax like `require` and `module.exports`. You may remember seeing this in our JavaScript exercises in the Foundations course (you've come a long way)! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. From c9e9e43645d2007ecf511894f3e1b374a754084b Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:58:43 +0100 Subject: [PATCH 22/24] Amend import/export verbiage to account for new section order Import/export syntax to be taught first, then the examples can be used to explain entry points more clearly. --- .../es6_modules.md | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 7fca44d180a..ce998e17d90 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -77,8 +77,14 @@ When using ESM, each module has its own private scope, where we use import/expor
+### Import and export + +How do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. + #### Named exports +Let's use our `one.js` and `two.js` examples from before. First, we'll need to export our greeting and farewell strings from `one.js`. + To export something as a **named export**, we can either stick the `export` keyword in front of its declaration, or add an `export { }` somewhere in the file (typically the end), where the curly braces contain a list of the names of the things to export. Either method is fine to use, and we can export as many things as we liked as named exports. ```javascript @@ -98,7 +104,7 @@ export { greeting, farewell }; Now to import these variables in `two.js`! Remember that we can control what we import, so if we only need the `greeting` variable, we could just import that on its own. If another file needed the `farewell` variable (or both), then that file could import what it needs. Don't import it? Can't use it. To do named imports, we must specify the names of the things we want to import inside `{ }` and provide the path to the file we're importing from (when we deal with importing third-party libraries later, you can just use the name of the library instead of a full file path). -Note that [you cannot use template strings for the file path](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#module-name), only single or double quoted strings. +Note that [you cannot use template strings for the file path](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#module-name), only single or double-quoted strings. ```javascript // two.js @@ -130,6 +136,8 @@ In contrast to named exports, a file can only default export a single thing. Som To export something from a file as a default export, we can also do it inline by prepending `export default` to the appropriate declaration, or we can export it at the end of the file, this time *without* any curly braces. Again, either way is perfectly fine. Note that if you do an inline default export, if you would normally declare with `let` or `const`, the `default` keyword *replaces* `let`/`const`. +Let's default export our greeting string from `one.js`. + ```javascript // one.js export default greeting = "Hello, Odinite!"; @@ -152,7 +160,9 @@ import helloOdinite from "./one.js"; console.log(helloOdinite); // "Hello, Odinite!" ``` -You can use both default and named exports in the same file. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever you prefer, or in the future, when working in a team, whatever your team prefers if they prefer a certain system. +You can use both default and named exports in the same file. Confusingly enough, there isn't really a universally agreed-upon rule for when to use either, outside of the fact that a file can have multiple named exports but only one default export. When it comes to only needing to export a single thing from a module, some people prefer using a default export whereas some prefer using a single named export. Both work so use whatever you prefer, or if working in a team, whatever the team prefers. + +Let's default export the greeting string from `one.js`, and export the farewell string as a named export. ```javascript // one.js @@ -160,9 +170,14 @@ export default greeting = "Hello, Odinite!"; export const farewell = "Bye bye, Odinite!"; ``` +We can then import them both in `two.js`. We need to default import the greeting string (which also means we can name it whatever we want) and named import the farewell string. + ```javascript // two.js import greeting, { farewell } from "./one.js"; + +console.log(greeting); // "Hello, Odinite!" +console.log(farewell); // "Bye bye, Odinite!" ``` ### Entry points @@ -197,8 +212,6 @@ two.js <-------------- one.js <-------------- three.js Note that we only needed the one script tag, as the browser will handle the additional file dependencies for us. We also did not need to add the `defer` attribute, as `type="module"` will automatically defer script execution for us. -But how do we actually import and export? In true JavaScript fashion, we don't have just one but two types of importing and exporting: `default` and `named`, and they essentially do the same kind of thing but very slightly differently. They can even be mixed and matched in the same file. - ### CommonJS Along the way, you may have bumped into something called CommonJS (CJS), which uses syntax like `require` and `module.exports`. You may remember seeing this in our JavaScript exercises in the Foundations course (you've come a long way)! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. From 7f0d03e928665d79dce996f3437d67518c978ce4 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 22 Jun 2024 22:04:08 +0100 Subject: [PATCH 23/24] Adjust verbiage for entry points section to account for new section order --- javascript/organizing_your_javascript_code/es6_modules.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index ce998e17d90..1c8101345c5 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -188,7 +188,7 @@ When we use ESM, instead of adding every JavaScript file to our HTML in order, w ``` -Why is `two.js` our entry point? Let's take our original `one.js` and `two.js` example and pretend we've written the import/exports using ES6 module syntax (we'll get to that shortly). `two.js` depends on `one.js` for the `greeting` variable, so we have the following **dependency graph**: +Why is `two.js` our entry point? Well, in our above examples, `two.js` imports variables from `one.js`, meaning `two.js` depends on `one.js`, so we have the following **dependency graph**: ```text importer depends on exporter @@ -233,13 +233,13 @@ The following questions are an opportunity to reflect on key topics in this less - [Before ES6 modules, how would you privatize a variable from being accessible in other files?](#before-es6-modules-the-global-scope-problem) - [Before ES6 modules, how would you expose variables to be accessible in later files?](#before-es6-modules-the-global-scope-problem) - [What are some benefits of writing code in modules?](#introduction) +- [What is the difference between default and named exports?](#default-exports) - [What is an entry point?](#entry-points) - [How do you link a module script in HTML?](#entry-points) -- [What is the difference between default and named exports?](#default-exports) ### Additional resources This section contains helpful links to related content. It isn't required, so consider it supplemental. -- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, ESM is supported by nearly every browser, certainly ones that will be in common use, so you will not need to worry about browser compatibility for this. +- This video on [ES6 Modules by Web Dev Simplified](https://youtu.be/cRHQNNcYf6s) summarizes much of the ESM topics discussed in this lesson. At the end, he mentions `nomodule` and support for older browsers that were unable to support ESM. Nowadays, this is not a concern as ESM is supported by basically every browser in common use. - Here is a [brief comparison of CommonJS modules and ES6 modules](https://blog.logrocket.com/commonjs-vs-es-modules-node-js/). From 387607dd60cd3379b4348b5480b810d8021809b2 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:25:55 +0100 Subject: [PATCH 24/24] Change NodeJS to Node.js Node.js is more accurate. --- javascript/organizing_your_javascript_code/es6_modules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index 1c8101345c5..38e3479fe15 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -214,9 +214,9 @@ Note that we only needed the one script tag, as the browser will handle the addi ### CommonJS -Along the way, you may have bumped into something called CommonJS (CJS), which uses syntax like `require` and `module.exports`. You may remember seeing this in our JavaScript exercises in the Foundations course (you've come a long way)! This is a module system that was designed for use with NodeJS that works a little differently than ESM, and is not something that browsers will be able to understand. +Along the way, you may have bumped into something called CommonJS (CJS), which uses syntax like `require` and `module.exports` instead of `import` and `export`. You may remember seeing this in our JavaScript exercises in the Foundations course (you've come a long way)! This is a module system that was designed for use with Node.js that works a little differently than ESM, and is not something that browsers will be able to understand. -CJS is still used quite a lot in NodeJS code, though in recent years, ESM in NodeJS has been gaining popularity. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the NodeJS course. +CJS is still used quite a lot in Node.js code, though in recent years, ESM in Node.js has been gaining popularity. For the time being, we are focused on writing code to run in the browser, so we will be spending time with ESM. If you are taking the Full Stack JavaScript pathway, then we will cover CJS in more detail later in the Node.js course. ### Assignment