diff --git a/javascript/organizing_your_javascript_code/es6_modules.md b/javascript/organizing_your_javascript_code/es6_modules.md index cc3f3d36a8d..38e3479fe15 100644 --- a/javascript/organizing_your_javascript_code/es6_modules.md +++ b/javascript/organizing_your_javascript_code/es6_modules.md @@ -1,183 +1,245 @@ ### 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 for this exact reason. -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. -### 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. They won't change how things work regarding the global scope and the module pattern, which is the main focus of this section. -### 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. +Let's say we have two scripts, `one.js` and `two.js`, and we link them in our HTML as separate scripts. -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. +```html + + +``` + +```javascript +// one.js +const greeting = "Hello, Odinite!"; +``` + +```javascript +// two.js +console.log(greeting); +``` -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. +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. -### Yarn? +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! -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. +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. -### Webpack and bundlers +```javascript +// one.js +(() => { + const greeting = "Hello, Odinite!"; +})(); +``` -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. +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! -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. +```javascript +// one.js +const greeting = (() => { + const greetingString = "Hello, Odinite!"; + const farewellString = "Bye bye, Odinite!"; + return greetingString; +})(); +``` -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? +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". -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. +But now, with ESM, we no longer need to use IIFEs for this specific purpose. -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/). +### ES6 modules -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. +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! -To get us started, we are going to refer to the official documentation. +
-1. Code along with all of the steps of [Webpack's "Getting Started" tutorial](https://webpack.js.org/guides/getting-started/). +#### Module scope is not the global scope -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 ` ``` -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. +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 +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. + +### CommonJS + +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 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 + +
+ +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. + +
### 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. -- [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 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) ### Additional resources 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, 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/). diff --git a/javascript/organizing_your_javascript_code/npm.md b/javascript/organizing_your_javascript_code/npm.md new file mode 100644 index 00000000000..f85775b8d64 --- /dev/null +++ b/javascript/organizing_your_javascript_code/npm.md @@ -0,0 +1,73 @@ +### Introduction + +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 + +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, 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'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 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 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. + +
+ +### 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.