diff --git a/resources/docs/docs/chapters/tp/npm.md b/resources/docs/docs/chapters/tp/npm.md index 547f6a2f8fbb69394335051cf283d176dca0393a..933ea9a47278dae53c1584210f48c486b8c92c4a 100644 --- a/resources/docs/docs/chapters/tp/npm.md +++ b/resources/docs/docs/chapters/tp/npm.md @@ -16,7 +16,7 @@ Fortunately, we now have the [**NPM**](https://docs.npmjs.com/about-npm) (Node P _NPM_ comes with a [_CLI_](https://docs.npmjs.com/cli/v9/commands) to easily create a project, install some dependencies and so on. -## The _NPM_ configuration file +## :fontawesome-solid-gear: The _NPM_ configuration file <hr> A project that uses _NPM_ comes with a configuration file at the root directory called [`package.json`](https://docs.npmjs.com/files/package.json). It contains some project metadata like: @@ -32,7 +32,7 @@ A project that uses _NPM_ comes with a configuration file at the root directory These informations will be set in the `package.json` file by the `npm init` command. -### `npm init` <span id="diy"> Do it yourself </span> +### :fontawesome-solid-terminal: `npm init` <span id="diy">:fontawesome-solid-wrench: Do it yourself </span> At the root of the `front-end/` directory, initialize a new NPM package with the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file#running-a-cli-questionnaire). @@ -95,14 +95,14 @@ package.json _NPM_ is not only a tool, it is also connected to the [official NPM repository](https://www.npmjs.com/). There, you can search for and download libraries published by other npm users, but also publish your own package with the `npm publish command`.<br> Set your package as private to avoid publishing it to the repository by accident. -#### <i class="fas fa-folder-tree"></i> Modified files +#### :fontawesome-solid-folder-tree: Modified files ``` front-end/ ├── package.json ``` -## <i class="fa fa-cloud-arrow-down"></i> Install a dependency +## :fontawesome-solid-cloud-arrow-down: Install a dependency The application can run locally with the help of an _HTTP server_. We started this server earlier with the `npx http-server -c-1` command. To be able to run the `http-server` without using `npx`, we can install the dependency for our project. @@ -140,7 +140,7 @@ All of our project [**dependencies**](https://docs.npmjs.com/specifying-dependen -### <i class="fa fa-terminal"></i> `npm install` <Diy /> +### :fontawesome-solid-terminal: `npm install` <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> Go back in the `front-end/` folder and install the `http-server` library as a [**development dependency**](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file) for our project. @@ -275,7 +275,7 @@ In addition to `package-lock.json`, _NPM_ also created a folder called `node_mod -#### <i class="fas fa-folder-tree"></i> Modified files +#### :fontawesome-solid-folder-tree: Modified files ``` front-end/ @@ -284,14 +284,14 @@ front-end/ ├── node_modules/ ``` -#### <i class="fa fa-list-check"></i> Checklist +#### :fontawesome-solid-list-check: Checklist - <input type="checkbox" /> I know how to **init** a new **_NPM_ package**. - <input type="checkbox" /> I can **install** a **_NPM_ dependency**. - <input type="checkbox" /> I know the difference between a **dependency** and a **devDependency** -## <i class="fas fa-terminal"></i> Write _NPM_ scripts +## :fontawesome-solid-terminal: Write _NPM_ scripts <hr> Did you notice that the generated `package.json` has a `"scripts"` section? @@ -332,7 +332,7 @@ npm run test Because we have not written any tests yet, it defaults printing an error and exits. -### Write the `npm start` script <Diy /> <BadgeEasy /> +### Write the `npm start` script <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> <span id="easy">:fontawesome-solid-star: Easy</span> In the previous section, we have installed the `http-server` package as a devDependency to our project. So now, to run the server, you can use the command `http-server -c-1` without `npx`. However, because it is rather hard to memorize, let's create a script as a shortcut instead of running it manually. @@ -374,7 +374,7 @@ So now, to run the server, you can use the command `http-server -c-1` without `n - Navigate to [http://localhost:8080/src](http://localhost:8080/src). The _front-end_ application should be up and running and connected to the _back-end_ at [http://localhost:8081/api-docs](http://localhost:8081/api-docs) to get the required data. -#### <i class="fas fa-folder-tree"></i> Modified files +#### :fontawesome-solid-folder-tree: Modified files ``` front-end/ @@ -383,7 +383,7 @@ front-end/ <span id="commit">:fontawesome-brands-git-alt: Commit !</span> -#### <i class="fa fa-list-check"></i> Checklist +#### :fontawesome-solid-list-check: Checklist - <input type="checkbox" /> I know what _NPM scripts_ are. - <input type="checkbox" /> I can run my application running the `npm start` command. diff --git a/resources/docs/docs/chapters/tp/setup.md b/resources/docs/docs/chapters/tp/setup.md index a43d1ce573ff92f47c7d66ad4624d8f708cd87ec..c621f0946069d33fab84fbbaa601dc1e4c0e7421 100644 --- a/resources/docs/docs/chapters/tp/setup.md +++ b/resources/docs/docs/chapters/tp/setup.md @@ -38,8 +38,8 @@ tag: - Install [_Prettier_](https://prettier.io/). _Prettier_ is a code formatter to automatically rearrange _JS_, _HTML_ and _CSS_ code when you save a file. You can install the extension for your IDE: - - [Prettier for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - - [Prettier for IntelliJ / Webstorm](https://plugins.jetbrains.com/plugin/10456-prettier) + - [Prettier for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) + - [Prettier for IntelliJ / Webstorm](https://plugins.jetbrains.com/plugin/10456-prettier) ## :fontawesome-solid-person-digging: Preparation <hr> @@ -48,12 +48,11 @@ In this tutorial, we provide you an existing codebase written in **good-old _ES5 Your mission, should you choose to accept it, is to **rewrite this application using modern _ES6+_**. !!! info "Long story short, JavaScript is an implementation of the **Ecma Script (ES) specification**. Any browser can have its own implementation but must comply to the ES specification, which is the standard. **_ES6_**, released in 2015, was a **big jump forward** and marks the beginning of the **Modern _JavaScript_ era**. Since then, there is a new released each year." -### Initialize the Git repository +### :fontawesome-brands-git-alt: Initialize the Git repository -<span id="diy"> Do it yourself </span> +<span id="diy">:fontawesome-solid-wrench: Do it yourself </span> <br> <br> -Download the project : [Meme-ORY](../../downloads/init.zip){:download="Meme-ORY"} - Create a new project under your namespace on your Gitlab. Call it **web-01**. - Clone that project in your workspace and checkout to a new branch called **develop** @@ -66,12 +65,12 @@ Download the project : [Meme-ORY](../../downloads/init.zip){:download="Meme-ORY" git switch -c develop ``` -- Download and extract the initial _ES5_ codebase for the _MEME-ORY_ application in your workspace: - <ResourcesButton path="init.zip" title="Meme-ORY" /> +- Download and extract the initial _ES5_ codebase for the _MEME-ORY_ application in your workspace: <br><br> + [<span id="download"> :fontawesome-solid-file-arrow-down: Meme-ORY</span>](../../downloads/init.zip){:download="Meme-ORY"} <br><br> This archive contains two folders: - - `back-end`: contains the code for the **application server**. This server offers a web API to setup a new game. You are not intended to modify it. - - `front-end` contains the code for the **web UI**. This code uses _HTML_, _CSS_ and legacy _ES5_. We will rewrite it step by step using modern _ES6_. + - `back-end`: contains the code for the **application server**. This server offers a web API to setup a new game. You are not intended to modify it. + - `front-end`: contains the code for the **web UI**. This code uses _HTML_, _CSS_ and legacy _ES5_. We will rewrite it step by step using modern _ES6_. !!! tip "Commit frequently on this branch when you see the badge." diff --git a/resources/docs/docs/chapters/tp/spa.md b/resources/docs/docs/chapters/tp/spa.md index 9ec7c33f7698e656843e8cae2ff06befef5cb3b2..35c3e5eea227c7d703561f6a185e872609e7bff6 100644 --- a/resources/docs/docs/chapters/tp/spa.md +++ b/resources/docs/docs/chapters/tp/spa.md @@ -21,7 +21,7 @@ Each view comes with a _complete *HTML* document_. Going from one view to anothe If the network is slow, it can cause **performance issues** and flickering until the page is fully loaded, which is not great in terms of **user experience**.  -## <i class="fa fa-wrench"></i> The browser dev tools +## :fontawesome-solid-wrench: The browser dev tools <hr> !!! tip "Did you know ?" Your web browser can give you a lot of information about what happens behind the scene (JavaScript execution, stack-traces, network, errors, ...). Press `ctrl+shift+I` (Firefox, Google Chrome, Chromium) to open the developer console. @@ -45,20 +45,20 @@ _**S**ingle **P**age **A**pplication_ (_SPA_) means the application lives in a s In a _SPA_, the application has only one page. Even if the content changes, we stay on the same `index.html`. As a result, we should neither use `window.location.href='...'` nor `<a href=‘…’>`, as it would load another document in place of `index.html`. Instead, we define a __Router__ to switch between views. -## <i class="fa-solid fa-signs-post"></i> The application _Router_ +## :fontawesome-solid-signs-post: The application _Router_ A **Router** is a JavaScript object which maps URLs to views. Here, our _Router_ is listening to url's [_hash_](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash) changes to know which view has to be displayed. It uses the [`DOM` API](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction) to dynamically add or remove content.  -### Create the _Router_ <span id="diy"> Do it yourself </span> +### Create the _Router_ <span id="diy"> :fontawesome-solid-wrench: Do it yourself </span> <hr> -- Download the _Router_ sources as router.js: [Router](../../stylesheets/router.zip){:download="router.zip"} +- Download the _Router_ sources: [<span id="download">:fontawesome-solid-file-down-arrow: Router</span>](../../stylesheets/router.zip){:download="router.zip"} This archive contains two source files you have to put in your `front-end/src/app/scripts/` folder: - - **`router.js`**: a rudimentary _Router_ implementation. + - **`router.js`**: a rudimentary _Router_ implementation. - **`main.js`**: the place where the _HTML templates_ and their corresponding JavaScript files are registered at the Router. The _Router_ will put the different views into the existing `document`, in the `<div id="content-outlet">`. ???+ note "Show the main.js file" @@ -114,7 +114,7 @@ It uses the [`DOM` API](https://developer.mozilla.org/en-US/docs/Web/API/Documen The faster way to find all specific string occurrences in a project is the `ctrl+shift+F` shortcut. In our case: `ctrl+shift+F` -> `TODO #spa` will do the job (replace `ctrl` by `cmd` on mac) -## <i class="fa-solid fa-table-columns"></i> The application shell +## :fontawesome-solid-table-columns: The application shell Each application view uses the same layout: @@ -126,7 +126,7 @@ It is called the **_Application Shell_** and is common to all application views.  -### Create the shell <Diy/> <BadgeMedium /> +### Create the shell <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> <span id="medium"> :fontawesome-solid-star: :fontawesome-solid-star: Medium</span> <hr> `welcome.html`, `game.html` and `score.html` are now _HTML_ templates/blocks instead of full-fledged _HTML_ documents. @@ -190,7 +190,7 @@ It is called the **_Application Shell_** and is common to all application views. - How many megabytes are transferred in total after going through the 3 views, with `size=2`? - How many files have been transferred? -#### <i class="fas fa-folder-tree"></i> Modified files +#### :fontawesome-solid-folder-tree: Modified files ``` src/app/scripts/main.js @@ -202,7 +202,7 @@ src/app/views/welcome.html <span id="commit">:fontawesome-brands-git-alt: Commit !</span> -#### <i class="fa fa-list-check"></i> Checklist +#### :fontawesome-solid-list-check: Checklist - <input type="checkbox" /> I know how to open and use the browser developer console. - <input type="checkbox" /> I know what is a _SPA_ and why it may be a better choice. diff --git a/resources/docs/docs/chapters/tp/webpack.md b/resources/docs/docs/chapters/tp/webpack.md index c187acdec91a8e9caf191a5872b53fb59d73f669..6de51497f448cd2d04aa3ae6f72d91c2f190162b 100644 --- a/resources/docs/docs/chapters/tp/webpack.md +++ b/resources/docs/docs/chapters/tp/webpack.md @@ -11,33 +11,33 @@ tag: From now we have been using the old way to put in common all of our JavaScript scripts as we have imported all of them in the `index.html` file like that: -index.html - -```html{10,11} -<!DOCTYPE html> -<html lang="en"> - <!-- ... --> - <head> - <!-- ... --> - </head> - <body> - <!-- ... --> - <script src="/src/app/scripts/utils.js"></script> - <script src="/src/app/scripts/router.js"></script> - <script src="/src/app/scripts/main.js"></script> - </body> -</html> -``` +=== "index.html" + + ```html linenums="1" + <!DOCTYPE html> + <html lang="en"> + <!-- ... --> + <head> + <!-- ... --> + </head> + <body> + <!-- ... --> + <script src="/src/app/scripts/utils.js"></script> + <script src="/src/app/scripts/router.js"></script> + <script src="/src/app/scripts/main.js"></script> + </body> + </html> + ``` In the previous step, we wrote the following lines in `main.js`. -main.js +=== "main.js" -```js{2} -const outlet = document.querySelector("#content-outlet"); -const router = new Router(outlet); -// ... -``` + ```js linenums="1" + const outlet = document.querySelector("#content-outlet"); + const router = new Router(outlet); + // ... + ``` It works, because: - A function named `Router()` is defined in `router.js` @@ -45,42 +45,42 @@ It works, because: - `router.js` has been imported in `index.html` **before** `main.js` - `main.js` is also defined in the **global scope** (`window`) and has access to the `Router` function. -> **info** The **scope** is the range where a variable lives in. Out of the scope, the variable is no longer defined. -> -> In a `function`, the scope is usually the `function` itself. Out of the function, the scope is the global `window`. Everything defined in `window` can be accessed from everywhere. +!!! info "Infos" + The **scope** is the range where a variable lives in. Out of the scope, the variable is no longer defined. + In a `function`, the scope is usually the `function` itself. Out of the function, the scope is the global `window`. Everything defined in `window` can be accessed from everywhere. -router.js +=== "router.js" -```js{7} -(function () { - // ... - function Router(outlet) { + ```js linenums="1" + (function () { + // ... + function Router(outlet) { + // ... + } + // ... + window.Router = Router; + })(); + // ... - } - // ... - window.Router = Router; -})(); - -// ... -``` + ``` -index.html - -```html{10,11} -<!DOCTYPE html> -<html lang="en"> - <!-- ... --> - <head> - <!-- ... --> - </head> - <body> - <!-- ... --> - <script src="/src/app/scripts/utils.js"></script> - <script src="/src/app/scripts/router.js"></script> - <script src="/src/app/scripts/main.js"></script> - </body> -</html> -``` +=== "index.html" + + ```html linenums="1" + <!DOCTYPE html> + <html lang="en"> + <!-- ... --> + <head> + <!-- ... --> + </head> + <body> + <!-- ... --> + <script src="/src/app/scripts/utils.js"></script> + <script src="/src/app/scripts/router.js"></script> + <script src="/src/app/scripts/main.js"></script> + </body> + </html> + ``` Although putting all variables and functions in the global scope has been a popular way to share code between different scripts, it is far from ideal: @@ -89,52 +89,51 @@ Although putting all variables and functions in the global scope has been a popu - We are not able to know for sure if some value has been properly initialized. - Global scope pollution has **side-effects** and undetermined behavior. -## Global scope pollution <Diy /> +## Global scope pollution <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> - Edit `index.html` and swap the import for `main.js` with another one: - <details><summary> Try it yourself </summary> - index.html - - ```html{7} - <!DOCTYPE html> - <html lang="en"> - <!-- ... --> - <body> - <div id="content-outlet" class="h-100 w-100 d-flex flex-column"></div> - - <script src="./app/scripts/main.js"></script> - <script src="./app/scripts/welcome.js"></script> - <script src="./app/scripts/game.js"></script> - <script src="./app/scripts/score.js"></script> - <script src="./app/scripts/utils.js"></script> - <script src="./app/scripts/router.js"></script> - </body> - </html> - ``` -</details> +??? note "Try it yourself" + + === "index.html" + + ```html linenums="1" + <!DOCTYPE html> + <html lang="en"> + <!-- ... --> + <body> + <div id="content-outlet" class="h-100 w-100 d-flex flex-column"></div> + <script src="./app/scripts/main.js"></script> + <script src="./app/scripts/welcome.js"></script> + <script src="./app/scripts/game.js"></script> + <script src="./app/scripts/score.js"></script> + <script src="./app/scripts/utils.js"></script> + <script src="./app/scripts/router.js"></script> + </body> + </html> + ``` - Reload the page. You should have the following error in the browser console: - > **boom** - > - > ``` - > main.js:2 Uncaught ReferenceError: Router is not defined - > at main.js:2:16 - > ``` +!!! bug "BOOM" + ``` linenums="1" + main.js:2 Uncaught ReferenceError: Router is not defined + at main.js:2:16 + ``` Fortunately, with **_ES6 modules_** we now have the `import` and `export` keywords to better deal with dependencies. -## <i class="fa fa-cubes"></i> _ES6_ modules +## :fontawesome-solid-cubes: _ES6_ modules + +!!! info "Infos" + In a nutshell, an _ES6 module_, _ES module_, or **_ESM_** is a regular `.js` file that contains at least one `export` or one `import` statement. + + - Use the `export` keyword to make a piece of code importable. + - The `export` keyword can only be at the root level of the file. (eg: not in a function nor in a condition). + - Use the `import` keyword to import a piece of code that has been exported in an other module. -> **info** In a nutshell, an _ES6 module_, _ES module_, or **_ESM_** is a regular `.js` file that contains at least one `export` or one `import` statement. -> -> - Use the `export` keyword to make a piece of code importable. -> - The `export` keyword can only be at the root level of the file. (eg: not in a function nor in a condition). -> - Use the `import` keyword to import a piece of code that has been exported in an other module. -> -> See the [cheatsheet](../../cheatsheets/CHEATSHEET.md#es-modules) + See the [cheatsheet](../../cheatsheets/CHEATSHEET.md#es-modules) -### <i class="fa fa-file-export"></i> `export` <Diy /> <BadgeEasy /> +### :fontawesome-solid-file-export: `export` <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> <span id="easy">:fontawesome-solid-star: Easy</span> - Edit `router.js`. Look at the comments `TODO #export-router` for more instructions. @@ -144,102 +143,103 @@ Fortunately, with **_ES6 modules_** we now have the `import` and `export` keywor - Currently the app is using _IIFE_. Remove this _IIFE_ as well as the assignation into `window`. - > **info** _IIFE_ stands for **I**mmediately **I**nvoked **F**unction **E**xpression. - > It was often used before _ES Modules_ to define private scopes. - > Now, **everything in an _ES module_ is private unless it is exported**. +!!! info "Infos" + _IIFE_ stands for **I**mmediately **I**nvoked **F**unction **E**xpression. + It was often used before _ES Modules_ to define private scopes. + Now, **everything in an _ES module_ is private unless it is exported**. - <details><summary> Show the router.js file</summary> +??? note "Show the router.js file" - router.js: before - - ```js{1,11,13} - (function () { - // ... - function renderTemplate(outlet, template) { - /* ... */ - } - - function Router(outlet) { - /* ... */ - } + === "router.js: before" + + ```js linenums="1" + (function () { + // ... + function renderTemplate(outlet, template) { + /* ... */ + } + + function Router(outlet) { + /* ... */ + } - window.Router = Router; - // ... - })(); - ``` + window.Router = Router; + // ... + })(); + ``` - router.js: after + === "router.js: after" - ```js{7} + ```js linenums="1" - // ... - function renderTemplate(outlet, template) { - /* ... */ - } + // ... + function renderTemplate(outlet, template) { + /* ... */ + } - export function Router(outlet) { - /* ... */ - } - // ... - ``` - </details> + export function Router(outlet) { + /* ... */ + } + // ... + ``` ### <i class="fa fa-file-import"></i> `import` <Diy /> <BadgeEasy /> - Edit `main.js`. Look at `TODO #import-router` for instructions. Use a [**named import**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import) to import the previously exported `Router`. - <details><summary> Show the main.js file </summary> - main.js +??? note "Show the main.js file" + === "main.js" - ```js - import { Router } from "./router"; + ```js linenums="1" + import { Router } from "./router"; - const outlet = document.querySelector("#content-outlet"); - const router = new Router(outlet); - router.register("", { - component: WelcomeComponent, - templateUrl: "/src/app/views/welcome.html", - }); - // ... - ``` - </details> + const outlet = document.querySelector("#content-outlet"); + const router = new Router(outlet); + router.register("", { + component: WelcomeComponent, + templateUrl: "/src/app/views/welcome.html", + }); + // ... + ``` - Refresh the page once `Router` is properly exported and imported. It should produce these errors: - > **boom** - > - > ``` - > Uncaught SyntaxError: Unexpected token 'export' (at router.js:18:1) - > Uncaught SyntaxError: Cannot use import statement outside a module (at main.js:1:1) - > ``` +!!! bug "Boom" + + ``` + Uncaught SyntaxError: Unexpected token 'export' (at router.js:18:1) + Uncaught SyntaxError: Cannot use import statement outside a module (at main.js:1:1) + ``` - The keyword `export` is not recognized - The static `import` refuses to execute. You have these errors even if `import` and `export` are defined in the _ES6_ standard and your web browser is up to date. - > **danger** Static `import` and `export` does not work as is on a web browser. That's why a **_bundler_ is required** +!!! danger "Danger" + Static `import` and `export` does not work as is on a web browser. That's why a **_bundler_ is required** -#### <i class="fas fa-folder-tree"></i> Modified files +#### :fontawesome-solid-folder-tree: Modified files ``` src/app/scripts/main.js src/app/scripts/router.js ``` -#### <i class="fa fa-list-check"></i> Checklist +#### :fontawesome-solid-list-check: Checklist -- [ ] I know what an _ES Module_ is. -- [ ] I know how to use the `export` keyword and do **named exports**. -- [ ] I know how to use the `import` keyword and do **named imports**. -- [ ] The codebase has no unresolved `TODO #export-router` comments left. -- [ ] The codebase has no unresolved `TODO #import-router` comments left. -- [ ] I understand why _IIFE_ were needed. +- <input type="checkbox" /> I know what an _ES Module_ is. +- <input type="checkbox" /> I know how to use the `export` keyword and do **named exports**. +- <input type="checkbox" /> I know how to use the `import` keyword and do **named imports**. +- <input type="checkbox" /> The codebase has no unresolved `TODO #export-router` comments left. +- <input type="checkbox" /> The codebase has no unresolved `TODO #import-router` comments left. +- <input type="checkbox" /> I understand why _IIFE_ were needed. -<!-- > **tip** Both regular JavaScript files and _ES Modules_ have the extension `.js`, although **they behave very differently**. To make it easier to recognize _ES Modules_, you can rename them with the `.mjs` file extension instead of `.js`. --> +!!! tip "Tips" + Both regular JavaScript files and _ES Modules_ have the extension `.js`, although **they behave very differently**. To make it easier to recognize _ES Modules_, you can rename them with the `.mjs` file extension instead of `.js`. --> -## <i class="fa fa-cubes"></i> The _bundler_ <BadgeHard /> +## :fontawesome-solid-cubes: The _bundler_ <span id="hard">:fontawesome-solid-star: :fontawesome-solid-star: :fontawesome-solid-star: Hard</span> > **info** A _Bundler_ is a build tool used to **resolve `import` and `export` statements**. _Bundlers_ usually work with `require()` and `module.exports` as well (NodeJS counterpart). > A _bundler_ produces a **_bundle_**: a single `.js` file with all sources concatenated together. @@ -247,6 +247,7 @@ src/app/scripts/router.js In this step, we will use **[_Webpack_](https://Webpack.js.org/)**, the most popular _bundler_, to _bundle_ our code. It is versatile and can be configured with a huge set of official and community plugins to extend its capabilities: + - **optimize** source code - generate **source maps** - **uglify / minifies** the source code @@ -254,101 +255,103 @@ It is versatile and can be configured with a huge set of official and community - create a **development server with live-reload** - ... and much more -### <i class="fa fa-file-download"></i> Install [_Webpack_](https://www.npmjs.com/package/webpack) <Diy /> +### :fontawesome-solid-file-arrow-down: Install [_Webpack_](https://www.npmjs.com/package/webpack) <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> Install _Webpack_ along with its CLI and development server: -```bash +```bash linenums="1" cd front-end npm install -D webpack webpack-cli webpack-dev-server html-webpack-plugin ``` -### <i class="fa fa-wrench"></i> `webpack.config.js` <Diy /> +### :fontawesome-solid-hammer: `webpack.config.js` <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> Create a new file called [`webpack.config.js`](https://webpack.js.org/configuration/), with a minimal _Webpack_ configuration: -webpack.config.js - -```javascript{5} -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -module.exports = { - mode: "development", - devtool: "inline-source-map", - entry: "./src/main.js", - devServer: { - static: { - directory: path.join(__dirname), - }, - }, - plugins: [ - new HtmlWebpackPlugin({ - filename: "index.html", - template: "./src/index.html", - }), - ], - optimization: { - minimize: false, - }, - module: { - rules: [], - }, -}; -``` +=== "webpack.config.js" + + ```javascript linenums="1" + const path = require("path"); + const HtmlWebpackPlugin = require("html-webpack-plugin"); + module.exports = { + mode: "development", + devtool: "inline-source-map", + entry: "./src/main.js", + devServer: { + static: { + directory: path.join(__dirname), + }, + }, + plugins: [ + new HtmlWebpackPlugin({ + filename: "index.html", + template: "./src/index.html", + }), + ], + optimization: { + minimize: false, + }, + module: { + rules: [], + }, + }; + ``` -> **tip** The [`devtool: "inline-source-map"`](https://webpack.js.org/configuration/devtool/) option generates the **source maps**. Simply put, this option will allow _Webpack_ to provide source maps to the _bundle_, so that the browser can reconstruct the original source code. +!!! tip "Tips" + The [`devtool: "inline-source-map"`](https://webpack.js.org/configuration/devtool/) option generates the **source maps**. Simply put, this option will allow _Webpack_ to provide source maps to the _bundle_, so that the browser can reconstruct the original source code. The _bundler_ uglifies, minifies and merges all code files into a single _bundle_, which makes it hard to debug. -<details> <summary> Show the bundled code snippet </summary> +??? note "Show the bundled code snippet" -```javascript -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _app_utils_utils__WEBPACK_IMPORTED_MODULE_0__ = - __webpack_require__( - /*! ./app/scripts/router */ "./app/scripts/router.js" - ); -// front-end/src/main.js -``` -Not pretty to debug, isn't it? That is why we asked for source maps in the _Webpack_ configuration file. This will help us while debugging. -</details> + ```javascript linenums="1" + __webpack_require__.r(__webpack_exports__); + /* harmony import */ var _app_utils_utils__WEBPACK_IMPORTED_MODULE_0__ = + __webpack_require__( + /*! ./app/scripts/router */ "./app/scripts/router.js" + ); + // front-end/src/main.js + ``` + Not pretty to debug, isn't it? That is why we asked for source maps in the _Webpack_ configuration file. This will help us while debugging. In `webpack.config.js` we also set `src/main.js` as the project entrypoint (this is the default value). - Move `src/app/scripts/main.js` => `src/main.js`. - > **info** Only files imported in the entrypoint file (`src/main.js`) and onward will be part of the _bundle_. +!!! info "Infos" + Only files imported in the entrypoint file (`src/main.js`) and onward will be part of the _bundle_. - Edit `index.html`. Look at the `TODO #import-js` comments for instructions. Remove `main.js` and `router.js` imports, as this is now managed by _Webpack_ itself. -### <i class="fa fa-play"></i> Serve with _Webpack_ <Diy /> +### :fontawesome-solid-play: Serve with _Webpack_ <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> -> **info** _Webpack_ has its own web development server. It watches the code and reloads the browser automatically on changes. +!!! info "Infos" + _Webpack_ has its own web development server. It watches the code and reloads the browser automatically on changes. - Edit `package.json`. Replace the `start` script to use the _Webpack_ command: - package.json +=== "package.json" - ```json - { - "scripts": { - "start": "webpack serve" + ```json linenums="1" + { + "scripts": { + "start": "webpack serve" + } } - } - ``` + ``` - Remove `http-server` from the dependencies. From now, we are going to use `webpack serve` instead. - <details><summary> Show the npm remove command</summary> +??? note "Show the npm remove command" - ```bash - npm remove http-server - ``` - </details> + ```bash linenums="1" + npm remove http-server + ``` Now, you should be able to start the application. Kill the old `http-server` and start a new _Webpack Development Server_: -```bash + +```bash linenums="1" npm run start ``` @@ -357,69 +360,68 @@ Attention, we now browse localhost:8080 and not localhost:8080/src. Change the `navbar-brand` link to point toward `/` instead of `/src` in `welcome.html`, `game.html` and `score.html` files. -<details><summary> Show the resulting HTML file </summary> - -```html{10} -<!DOCTYPE html> -<html lang="en"> - <head> - <!-- ... --> - </head> - - <body> - <nav class="navbar bg-primary mb-3 shadow"> - <div class="container-fluid"> - <a class="navbar-brand d-flex" href="/"> - <img - class="d-inline-block align-top" - src="/src/assets/logo_take_my_money.png" - alt="logo" - /> - <span class="align-self-center m-2">MÈME ory</span> - </a> - <span class="navbar-title"></span> - </div> - </nav> - <!-- ... --> - </body> -</html> -``` -</details> +??? note "Show the resulting HTML file" + + ```html linenums="1" + <!DOCTYPE html> + <html lang="en"> + <head> + <!-- ... --> + </head> + <body> + <nav class="navbar bg-primary mb-3 shadow"> + <div class="container-fluid"> + <a class="navbar-brand d-flex" href="/"> + <img + class="d-inline-block align-top" + src="/src/assets/logo_take_my_money.png" + alt="logo" + /> + <span class="align-self-center m-2">MÈME ory</span> + </a> + <span class="navbar-title"></span> + </div> + </nav> + <!-- ... --> + </body> + </html> + ``` -### <i class="fa fa-hammer"></i> Build with Webpack <Diy /> +### :fontawesome-solid-hammer: Build with Webpack <span id="diy">:fontawesome-solid-wrench: Do it yourself</span> You can also build the application for production. To do this, add a `build` script in the `package.json` file: -package.json +=== "package.json" -```json -"scripts": { - "build": "webpack build --mode=production --no-devtool", - "start": "webpack serve", - "test": "echo \"Error: no test specified\" && exit 1" -}, -``` + ```json linenums="1" + "scripts": { + "build": "webpack build --mode=production --no-devtool", + "start": "webpack serve", + "test": "echo \"Error: no test specified\" && exit 1" + }, + ``` -> **danger** Ensure you **disable the source maps for production builds** since it will weight the _bundle_ a lot and give access to the original application source code to everyone. -> Here this is done with the `--mode=production --no-devtool` flag. +!!! danger "Danger" + Ensure you **disable the source maps for production builds** since it will weight the _bundle_ a lot and give access to the original application source code to everyone. + Here this is done with the `--mode=production --no-devtool` flag. -```bash +```bash linenums="1" npm run build ``` Look at the resulting build, located in the `dist/` folder. -<details><summary> Show the dist/ folder </summary> +??? note "Show the dist/ folder" -``` -[4.0K] dist/ -├── [1.1K] index.html -└── [4.2K] main.js -``` -</details> + ``` + [4.0K] dist/ + ├── [1.1K] index.html + └── [4.2K] main.js + ``` -> **danger** Do not forget to add the `dist/` folder in `.gitignore`. +!!! danger "Danger" + Do not forget to add the `dist/` folder in `.gitignore`. -#### <i class="fas fa-folder-tree"></i> Modified files +#### :fontawesome-solid-folder-tree: Modified files ``` src/main.js @@ -430,28 +432,16 @@ package.json package-lock.json ``` -#### <i class="fa fa-list-check"></i> Checklist - -- [ ] I understand why _bundlers_ are needed -- [ ] I know how to write a basic _Webpack_ configuration -- [ ] I can build an application with _Webpack_ -- [ ] I can serve an application with _Webpack_ -- [ ] The codebase has no unresolved `TODO #import-js` comments left. - -> **question** Build the code with `npm run build` and look at the code generated in `dist/main.js`. -> -> - What is the size of this file? -> - The source code for `welcome.js`, `game.js` and `score.js` has not been bundled at all. Why? +#### :fontawesome-solid-list-check: Checklist -## <i class="fas fa-graduation-cap"></i> Assessment +- <input type="checkbox" /> I understand why _bundlers_ are needed +- <input type="checkbox" /> I know how to write a basic _Webpack_ configuration +- <input type="checkbox" /> I can build an application with _Webpack_ +- <input type="checkbox" /> I can serve an application with _Webpack_ +- <input type="checkbox" /> The codebase has no unresolved `TODO #import-js` comments left. -<iframe src="https://docs.google.com/forms/d/e/1FAIpQLSdzd5BXpKEJ5F1mtPcSuM3pn8ozs5WzHHllvsdVUavYQMCn5A/viewform?embedded=true" width="100%" height="640" frameborder="0" marginheight="0" marginwidth="0">Chargement…</iframe> +!!! question "Question" + Build the code with `npm run build` and look at the code generated in `dist/main.js`. -<style> -summary { - color: #cb2468; - text-align: center; - margin-bottom: 20px; - margin-top: 20px -} -</style> \ No newline at end of file + - What is the size of this file? + - The source code for `welcome.js`, `game.js` and `score.js` has not been bundled at all. Why? diff --git a/resources/docs/docs/stylesheets/global.css b/resources/docs/docs/stylesheets/global.css index ec2a44bec3a38f707d899f56e3fb899941fb1add..cd933f13dacb580f0a6da57564682368b60e7c0f 100644 --- a/resources/docs/docs/stylesheets/global.css +++ b/resources/docs/docs/stylesheets/global.css @@ -2,7 +2,7 @@ h2, h3 { color: #cb2468; font-weight: 500 !important; ; } -#getting-started, #the-package-manager, #single-page-application-spa { +#getting-started, #the-package-manager, #single-page-application-spa, #webpack { color: #cb2468; font-weight: 700; } @@ -18,6 +18,7 @@ h2, h3 { color: white; padding: 5px; border-radius: 10px; + font-size: 17px; } #commit { @@ -27,3 +28,28 @@ h2, h3 { border-radius: 3px; color: white; } + +#download { + background-color: #cb2468; + padding: 5px; + width: fit-content; + border-radius: 5px; + color: white; +} + +#easy, #medium, #hard { + background-color: #69ce01; + width: fit-content; + padding: 3px; + color: white; + border-radius: 2px; + font-size: 15px; +} + +#medium { + background-color: #f3980e; +} + +#hard { + background-color: #cb0202; +} \ No newline at end of file