From b733a695f5e311923e2d65b9bd253036811ca19f Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 10:24:16 +0100 Subject: [PATCH 01/31] Write intro and LO items Lesson structure and key concepts mostly raised by Advait. Co-authored-by: advait0603 --- .../webpack_part_1.md | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 javascript/organizing_your_javascript_code/webpack_part_1.md diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md new file mode 100644 index 00000000000..3a422575ee6 --- /dev/null +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -0,0 +1,38 @@ +### Introduction + +In the previous lesson, we introduced ES6 modules (ESM) and npm. While the introduction of ESM greatly mitigated some of the issues with managing individual script files and dependencies, there would still be performance issues to consider the more module files the browser would have to download individually (especially as more third party libraries would be imported). Fortunately, more recent web technologies have greatly improved these aspects, but bundlers still provide us with a lot of power to process and optimize our code in various ways. This power, however, does come with a small cost of needing to configure a bundler. For now, our needs are few and simple, and we can look at the basic things one at a time. + +Awareness of and basic experience with bundlers are valuable. While in recent years, new build tools have come out that handle a lot of basic configuration for us, in the real world, you may not always get a chance to use these tools. It's very reasonable to end up working with codebases that use tools that require more manual configuration. Even if you did get to work with tools that handle more things for you, it's useful to understand what those tools are actually doing for you. + +### Lesson overview + +This section contains a general overview of topics that you will learn in this lesson. + +- Explain the purpose of bundlers and how they work. +- Configure Webpack to bundle JavaScript modules. +- Configure Webpack to deal with non-JavaScript files during bundling, including with HtmlWebpackPlugin. +- Set up Webpack's development server. + +### Bundling + +### Webpack + +### HTML-webpack-plugin + +### 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. + +- + +### 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 814d70ac99ad32fa6a6a01e1d9a5f324d3c39119 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 11:05:29 +0100 Subject: [PATCH 02/31] Write general bundling intro section --- .../organizing_your_javascript_code/webpack_part_1.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 3a422575ee6..a287252beaa 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -15,8 +15,14 @@ This section contains a general overview of topics that you will learn in this l ### Bundling +In the previous lesson, we learnt what an **entry point** was, what a **dependency graph** was, and how to add an entry point file to HTML as a module script. With bundling, the same concepts of entry points and dependency graphs apply. We provide the bundler with an entry point and it builds a dependency graph from that file, combines all relevant files together, then outputs a single file with all the necessary code included. + +While it does this, we could also get it to do a whole bunch of other things, such as [minifying our code](https://en.wikipedia.org/wiki/Minification_(programming)), image optimizations, or even ["tree shaking"](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) (detecting and removing unused code within a bundle). Most of these extra optimizations are out of the scope of this course; we will instead be focusing on getting a bundler called Webpack set up to bundle JavaScript, and handle HTML, CSS, and assets (such as images). + ### Webpack + + ### HTML-webpack-plugin ### Assignment From 7dad7d41218f87e31af258c21e932a57a7afcf9d Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 12:37:54 +0100 Subject: [PATCH 03/31] Begin webpack tutorial section --- .../webpack_part_1.md | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index a287252beaa..0d9c1310285 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -15,13 +15,39 @@ This section contains a general overview of topics that you will learn in this l ### Bundling -In the previous lesson, we learnt what an **entry point** was, what a **dependency graph** was, and how to add an entry point file to HTML as a module script. With bundling, the same concepts of entry points and dependency graphs apply. We provide the bundler with an entry point and it builds a dependency graph from that file, combines all relevant files together, then outputs a single file with all the necessary code included. +In the previous lesson, we learned what an **entry point** is, what a **dependency graph** is, and how to add an entry point file to HTML as a module script. With bundling, the same concepts of entry points and dependency graphs apply: we provide the bundler with an entry point and it builds a dependency graph from that file, combines all relevant files together, then outputs a single file with all the necessary code included. -While it does this, we could also get it to do a whole bunch of other things, such as [minifying our code](https://en.wikipedia.org/wiki/Minification_(programming)), image optimizations, or even ["tree shaking"](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) (detecting and removing unused code within a bundle). Most of these extra optimizations are out of the scope of this course; we will instead be focusing on getting a bundler called Webpack set up to bundle JavaScript, and handle HTML, CSS, and assets (such as images). +While it does this, we could also get it to do a whole bunch of other things, such as [minifying our code](https://en.wikipedia.org/wiki/Minification_(programming)), image optimizations, or even ["tree shaking"](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). Most of these extra optimizations are out of the scope of this course; we will instead be focusing on basic bundling of JavaScript, while handling HTML, CSS, and assets (such as images). ### Webpack +Webpack is one of the most popular JavaScript bundlers, if not the most popular one, and has been for a long time. Let's get started with bundling! +We'll first need to make a new directory for our practice app, then create a `package.json` file in it for npm to record information about packages we use (like Webpack). Run the following commands in your terminal: + +```bash +mkdir webpack-practice +cd webpack-practice +npm init -y +``` + +Once inside your new directory, we can go ahead and install Webpack, which involves two packages. + +```bash +npm install --save-dev webpack webpack-cli +``` + +Note that we included the `--save-dev` flag (you can also use `-D` as a shortcut), which tells npm to record our two packages as development dependencies. We will only be using Webpack during development. The actual code run in the browser will not include any Webpack code. + +
+ +#### src and dist + +When dealing with Webpack (and often with any other bundler or build tool), we have two very important directories: `src` (short for "source") and `dist` (short for "distribution"). We could technically call these directories whatever we want, but these names are convention. + +`src` is where we keep all of our website's source code, essentially where all of our work will be done (with an exception being altering any configuration files in the root of the project). When we run Webpack to bundle our code, it will output the bundled files into the `dist` directory. The idea is that if someone was to fork or clone the project, they would not need the `dist` directory, as they'd just be able to run Webpack to build from `src` into their own `dist`. Similarly, to deploy our website, we would only need the `dist` code and nothing else. Keep that in mind! Work inside `src`, build into and deploy from `dist`! + +
### HTML-webpack-plugin From ecafbfe74297df94b4dbc0c35146795b93fdc2e3 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 13:16:59 +0100 Subject: [PATCH 04/31] Add upcoming section headings --- .../organizing_your_javascript_code/webpack_part_1.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 0d9c1310285..a87c71bddde 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -49,7 +49,15 @@ When dealing with Webpack (and often with any other bundler or build tool), we h -### HTML-webpack-plugin +### Bundling JavaScript + +### Loading CSS + +### Handling HTML + +### Loading images + +### Webpack dev server ### Assignment From f189421a7065647a55860c9082e3bc726d3b5a54 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 13:53:53 +0100 Subject: [PATCH 05/31] Write JS bundling instructions --- .../webpack_part_1.md | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index a87c71bddde..052229380ee 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -37,7 +37,9 @@ Once inside your new directory, we can go ahead and install Webpack, which invol npm install --save-dev webpack webpack-cli ``` -Note that we included the `--save-dev` flag (you can also use `-D` as a shortcut), which tells npm to record our two packages as development dependencies. We will only be using Webpack during development. The actual code run in the browser will not include any Webpack code. +Note that we included the `--save-dev` flag (you can also use `-D` as a shortcut), which tells npm to record our two packages as development dependencies. We will only be using Webpack during development. The actual code run that makes Webpack run will not be a part of the code that the browser will run. + +Also notice that when these finished installing, a `node_modules` directory and a `package-lock.json` got auto-generated. `node_modules` is where Webpack's actual code (and a whole bunch of other stuff) lives, and `package-lock.json` is just another file npm uses to track package information.
@@ -51,10 +53,70 @@ When dealing with Webpack (and often with any other bundler or build tool), we h ### Bundling JavaScript -### Loading CSS +Now that we've installed Webpack in our project directory, let's create a `src` directory with two JavaScript files inside it: `index.js` and `greeting.js`. + +```bash +mkdir src && touch src/index.js src/greeting.js +``` + +Inside our two JavaScript files, we'll have the following: + +```javascript +// index.js +import { greeting } from "./greeting.js"; + +console.log(greeting); +``` + +```javascript +// greeting.js +export const greeting = "Hello, Odinite!"; +``` + +Great, now we have an `index.js` that imports from, and so depends on, `greeting.js`. In order to bundle this, we'll also want a Webpack configuration file which will contain all the details we need for bundling, such as the entry point, the output destination, and anything like plugins and loaders (which we will cover shortly). + +Back in your project root (so outside of `src`), create a `webpack.config.js` file that contains the following: + +```javascript +// webpack.config.js +const path = require("path"); + +module.exports = { + mode: "development", + entry: "./src/index.js", + output: { + filename: "main.js", + path: path.resolve(__dirname, "dist"), + clean: true, + }, +}; +``` + +Yes, you may have noticed this file uses CommonJS (CJS) syntax instead of ESM. That's because this file (and Webpack itself) runs in NodeJS and not the browser. By default, NodeJS uses CJS syntax, and the configuration file also contains some CJS-specific things. We need not worry about this - this is just stuff we need for Webpack to do it's thing. + +You'll notice the exported object containing a few key sections: + +- `mode`: For now, we will just leave this in development mode, as it will be more useful to us. We will revisit this and production mode in a later lesson. +- `entry`: A file path from the config file to whichever file is our entry point, which in this case is `src/index.js`. +- `output`: An object containing information about the output bundle. + - `filename`: The name of the output bundle - it can be anything you want. + - `path`: The path to the output directory, in this case, `dist`. If this directory doesn't already exist when we run Webpack, it will automatically create it for us as well. Don't worry too much about why we have the `path.resolve` part - this is just the way Webpack recommends we specify the output directory. + - `clean`: If we include this option and set it to `true`, then each time we run Webpack to bundle, it will empty the output directory first before bundling the files into it. This helps us keep `dist` clean so it only contains the files produced by the most recent bundling. + +With these files all in place, let's run Webpack and see what happens! + +```bash +npx webpack +``` + +You should see that Webpack has created a `dist` directory for us containing a `main.js` file! Inside this file is...a lot of stuff... Don't worry, most of this stuff is just for development tools we will use later. If you go ahead and run this file with `node dist/main.js`, you should see `Hello, Odinite!` get logged in the terminal. + +Congratulations! You've just made your first bundle with Webpack! ### Handling HTML +### Loading CSS + ### Loading images ### Webpack dev server From f8442d76de62b563b7716f293033b07bc4ffdfec Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 15:31:10 +0100 Subject: [PATCH 06/31] Add HtmlWebpackPlugin setup instructions --- .../webpack_part_1.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 052229380ee..120ba90058d 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -115,6 +115,43 @@ Congratulations! You've just made your first bundle with Webpack! ### Handling HTML +Let's actually include some HTML. After all, we're interested in making websites! Since HTML isn't JavaScript, Webpack can't just bundle it straight away, but there's a nifty tool we can use called `HtmlWebpackPlugin` that's just perfect for us. + +Run the following command to install HtmlWebpackPlugin (also as a dev dependency): + +```bash +npm install --save-dev html-webpack-plugin +``` + +We should also create an `template.html` (you can name this whatever you want) inside `src`, and fill that with the usual HTML boilerplate. **We do not need to add a script tag in this file!** HtmlWebpackPlugin will automatically add our output bundle as a script tag; we wouldn't want to double up by including our own one too! Inside our `webpack.config.js`, we can add a few little bits. + +```javascript +// webpack.config.js +const path = require("path"); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: "development", + entry: "./src/index.js", + output: { + filename: "main.js", + path: path.resolve(__dirname, "dist"), + clean: true, + }, + plugins: [ + new HtmlWebpackPlugin({ template: './src/template.html' }), + ], +}; +``` + +All we're doing here is making sure our Webpack configuration has access to HtmlWebpackPlugin, then we add it as a plugin to the configuration object. Inside HtmlWebpackPlugin function call, we pass in any options. For now, we're only interested in the `template` option. + +If we provide the path to our `src/template.html` file as a template, when we run `npx webpack` again, you'll notice our `dist` directory not only contains a `main.js` file but an `index.html` file as well. You'll also notice that HtmlWebpackPlugin has automatically added a deferred script tag to our `main.js` bundle file - what a darling! If you open this file in the browser and check the browser console, you should see our lovely `"Hello, Odinite!"` string logged. + +We've now successfully configured Webpack to handle our HTML file and inject the appropriate script tag. Any changes to HTML we make, we can just rerun Webpack to generate fresh `dist` code. + +Let's see how we'd handle CSS. + ### Loading CSS ### Loading images From 795d210b9708f5aa2ccc9097b5c4e6411c0849ff Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 18:30:13 +0100 Subject: [PATCH 07/31] Write CSS loading sections --- .../webpack_part_1.md | 81 +++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 120ba90058d..29fa7c72264 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -23,11 +23,11 @@ While it does this, we could also get it to do a whole bunch of other things, su Webpack is one of the most popular JavaScript bundlers, if not the most popular one, and has been for a long time. Let's get started with bundling! -We'll first need to make a new directory for our practice app, then create a `package.json` file in it for npm to record information about packages we use (like Webpack). Run the following commands in your terminal: +We'll first need to make a new directory for our practice app, then create a `package.json` file in it for npm to record information about packages we use (like Webpack). Run the following in your terminal: ```bash -mkdir webpack-practice -cd webpack-practice +mkdir webpack-practice && +cd webpack-practice && npm init -y ``` @@ -123,12 +123,12 @@ Run the following command to install HtmlWebpackPlugin (also as a dev dependency npm install --save-dev html-webpack-plugin ``` -We should also create an `template.html` (you can name this whatever you want) inside `src`, and fill that with the usual HTML boilerplate. **We do not need to add a script tag in this file!** HtmlWebpackPlugin will automatically add our output bundle as a script tag; we wouldn't want to double up by including our own one too! Inside our `webpack.config.js`, we can add a few little bits. +We should also create a `template.html` inside `src` (you can name this file whatever you want), and fill that with the usual HTML boilerplate. **We do not need to add a script tag in this file!** HtmlWebpackPlugin will automatically add our output bundle as a script tag. We wouldn't want to double up by including our own one too! Inside our `webpack.config.js`, we can add a few little bits. ```javascript // webpack.config.js const path = require("path"); -const HtmlWebpackPlugin = require('html-webpack-plugin'); +const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { mode: "development", @@ -139,7 +139,7 @@ module.exports = { clean: true, }, plugins: [ - new HtmlWebpackPlugin({ template: './src/template.html' }), + new HtmlWebpackPlugin({ template: "./src/template.html" }), ], }; ``` @@ -154,6 +154,75 @@ Let's see how we'd handle CSS. ### Loading CSS +We don't just need one new package for CSS, we need *two*. Gosh, what a greedy little thing... Let's install them. + +```bash +npm install --save-dev style-loader css-loader +``` + +`css-loader` will read any CSS files we import in a JavaScript file and store the result in a string. `style-loader` then takes that string and actually adds the JavaScript code that will apply those styles to the page. Therefore, we need both. + +Back in our `webpack.config.js`, we need to add these loaders so Webpack knows what to do. Since these aren't plugins, they go in a separate section: + +```javascript +// webpack.config.js +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); + +module.exports = { + mode: "development", + entry: "./src/index.js", + output: { + filename: "main.js", + path: path.resolve(__dirname, "dist"), + clean: true, + }, + plugins: [ + new HtmlWebpackPlugin({ template: "./src/template.html" }), + ], + module: { + rules: [ + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + ], + }, +}; +``` + +All this does is tell Webpack that if it encounters an imported file ending with `.css`, it should use the listed loaders to process that CSS file. + +
+ +#### Loader order matters! + +Notice how we put `css-loader` **at the end** of the array. We **must** set this order and not the reverse. + +Webpack will run the loaders starting at the end, so we want it to read the CSS file into a string with `css-loader` first, then use `style-loader` to inject the JavaScript that applies the CSS in that string to the page. It wouldn't work the same if we told it to do things back-to-front now. + +
+ +Now that Webpack knows what to do with imported CSS files, let's add some CSS! Create a `src/styles.css` with the following: + +```css +// styles.css +body { + background-color: rebeccapurple; +} +``` + +You can now import your CSS file into one of your JavaScript files. `src/index.js` makes sense. We don't need anything from the imported CSS file itself. Since our CSS and style loaders will handle all of that for us, we can just use a [side effect import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#import_a_module_for_its_side_effects_only). + +```javascript +import "./styles.css"; +import { greeting } from "./greeting.js"; + +console.log(greeting); +``` + +Once again, rebundle with Webpack using `npx webpack`, then open `dist/index.html` and enjoy the beautiful purple screen! + ### Loading images ### Webpack dev server From 934aaafc804b8832fe13ec12a76a05acc62ba6ae Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Thu, 9 May 2024 18:39:51 +0100 Subject: [PATCH 08/31] Set out image loading subsections --- .../webpack_part_1.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 29fa7c72264..ad0d7e3f6b4 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -225,6 +225,22 @@ Once again, rebundle with Webpack using `npx webpack`, then open `dist/index.htm ### Loading images +We're nearly done with the main Webpack configuration! If we have any image files we want to include within our website, they will also require a little extra configuration since they're not JavaScript files. + +There are three different ways images you'll likely be dealing with images with Webpack: + +1. Image files used in our CSS inside `url()`. +1. Image files we reference in our HTML template, e.g. as the `src` of an ``. +1. Images we use in our JavaScript, where will will need to import the image files. + +#### Images used in CSS files + +Lucky us! `css-loader` already handles this for us, so there's nothing extra to do for image paths in CSS! + +#### Images used in our HTML template + +#### Images used in JavaScript + ### Webpack dev server ### Assignment From 5a0bd0a534d8bc889e68db4aa60b3bc3950e00f9 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 14:45:17 +0100 Subject: [PATCH 09/31] Write html-loader instructions --- .../webpack_part_1.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index ad0d7e3f6b4..94a1ec51afc 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -239,6 +239,43 @@ Lucky us! `css-loader` already handles this for us, so there's nothing extra to #### Images used in our HTML template +Currently, if we were to use a local image file in our HTML template, for example ``, HtmlWebpackPlugin would have no idea that the string `"./odin.png"` references a file, let alone what that file is and where it lives. If only there was a tool that could figure these things out! + +```bash +npm install --save-dev html-loader +``` + +```javascript +// webpack.config.js +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); + +module.exports = { + mode: "development", + entry: "./src/index.js", + output: { + filename: "main.js", + path: path.resolve(__dirname, "dist"), + clean: true, + }, + plugins: [ + new HtmlWebpackPlugin({ template: "./src/template.html" }), + ], + module: { + rules: [ + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + { + test: /\.html$/i, + loader: 'html-loader', + }, + ], + }, +}; +``` + #### Images used in JavaScript ### Webpack dev server From b8fe052268eafedcb204d91647784920b9fada8d Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 22:00:43 +0100 Subject: [PATCH 10/31] Restructure Webpack image handling section --- .../webpack_part_1.md | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 94a1ec51afc..87caaab399a 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -225,25 +225,48 @@ Once again, rebundle with Webpack using `npx webpack`, then open `dist/index.htm ### Loading images -We're nearly done with the main Webpack configuration! If we have any image files we want to include within our website, they will also require a little extra configuration since they're not JavaScript files. +We're nearly done with the main Webpack configuration! If we have any local image files we want to include within our website, they will also require a little extra configuration since they're not JavaScript files. -There are three different ways images you'll likely be dealing with images with Webpack: +There are three different ways you could be dealing with local image files: -1. Image files used in our CSS inside `url()`. -1. Image files we reference in our HTML template, e.g. as the `src` of an ``. -1. Images we use in our JavaScript, where will will need to import the image files. +1. **Image files used in our CSS inside `url()`** + Lucky us! `css-loader` already handles this for us, so there's nothing extra to do for image paths in CSS! +1. **Image files we reference in our HTML template, e.g. as the `src` of an ``** + We need to install and tell Webpack to use something called `html-loader`, which will detect image file paths in our HTML template and load the right image files for us. Without this, `./odin.png` would just be a bit of text that will no longer reference the correct file once we run Webpack to build into `dist`. We can install it with `npm install --save-dev html-loader`, then add the following object to the `modules.rules` array within `webpack.config.js`: -#### Images used in CSS files + ```javascript + { + test: /\.html$/i, + loader: 'html-loader', + }, + ``` -Lucky us! `css-loader` already handles this for us, so there's nothing extra to do for image paths in CSS! +1. **Images we use in our JavaScript, where we will need to import the files** + If we need to use a local image file in our JavaScript, for example manipulating the DOM to create or edit `img` elements and set their `src` attribute, we need to import the images into our JavaScript module. Since images aren't JavaScript, we need to tell Webpack that these files will be assets by adding an `asset/resource` rule. No need to install anything here, just add the following object to the `modules.rules` array within `webpack.config.js`: -#### Images used in our HTML template + ```javascript + { + test: /\.(png|svg|jpg|jpeg|gif)$/i, + type: "asset/resource", + } + ``` -Currently, if we were to use a local image file in our HTML template, for example ``, HtmlWebpackPlugin would have no idea that the string `"./odin.png"` references a file, let alone what that file is and where it lives. If only there was a tool that could figure these things out! + You can always edit the regex in the `test` property to remove any file extensions you don't need, or add any extensions you do need. What's shown above is straight from [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/#loading-images) and will recognise most commonly used image file extensions. -```bash -npm install --save-dev html-loader -``` + Then in whatever JavaScript module we want to use that image in, we just have to default import it. + + ```javascript + import odinImage from "./odin.png"; + + const image = document.createElement("img"); + image.src = odinImage; + + document.body.appendChild(image); + ``` + + We have to import it so that the `odinImage` variable contains the correct file path, even when we bundle into `dist`. If we just wrote `image.src = "./odin.png";`, then the "file path" would just be a plain string. When we bundle into `dist`, Webpack will not magically recognise this string in our JavaScript references a file, and will not include it in the bundle. When we import it and set the correct `asset/resource` rule, Webpack will recognise the import, include the image file when we bundle, and also make sure the imported variable contains the correct file path at the end. + +After all that, if we added both `html-loader` and the image `asset/resource` rule, our `webpack.config.js` would look something like this: ```javascript // webpack.config.js @@ -271,13 +294,15 @@ module.exports = { test: /\.html$/i, loader: 'html-loader', }, + { + test: /\.(png|svg|jpg|jpeg|gif)$/i, + type: "asset/resource", + } ], }, }; ``` -#### Images used in JavaScript - ### Webpack dev server ### Assignment From 26c831634e6636adf4cad318177c1e3bcc6fb522 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 22:14:18 +0100 Subject: [PATCH 11/31] Add note on necessity of loaders/plugins --- .../webpack_part_1.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 87caaab399a..f21b41b5681 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -238,7 +238,7 @@ There are three different ways you could be dealing with local image files: { test: /\.html$/i, loader: 'html-loader', - }, + } ``` 1. **Images we use in our JavaScript, where we will need to import the files** @@ -251,7 +251,7 @@ There are three different ways you could be dealing with local image files: } ``` - You can always edit the regex in the `test` property to remove any file extensions you don't need, or add any extensions you do need. What's shown above is straight from [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/#loading-images) and will recognise most commonly used image file extensions. + You can always edit the regex in the `test` property to remove any file extensions you don't need, or add any extensions you do need. What's shown above is straight from [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/#loading-images) and will recognise most of the common image file extensions. Then in whatever JavaScript module we want to use that image in, we just have to default import it. @@ -297,12 +297,22 @@ module.exports = { { test: /\.(png|svg|jpg|jpeg|gif)$/i, type: "asset/resource", - } + }, ], }, }; ``` +
+ +#### You only need to configure what you need + +You may not need everything we've mentioned. If your project does not have images with local file path sources in your HTML template, you do not need `html-loader` set up. If you aren't using any local images in your JavaScript, you won't need the image `asset/resource` rule set up. + +Similarly, in the future, you may end up working with something that needs a special loader or plugin. You can always use Google or reference Webpack's documentation for instructions for what you need. + +
+ ### Webpack dev server ### Assignment From be785f6e5b732bc5e35c5d2520169235b1e1316f Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 23:01:24 +0100 Subject: [PATCH 12/31] Add note about Webpack hashed asset names --- javascript/organizing_your_javascript_code/webpack_part_1.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index f21b41b5681..eab1e3ce61a 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -303,6 +303,8 @@ module.exports = { }; ``` +You might notice that when images are included when bundling, the output image file in `dist` has a different file name (it will likely be some jumble of numbers and letters). By default, Webpack gives your bundled image files a new name by hashing their contents. You do not need to know how this works, nor do you need to dig the details of why, nor how to change this. You just need to be aware that this is expected behaviour (it's to do preventing issues with the browser cache and matching file names). +
#### You only need to configure what you need From 7b78c289ff5b7be949550e24b66b8a5e27c24f65 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 23:25:06 +0100 Subject: [PATCH 13/31] Add instructions for setting up webpack-dev-server --- .../webpack_part_1.md | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index eab1e3ce61a..ea7f3e90131 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -237,7 +237,7 @@ There are three different ways you could be dealing with local image files: ```javascript { test: /\.html$/i, - loader: 'html-loader', + loader: "html-loader", } ``` @@ -292,7 +292,7 @@ module.exports = { }, { test: /\.html$/i, - loader: 'html-loader', + loader: "html-loader", }, { test: /\.(png|svg|jpg|jpeg|gif)$/i, @@ -317,6 +317,63 @@ Similarly, in the future, you may end up working with something that needs a spe ### Webpack dev server +During this lesson, did you get a bit annoyed with having to run `npx webpack` to rebundle with every change? Fortunately, there are multiple solutions for this and we will focus on what we think is the most useful option: `webpack-dev-server`. Install it as follows: + +```bash +npm install --save-dev webpack-dev-server +``` + +You may have used something like the Live Server VSCode extension before, where it automatically refreshes your web page whenever you save a change. `webpack-dev-server` is very similar, meaning we won't have to keep running `npx webpack` after each change we make. + +It works by bundling your code behind the scenes (as if we ran `npx webpack`, but without saving the files to `dist`) and it does this every time you save a file that's used in the bundle. We can also use something called a **source map** so that any error messages reference files and lines from our development code, and not the jumbled mess inside our single bundled `.js` file! + +Once installed, in our `webpack.config.js`, we only need to add a couple more properties somewhere in the configuration object (the order does not matter): + +```javascript +// webpack.config.js +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); + +module.exports = { + mode: "development", + entry: "./src/index.js", + output: { + filename: "main.js", + path: path.resolve(__dirname, "dist"), + clean: true, + }, + devtool: "eval-source-map", + devServer: { + watchFiles: "./src/template.html", + }, + plugins: [ + new HtmlWebpackPlugin({ template: "./src/template.html" }), + ], + module: { + rules: [ + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + { + test: /\.html$/i, + loader: "html-loader", + }, + { + test: /\.(png|svg|jpg|jpeg|gif)$/i, + type: "asset/resource", + }, + ], + }, +}; +``` + +Firstly, we add the `eval-source-map` as a `devtool` option. If we don't do this, any error messages we get won't necessarily match up to the correct files and line numbers from our development code. In the devtools "Sources" tab, we also won't be able to find our original untouched code, making the Chrome debugger harder to use. Adding this source map will solve both of these problems for us. + +Secondly, by default, `webpack-dev-server` will only auto-restart when it detects any changes to files we import into our JavaScript bundle, so our HTML template will be ignored! All we need to do is add it to the dev server's list of watched files - nice and simple! + +Once set up, `npx webpack serve` will host our web page on `http://localhost:8080/`, which we can open in our browser and start working! + ### Assignment
From 4a0b3fe70dfd33e1a438bb7120bc341ceade07c6 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 23:37:38 +0100 Subject: [PATCH 14/31] Round off Webpack lesson contents --- .../organizing_your_javascript_code/webpack_part_1.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index ea7f3e90131..5febdc32ead 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -311,7 +311,7 @@ You might notice that when images are included when bundling, the output image f You may not need everything we've mentioned. If your project does not have images with local file path sources in your HTML template, you do not need `html-loader` set up. If you aren't using any local images in your JavaScript, you won't need the image `asset/resource` rule set up. -Similarly, in the future, you may end up working with something that needs a special loader or plugin. You can always use Google or reference Webpack's documentation for instructions for what you need. +Similarly, in the future, you may end up working with things that need a special loader or plugin, such as custom fonts or preprocessors. You can always use Google or reference Webpack's documentation for instructions for what you need when that time comes.
@@ -374,6 +374,12 @@ Secondly, by default, `webpack-dev-server` will only auto-restart when it detect Once set up, `npx webpack serve` will host our web page on `http://localhost:8080/`, which we can open in our browser and start working! +### Rounding up + +Yes, yes, this all might seem like a lot. You've gone from just having some basic HTML/CSS/JS files and not needing much else to suddenly need this loader, that plugin, this configuration file etc. In the real world, as apps get more complex, we need tools that can improve our development experience while optimizing things in production. Even though we're not using all of the features available to us right now, a general understanding of what these sorts of tools are doing for us is valuable. Later in the curriculum, you will use different tools that abstract a lot of these underlying mechanisms away from us. Using them and having no clue what they're actually doing for you can make things harder for you when you eventually encounter a situation that actually needs some kind of manual configuration. + +In a later lesson, we will introduce some extra things that can make setting up and working with Webpack much quicker and straightforward. For now, however, it's good to get a little manual practice in. + ### Assignment
From 0a841c4793a54cb7f50c282d9d9ca17ec3ca0f23 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 23:39:17 +0100 Subject: [PATCH 15/31] Tweak code examples formatting --- .../webpack_part_1.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 5febdc32ead..152e3888ba0 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -139,7 +139,9 @@ module.exports = { clean: true, }, plugins: [ - new HtmlWebpackPlugin({ template: "./src/template.html" }), + new HtmlWebpackPlugin({ + template: "./src/template.html", + }), ], }; ``` @@ -178,7 +180,9 @@ module.exports = { clean: true, }, plugins: [ - new HtmlWebpackPlugin({ template: "./src/template.html" }), + new HtmlWebpackPlugin({ + template: "./src/template.html", + }), ], module: { rules: [ @@ -282,7 +286,9 @@ module.exports = { clean: true, }, plugins: [ - new HtmlWebpackPlugin({ template: "./src/template.html" }), + new HtmlWebpackPlugin({ + template: "./src/template.html", + }), ], module: { rules: [ @@ -347,7 +353,9 @@ module.exports = { watchFiles: "./src/template.html", }, plugins: [ - new HtmlWebpackPlugin({ template: "./src/template.html" }), + new HtmlWebpackPlugin({ + template: "./src/template.html", + }), ], module: { rules: [ From 047cb2f207fdfca09c589abacb5f4abfb9874b72 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Fri, 10 May 2024 23:51:28 +0100 Subject: [PATCH 16/31] Add assignment and KC content --- .../organizing_your_javascript_code/webpack_part_1.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index 152e3888ba0..b45b95a9f38 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -392,13 +392,22 @@ In a later lesson, we will introduce some extra things that can make setting up
+1. Start by reading the [Webpack concepts](https://webpack.js.org/concepts/) page, to get a general understanding of some of the main terms. +1. [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/) goes through some examples of how to handle various kinds of assets, like CSS, images, and fonts. You'll see that its examples use `npm run build` to bundle the files; in these examples, that's the equivalent of `npx webpack`. We will go through npm scripts in a later 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 a bundler?](#bundling) +- [What is Webpack?](#webpack) +- [How do you bundle JavaScript?](#bundling-javascript) +- [How do you load CSS using Webpack?](#loading-css) +- [How do you automatically build HTML files in `dist` using Webpack?](#handling-html) +- [How would you handle assets like local image files?](#loading-images) +- [What Webpack tool could you use while development to view changes to your website live?](#webpack-dev-server) ### Additional resources From 3d9e9b265288596b78343c054965b266b144f252 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 11 May 2024 00:20:07 +0100 Subject: [PATCH 17/31] Fix grammar and spelling across the file Uses AE instead of BE spelling. --- .../webpack_part_1.md | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/javascript/organizing_your_javascript_code/webpack_part_1.md b/javascript/organizing_your_javascript_code/webpack_part_1.md index b45b95a9f38..6ed91b4572c 100644 --- a/javascript/organizing_your_javascript_code/webpack_part_1.md +++ b/javascript/organizing_your_javascript_code/webpack_part_1.md @@ -1,6 +1,6 @@ ### Introduction -In the previous lesson, we introduced ES6 modules (ESM) and npm. While the introduction of ESM greatly mitigated some of the issues with managing individual script files and dependencies, there would still be performance issues to consider the more module files the browser would have to download individually (especially as more third party libraries would be imported). Fortunately, more recent web technologies have greatly improved these aspects, but bundlers still provide us with a lot of power to process and optimize our code in various ways. This power, however, does come with a small cost of needing to configure a bundler. For now, our needs are few and simple, and we can look at the basic things one at a time. +In the previous lesson, we introduced ES6 modules (ESM) and npm. While the introduction of ESM greatly mitigated some of the issues with managing individual script files and dependencies, there would still be performance issues to consider the more module files the browser would have to download individually (especially as more third-party libraries would be imported). Fortunately, more recent web technologies have greatly improved these aspects, but bundlers still provide us with a lot of power to process and optimize our code in various ways. This power, however, does come with the small cost of needing to configure a bundler. For now, our needs are few and simple, and we can look at the basic things one at a time. Awareness of and basic experience with bundlers are valuable. While in recent years, new build tools have come out that handle a lot of basic configuration for us, in the real world, you may not always get a chance to use these tools. It's very reasonable to end up working with codebases that use tools that require more manual configuration. Even if you did get to work with tools that handle more things for you, it's useful to understand what those tools are actually doing for you. @@ -15,9 +15,9 @@ This section contains a general overview of topics that you will learn in this l ### Bundling -In the previous lesson, we learned what an **entry point** is, what a **dependency graph** is, and how to add an entry point file to HTML as a module script. With bundling, the same concepts of entry points and dependency graphs apply: we provide the bundler with an entry point and it builds a dependency graph from that file, combines all relevant files together, then outputs a single file with all the necessary code included. +In the previous lesson, we learned what an **entry point** is, what a **dependency graph** is, and how to add an entry point file to HTML as a module script. With bundling, the same concepts of entry points and dependency graphs apply: we provide the bundler with an entry point. It then builds a dependency graph from that file, combines all relevant files together, and then outputs a single file with all the necessary code included. -While it does this, we could also get it to do a whole bunch of other things, such as [minifying our code](https://en.wikipedia.org/wiki/Minification_(programming)), image optimizations, or even ["tree shaking"](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). Most of these extra optimizations are out of the scope of this course; we will instead be focusing on basic bundling of JavaScript, while handling HTML, CSS, and assets (such as images). +While it does this, we could also get it to do a whole bunch of other things, such as [minifying our code](https://en.wikipedia.org/wiki/Minification_(programming)), image optimizations, or even ["tree shaking"](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). Most of these extra optimizations are out of the scope of this course; we will instead be focusing on basic bundling of JavaScript, and handling HTML, CSS, and images. ### Webpack @@ -37,7 +37,7 @@ Once inside your new directory, we can go ahead and install Webpack, which invol npm install --save-dev webpack webpack-cli ``` -Note that we included the `--save-dev` flag (you can also use `-D` as a shortcut), which tells npm to record our two packages as development dependencies. We will only be using Webpack during development. The actual code run that makes Webpack run will not be a part of the code that the browser will run. +Note that we included the `--save-dev` flag (you can also use `-D` as a shortcut), which tells npm to record our two packages as development dependencies. We will only be using Webpack during development. The actual code that makes Webpack run will not be part of the code that the browser will run. Also notice that when these finished installing, a `node_modules` directory and a `package-lock.json` got auto-generated. `node_modules` is where Webpack's actual code (and a whole bunch of other stuff) lives, and `package-lock.json` is just another file npm uses to track package information. @@ -45,9 +45,9 @@ Also notice that when these finished installing, a `node_modules` directory and #### src and dist -When dealing with Webpack (and often with any other bundler or build tool), we have two very important directories: `src` (short for "source") and `dist` (short for "distribution"). We could technically call these directories whatever we want, but these names are convention. +When dealing with Webpack (and often with any other bundler or build tool), we have two very important directories: `src` (short for "source") and `dist` (short for "distribution"). We could technically call these directories whatever we want, but these names are conventions. -`src` is where we keep all of our website's source code, essentially where all of our work will be done (with an exception being altering any configuration files in the root of the project). When we run Webpack to bundle our code, it will output the bundled files into the `dist` directory. The idea is that if someone was to fork or clone the project, they would not need the `dist` directory, as they'd just be able to run Webpack to build from `src` into their own `dist`. Similarly, to deploy our website, we would only need the `dist` code and nothing else. Keep that in mind! Work inside `src`, build into and deploy from `dist`! +`src` is where we keep all of our website's source code, essentially where all of our work will be done (with an exception being altering any configuration files in the root of the project). When we run Webpack to bundle our code, it will output the bundled files into the `dist` directory. The idea is that if someone were to fork or clone the project, they would not need the `dist` directory, as they'd just be able to run Webpack to build from `src` into their own `dist`. Similarly, to deploy our website, we would only need the `dist` code and nothing else. Keep that in mind! Work inside `src`, build into `dist`, then deploy from there!
@@ -73,7 +73,7 @@ console.log(greeting); export const greeting = "Hello, Odinite!"; ``` -Great, now we have an `index.js` that imports from, and so depends on, `greeting.js`. In order to bundle this, we'll also want a Webpack configuration file which will contain all the details we need for bundling, such as the entry point, the output destination, and anything like plugins and loaders (which we will cover shortly). +Great, now we have an `index.js` that imports from, and so depends on, `greeting.js`. In order to bundle this, we'll also want a Webpack configuration file, which will contain all the details we need for bundling, such as the entry point, the output destination, and anything like plugins and loaders (which we will cover shortly). Back in your project root (so outside of `src`), create a `webpack.config.js` file that contains the following: @@ -92,16 +92,16 @@ module.exports = { }; ``` -Yes, you may have noticed this file uses CommonJS (CJS) syntax instead of ESM. That's because this file (and Webpack itself) runs in NodeJS and not the browser. By default, NodeJS uses CJS syntax, and the configuration file also contains some CJS-specific things. We need not worry about this - this is just stuff we need for Webpack to do it's thing. +Yes, you may have noticed this file uses CommonJS (CJS) syntax instead of ESM. That's because this file (and Webpack itself) runs in NodeJS and not the browser. By default, NodeJS uses CJS syntax, and the configuration file also contains some CJS-specific things. We need not worry about this - this is just stuff we need for Webpack to do its thing. -You'll notice the exported object containing a few key sections: +You'll notice the exported object contains a few key sections: - `mode`: For now, we will just leave this in development mode, as it will be more useful to us. We will revisit this and production mode in a later lesson. - `entry`: A file path from the config file to whichever file is our entry point, which in this case is `src/index.js`. - `output`: An object containing information about the output bundle. - `filename`: The name of the output bundle - it can be anything you want. - `path`: The path to the output directory, in this case, `dist`. If this directory doesn't already exist when we run Webpack, it will automatically create it for us as well. Don't worry too much about why we have the `path.resolve` part - this is just the way Webpack recommends we specify the output directory. - - `clean`: If we include this option and set it to `true`, then each time we run Webpack to bundle, it will empty the output directory first before bundling the files into it. This helps us keep `dist` clean so it only contains the files produced by the most recent bundling. + - `clean`: If we include this option and set it to `true`, then each time we run Webpack to bundle, it will empty the output directory first before bundling the files into it. This helps us keep `dist` clean, so it only contains the files produced by the most recent bundling. With these files all in place, let's run Webpack and see what happens! @@ -109,7 +109,7 @@ With these files all in place, let's run Webpack and see what happens! npx webpack ``` -You should see that Webpack has created a `dist` directory for us containing a `main.js` file! Inside this file is...a lot of stuff... Don't worry, most of this stuff is just for development tools we will use later. If you go ahead and run this file with `node dist/main.js`, you should see `Hello, Odinite!` get logged in the terminal. +You should see that Webpack has created a `dist` directory for us containing a `main.js` file! Inside this file is...a lot of stuff... Don't worry, most of this stuff is just for development tools we will use later. If you go ahead and run this file with `node dist/main.js`, you should see `Hello, Odinite!` logged in the terminal. Congratulations! You've just made your first bundle with Webpack! @@ -123,7 +123,7 @@ Run the following command to install HtmlWebpackPlugin (also as a dev dependency npm install --save-dev html-webpack-plugin ``` -We should also create a `template.html` inside `src` (you can name this file whatever you want), and fill that with the usual HTML boilerplate. **We do not need to add a script tag in this file!** HtmlWebpackPlugin will automatically add our output bundle as a script tag. We wouldn't want to double up by including our own one too! Inside our `webpack.config.js`, we can add a few little bits. +We should also create a `template.html` inside `src` (you can name this file whatever you want) and fill that with the usual HTML boilerplate. **We do not need to put a script tag in this file!** HtmlWebpackPlugin will automatically add our output bundle as a script tag. We wouldn't want to double up by including our own one as well! Inside our `webpack.config.js`, we can add a few little bits. ```javascript // webpack.config.js @@ -146,9 +146,9 @@ module.exports = { }; ``` -All we're doing here is making sure our Webpack configuration has access to HtmlWebpackPlugin, then we add it as a plugin to the configuration object. Inside HtmlWebpackPlugin function call, we pass in any options. For now, we're only interested in the `template` option. +All we're doing here is making sure our Webpack configuration has access to HtmlWebpackPlugin, then adding it as a plugin to the configuration object. Inside the HtmlWebpackPlugin constructor call, we pass in any options. For now, we're only interested in the `template` option. -If we provide the path to our `src/template.html` file as a template, when we run `npx webpack` again, you'll notice our `dist` directory not only contains a `main.js` file but an `index.html` file as well. You'll also notice that HtmlWebpackPlugin has automatically added a deferred script tag to our `main.js` bundle file - what a darling! If you open this file in the browser and check the browser console, you should see our lovely `"Hello, Odinite!"` string logged. +If we provide the path to our `src/template.html` file as a template, when we run `npx webpack` again, you'll notice our `dist` directory not only contains a `main.js` file but an `index.html` file as well (it can't combine them into one file). You'll also notice that HtmlWebpackPlugin has automatically added a deferred script tag to our `main.js` bundle file - what a darling! If you open this file in the browser and check the browser console, you should see our lovely `"Hello, Odinite!"` string logged. We've now successfully configured Webpack to handle our HTML file and inject the appropriate script tag. Any changes to HTML we make, we can just rerun Webpack to generate fresh `dist` code. @@ -225,7 +225,7 @@ import { greeting } from "./greeting.js"; console.log(greeting); ``` -Once again, rebundle with Webpack using `npx webpack`, then open `dist/index.html` and enjoy the beautiful purple screen! +Once again, bundle with Webpack using `npx webpack`, then open `dist/index.html` and enjoy the beautiful purple screen! ### Loading images @@ -246,7 +246,7 @@ There are three different ways you could be dealing with local image files: ``` 1. **Images we use in our JavaScript, where we will need to import the files** - If we need to use a local image file in our JavaScript, for example manipulating the DOM to create or edit `img` elements and set their `src` attribute, we need to import the images into our JavaScript module. Since images aren't JavaScript, we need to tell Webpack that these files will be assets by adding an `asset/resource` rule. No need to install anything here, just add the following object to the `modules.rules` array within `webpack.config.js`: + If we need to use a local image file in our JavaScript (such as when manipulating the DOM to create or edit `img` elements and set their `src` attribute), we need to import the images into our JavaScript module. Since images aren't JavaScript, we need to tell Webpack that these files will be assets by adding an `asset/resource` rule. No need to install anything here. Just add the following object to the `modules.rules` array within `webpack.config.js`: ```javascript { @@ -255,9 +255,9 @@ There are three different ways you could be dealing with local image files: } ``` - You can always edit the regex in the `test` property to remove any file extensions you don't need, or add any extensions you do need. What's shown above is straight from [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/#loading-images) and will recognise most of the common image file extensions. + You can always edit the regex in the `test` property to remove any file extensions you don't need or add any extensions you do need. What's shown above is straight from [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/#loading-images) and will recognize most of the common image file extensions. - Then in whatever JavaScript module we want to use that image in, we just have to default import it. + Then, in whatever JavaScript module we want to use that image in, we just have to default import it. ```javascript import odinImage from "./odin.png"; @@ -268,7 +268,7 @@ There are three different ways you could be dealing with local image files: document.body.appendChild(image); ``` - We have to import it so that the `odinImage` variable contains the correct file path, even when we bundle into `dist`. If we just wrote `image.src = "./odin.png";`, then the "file path" would just be a plain string. When we bundle into `dist`, Webpack will not magically recognise this string in our JavaScript references a file, and will not include it in the bundle. When we import it and set the correct `asset/resource` rule, Webpack will recognise the import, include the image file when we bundle, and also make sure the imported variable contains the correct file path at the end. + We have to import it so that the `odinImage` variable contains the correct file path, even when we bundle into `dist`. If we just wrote `image.src = "./odin.png";`, then the "file path" would just be a plain string. When we bundle into `dist`, Webpack will not magically recognize that this string in our JavaScript references a file and so will not include it in the bundle. When we import it and set the correct `asset/resource` rule, Webpack will recognize the import, include the image file when we bundle, and also make sure the imported variable contains the correct file path at the end. After all that, if we added both `html-loader` and the image `asset/resource` rule, our `webpack.config.js` would look something like this: @@ -309,7 +309,7 @@ module.exports = { }; ``` -You might notice that when images are included when bundling, the output image file in `dist` has a different file name (it will likely be some jumble of numbers and letters). By default, Webpack gives your bundled image files a new name by hashing their contents. You do not need to know how this works, nor do you need to dig the details of why, nor how to change this. You just need to be aware that this is expected behaviour (it's to do preventing issues with the browser cache and matching file names). +You might notice that when images are included when bundling, the output image file in `dist` has a different file name (it will likely be some jumble of numbers and letters). By default, Webpack gives your bundled image files a new name by hashing their contents. You do not need to know how this works, nor do you need to dig into the details of why, nor how to change it. You just need to be aware that this is expected behavior (it's to do with preventing issues with the browser cache and matching file names).
@@ -317,13 +317,13 @@ You might notice that when images are included when bundling, the output image f You may not need everything we've mentioned. If your project does not have images with local file path sources in your HTML template, you do not need `html-loader` set up. If you aren't using any local images in your JavaScript, you won't need the image `asset/resource` rule set up. -Similarly, in the future, you may end up working with things that need a special loader or plugin, such as custom fonts or preprocessors. You can always use Google or reference Webpack's documentation for instructions for what you need when that time comes. +Similarly, in the future, you may end up working with things that need a special loader or plugin, such as custom fonts or preprocessors. You can always use Google or reference Webpack's documentation for instructions on what you'd need when that time comes.
### Webpack dev server -During this lesson, did you get a bit annoyed with having to run `npx webpack` to rebundle with every change? Fortunately, there are multiple solutions for this and we will focus on what we think is the most useful option: `webpack-dev-server`. Install it as follows: +During this lesson, did you get a bit annoyed with having to run `npx webpack` to rebundle with every change? Fortunately, there are multiple solutions for this, and we will focus on what we think is the most useful option: `webpack-dev-server`. Install it as follows: ```bash npm install --save-dev webpack-dev-server @@ -331,7 +331,7 @@ npm install --save-dev webpack-dev-server You may have used something like the Live Server VSCode extension before, where it automatically refreshes your web page whenever you save a change. `webpack-dev-server` is very similar, meaning we won't have to keep running `npx webpack` after each change we make. -It works by bundling your code behind the scenes (as if we ran `npx webpack`, but without saving the files to `dist`) and it does this every time you save a file that's used in the bundle. We can also use something called a **source map** so that any error messages reference files and lines from our development code, and not the jumbled mess inside our single bundled `.js` file! +It works by bundling your code behind the scenes (as if we ran `npx webpack`, but without saving the files to `dist`), and it does this every time you save a file that's used in the bundle. We can also use something called a **source map** so that any error messages reference files and lines from our development code and not the jumbled mess inside our single bundled `.js` file! Once installed, in our `webpack.config.js`, we only need to add a couple more properties somewhere in the configuration object (the order does not matter): @@ -384,15 +384,15 @@ Once set up, `npx webpack serve` will host our web page on `http://localhost:808 ### Rounding up -Yes, yes, this all might seem like a lot. You've gone from just having some basic HTML/CSS/JS files and not needing much else to suddenly need this loader, that plugin, this configuration file etc. In the real world, as apps get more complex, we need tools that can improve our development experience while optimizing things in production. Even though we're not using all of the features available to us right now, a general understanding of what these sorts of tools are doing for us is valuable. Later in the curriculum, you will use different tools that abstract a lot of these underlying mechanisms away from us. Using them and having no clue what they're actually doing for you can make things harder for you when you eventually encounter a situation that actually needs some kind of manual configuration. +Yes, yes, this all might seem like a lot. You've gone from just having some basic HTML, CSS and JS files, and not needing much else to suddenly needing this loader, that plugin, this configuration file, etc. In the real world, as apps get more complex, we need tools that can improve our development experience while optimizing things in production. Even though we're not using all of the features available to us right now, a general understanding of what these sorts of tools are doing for us is valuable. Later in the curriculum, you will use different tools that abstract a lot of these underlying mechanisms away from us. Using them and having no clue what they're actually doing for you can make things harder for you when you eventually encounter a situation that actually needs some kind of manual configuration. -In a later lesson, we will introduce some extra things that can make setting up and working with Webpack much quicker and straightforward. For now, however, it's good to get a little manual practice in. +In a later lesson, we will introduce some extra things that can make setting up and working with Webpack much quicker and more straightforward. For now, however, it's good to get a little manual practice in. ### Assignment
-1. Start by reading the [Webpack concepts](https://webpack.js.org/concepts/) page, to get a general understanding of some of the main terms. +1. Start by reading the [Webpack concepts](https://webpack.js.org/concepts/) page to get a general understanding of some of the main terms. 1. [Webpack's Asset Management guide](https://webpack.js.org/guides/asset-management/) goes through some examples of how to handle various kinds of assets, like CSS, images, and fonts. You'll see that its examples use `npm run build` to bundle the files; in these examples, that's the equivalent of `npx webpack`. We will go through npm scripts in a later lesson.
@@ -407,7 +407,7 @@ The following questions are an opportunity to reflect on key topics in this less - [How do you load CSS using Webpack?](#loading-css) - [How do you automatically build HTML files in `dist` using Webpack?](#handling-html) - [How would you handle assets like local image files?](#loading-images) -- [What Webpack tool could you use while development to view changes to your website live?](#webpack-dev-server) +- [What Webpack tool could you use during development to view changes to your website live?](#webpack-dev-server) ### Additional resources From fc5a8eea68c8fafeb2da10c61adcff9515b93ba9 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 11 May 2024 00:26:14 +0100 Subject: [PATCH 18/31] Add co-author Co-authored-by: advait0603 From 57731dd470348b1fbb11e4e5cc1e0837e52e2f05 Mon Sep 17 00:00:00 2001 From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com> Date: Sat, 11 May 2024 00:30:18 +0100 Subject: [PATCH 19/31] Rename new webpack lesson to overwrite existing --- .../webpack.md | 405 +++++++++++++++-- .../webpack_part_1.md | 416 ------------------ 2 files changed, 367 insertions(+), 454 deletions(-) delete mode 100644 javascript/organizing_your_javascript_code/webpack_part_1.md diff --git a/javascript/organizing_your_javascript_code/webpack.md b/javascript/organizing_your_javascript_code/webpack.md index 062640ede0e..6ed91b4572c 100644 --- a/javascript/organizing_your_javascript_code/webpack.md +++ b/javascript/organizing_your_javascript_code/webpack.md @@ -1,71 +1,399 @@ ### Introduction -We've already introduced webpack in a previous lesson. It is the go-to tool across the web for bundling and compiling JavaScript code. There *are* other options out there, but at this time none of them are as popular or widely used as webpack. +In the previous lesson, we introduced ES6 modules (ESM) and npm. While the introduction of ESM greatly mitigated some of the issues with managing individual script files and dependencies, there would still be performance issues to consider the more module files the browser would have to download individually (especially as more third-party libraries would be imported). Fortunately, more recent web technologies have greatly improved these aspects, but bundlers still provide us with a lot of power to process and optimize our code in various ways. This power, however, does come with the small cost of needing to configure a bundler. For now, our needs are few and simple, and we can look at the basic things one at a time. -In our last lesson, we covered the first half of what webpack can do for you: bundling your modules. Another amazing feature is webpack's ability to process and manipulate your code as it bundles this. So, for example, if you would like to use [Sass](http://sass-lang.com/) or [PostCSS](https://postcss.org/) to write your CSS, webpack can allow you to do that. Webpack can manage your images and compress and optimize them for use on the web. Webpack can [minify and uglify](https://stackoverflow.com/questions/33708197/does-it-make-sense-to-do-both-minify-and-uglify/33708348) your code. There are tons of things webpack can do, but to access these functions we need to learn more about loaders and plugins. +Awareness of and basic experience with bundlers are valuable. While in recent years, new build tools have come out that handle a lot of basic configuration for us, in the real world, you may not always get a chance to use these tools. It's very reasonable to end up working with codebases that use tools that require more manual configuration. Even if you did get to work with tools that handle more things for you, it's useful to understand what those tools are actually doing for you. ### Lesson overview This section contains a general overview of topics that you will learn in this lesson. -- Use webpack by following its documentation. -- Load assets with webpack. -- Manage output with webpack and HtmlWebpackPlugin. -- Configure webpack with useful features for development. +- Explain the purpose of bundlers and how they work. +- Configure Webpack to bundle JavaScript modules. +- Configure Webpack to deal with non-JavaScript files during bundling, including with HtmlWebpackPlugin. +- Set up Webpack's development server. ### Bundling -As briefly introduced in the previous lesson, if you give webpack a file as an entry point, it will build a dependency graph based on all the imports/exports starting there, before bundling everything into a single `.js` file in `dist`. If for whatever reason you needed it to output multiple bundles (e.g. you have multiple HTML pages that each need their own), then each entry point you give Webpack will produce its own output bundle. +In the previous lesson, we learned what an **entry point** is, what a **dependency graph** is, and how to add an entry point file to HTML as a module script. With bundling, the same concepts of entry points and dependency graphs apply: we provide the bundler with an entry point. It then builds a dependency graph from that file, combines all relevant files together, and then outputs a single file with all the necessary code included. -If you are only dealing with bundling JavaScript then this is fairly straightforward. But what if your project also includes CSS or assets like images or fonts? For CSS, you can import your `.css` file directly into your JavaScript and for assets like images, they might be used inside your CSS or imported directly into your JavaScript. When you tell Webpack to bundle your files, it will come across these files and try to bundle them together or process any assets like images and copy them into `dist`. +While it does this, we could also get it to do a whole bunch of other things, such as [minifying our code](https://en.wikipedia.org/wiki/Minification_(programming)), image optimizations, or even ["tree shaking"](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). Most of these extra optimizations are out of the scope of this course; we will instead be focusing on basic bundling of JavaScript, and handling HTML, CSS, and images. -Since these sorts of files are not JavaScript, however, Webpack will not know how to process them unless you tell it how to by including the correct loaders and rules. If you really wanted to, with the right loaders/plugins/rules, you could even do things such as image optimization when you build your project into `dist`. In the assignment links below, you will get to see how you can install and configure these loaders and rules for CSS and assets. +### Webpack -### HTML-webpack-plugin +Webpack is one of the most popular JavaScript bundlers, if not the most popular one, and has been for a long time. Let's get started with bundling! -Since we would like to keep all of our development work within `src` and leave `dist` for the production build (the code that you will actually deploy), what about handling HTML files? +We'll first need to make a new directory for our practice app, then create a `package.json` file in it for npm to record information about packages we use (like Webpack). Run the following in your terminal: -Similarly to how we will need loaders and rules for CSS and assets, we can use a plugin called `html-webpack-plugin` which will automatically build an HTML file in `dist` for us when we build our project. It will also then automatically add certain things to the HTML like our output bundle in a `