diff --git a/resources/docs/docs/chapters/tp/arrow-functions.md b/resources/docs/docs/chapters/tp/arrow-functions.md index 1e655fb5f653427534090ff7fcaa0ad8a1255ae4..8649f497e1f0c1ad64d11ff9366f914bbd9c11de 100644 --- a/resources/docs/docs/chapters/tp/arrow-functions.md +++ b/resources/docs/docs/chapters/tp/arrow-functions.md @@ -25,7 +25,7 @@ Open `game.js` and look at the `goToScore()` method. It is called once all card setTimeout( function () { const scorePage = "#score"; - scorePage + + window.location = scorePage + "?name=" + this._name + "&size=" + @@ -88,7 +88,7 @@ Example: // ... setTimeout(function () => { const scorePage = "#score"; - scorePage + + window.location = scorePage + "?name=" + this._name + "&size=" + @@ -110,7 +110,7 @@ Example: // ... setTimeout(() => { const scorePage = "#score"; - scorePage + + window.location = scorePage + "?name=" + this._name + "&size=" + diff --git a/resources/docs/docs/chapters/tp/asynchronous.md b/resources/docs/docs/chapters/tp/asynchronous.md index ff71aa1dbc3e32777642f6909532098cae9f2992..5166aecf06334e69ea63b094a3fdd7a11feada1e 100644 --- a/resources/docs/docs/chapters/tp/asynchronous.md +++ b/resources/docs/docs/chapters/tp/asynchronous.md @@ -21,187 +21,183 @@ element.addEventListener("click", () => { Things start to get messy when a callback call returns other callbacks, because the execution order is really different from the writing order: -> **info** A piece of code that uses too much callbacks is called a **_callback hell_**. -> :::spoiler Show an example of a callback hell -> -> ```js{3,5,9,13} -> // "done" callback needs to be passed as argument all around -> -> function inbox(done) { -> httpGetContacts((contacts) => -> contacts.forEach((c) => printLastMessage(c, done)) -> ); -> } -> -> function printLastMessage(contact, done) { -> httpGetProfilePicture(contact, (picture) => { -> httpGetMessages(contact, (messages) => { -> printMessage(contact, picture, messages[0]); -> done(); -> }); -> }); -> } -> ``` -> -> ::: +!!! info "Infos" + A piece of code that uses too much callbacks is called a **_callback hell_**. + +???tip "Show an example of a callback hell" + + ```js linenums="1" + // "done" callback needs to be passed as argument all around + + function inbox(done) { + httpGetContacts((contacts) => + contacts.forEach((c) => printLastMessage(c, done)) + ); + } + + function printLastMessage(contact, done) { + httpGetProfilePicture(contact, (picture) => { + httpGetMessages(contact, (messages) => { + printMessage(contact, picture, messages[0]); + done(); + }); + }); + } + ``` ## `Promise` _ES6_ came with the new **[`Promise` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** to write asynchronous code. -> **info** A `Promise` is an object that represents the eventual completion or failure of an asynchronous operation. -> -> - It has a `.then()` method to gather the resulting value. -> - Because `.then()` returns a promise itself, promises can be chained together. -> -> :::spoiler Show an example of a Promise -> -> ```js -> function inbox() { -> return httpGetContacts().then((contacts) => -> Promise.all(printLastMessage(contact)) -> ); -> } -> -> function printLastMessage(contact) { -> let messages, picture; -> return httpGetProfilePicture(contact) -> .then((p) => { -> picture = p; -> httpGetMessages(contact); -> }) -> .then((messages) => printMessage(contact, picture, messages[0])); -> } -> ``` -> -> ::: +!!! info "Infos" + A `Promise` is an object that represents the eventual completion or failure of an asynchronous operation. + +- It has a `.then()` method to gather the resulting value. +- Because `.then()` returns a promise itself, promises can be chained together. + +???tip "Show an example of a Promise" + + ```js linenums="1" + function inbox() { + return httpGetContacts().then((contacts) => + Promise.all(printLastMessage(contact)) + ); + } + + function printLastMessage(contact) { + let messages, picture; + return httpGetProfilePicture(contact) + .then((p) => { + picture = p; + httpGetMessages(contact); + }) + .then((messages) => printMessage(contact, picture, messages[0])); + } + ``` ## `async` / `await` In addition to `Promise`, _ES8_ introduced the [`async` and `await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) keywords, to simplify the `Promise` usage. -> **info** Any function can be declared with the `async` keyword. When a function is async, it returns a `Promise` and can use the `await` keyword to call other `async` functions without the need of configuring the Promise chain. +!!!info "Infos" + Any function can be declared with the `async` keyword. When a function is async, it returns a `Promise` and can use the `await` keyword to call other `async` functions without the need of configuring the Promise chain. -:::code-tabs -@tab with callbacks +=== "with callbacks" -```js -function inbox(done) { - httpGetContacts((contacts) => - contacts.forEach((c) => printLastMessage(c, done)) - ); -} - -function printLastMessage(contact, done) { - httpGetProfilePicture(contact, (picture) => { - httpGetMessages(contact, (messages) => { - printMessage(contact, picture, messages[0]); - done(); - }); - }); -} -``` + ```js linenums="1" + function inbox(done) { + httpGetContacts((contacts) => + contacts.forEach((c) => printLastMessage(c, done)) + ); + } -@tab with promises + function printLastMessage(contact, done) { + httpGetProfilePicture(contact, (picture) => { + httpGetMessages(contact, (messages) => { + printMessage(contact, picture, messages[0]); + done(); + }); + }); + } + ``` -```js -function inbox() { - return httpGetContacts().then((contacts) => - Promise.all(printLastMessage(contact)) - ); -} -function printLastMessage(contact) { - let messages, picture; - return httpGetProfilePicture(contact) - .then((p) => { - picture = p; - httpGetMessages(contact); - }) - .then((messages) => printMessage(contact, picture, messages[0])); -} -``` +=== "with promises" + + ```js linenums="1" + function inbox() { + return httpGetContacts().then((contacts) => + Promise.all(printLastMessage(contact)) + ); + } + function printLastMessage(contact) { + let messages, picture; + return httpGetProfilePicture(contact) + .then((p) => { + picture = p; + httpGetMessages(contact); + }) + .then((messages) => printMessage(contact, picture, messages[0])); + } + ``` -@tab with async / await +=== "with async / await" -```js -async function inbox() { - const contacts = await httpGetContacts(); - - for (const contact of contacts) { - const picture = await httpGetProfilePicture(contact); - const messages = await httpGetMessages(contact); - printMessage(contact, picture, messages[0]); - } -} -``` + ```js linenums="1" + async function inbox() { + const contacts = await httpGetContacts(); -::: + for (const contact of contacts) { + const picture = await httpGetProfilePicture(contact); + const messages = await httpGetMessages(contact); + printMessage(contact, picture, messages[0]); + } + } + ``` -> **tip** Compared to using callback, `Promise` and `async/await` improve the code readability writing statements in the same order as they are executed. +!!!tip "Tips" + Compared to using callback, `Promise` and `async/await` improve the code readability writing statements in the same order as they are executed. ## `fetch` With _ES5_, we used to need the ugly `XMLHttpRequest` to write _Ajax_ requests. -> **info** _Ajax_ (Asynchronous JavaScript And XML) is the way JavaScript fetches resources with asynchronous HTTP requests. +!!!info "Infos" + _Ajax_ (Asynchronous JavaScript And XML) is the way JavaScript fetches resources with asynchronous HTTP requests. Now with _ES6_, _AJAX_ calls are made with the new [`fetch` function](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) that returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). -:::code-tabs -@tab game.js - XMLHttpRequest 😩 - -```js -fetchConfig(cb) { - var xhr = typeof XMLHttpRequest != 'undefined' - ? new XMLHttpRequest() - : new ActiveXObject('Microsoft.XMLHTTP'); - - xhr.open('get', environment.api.host + '/board?size=' + this._size, true); - - xhr.onreadystatechange = function() { - var status; - var data; - // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate - if (xhr.readyState == 4) { // `DONE` - status = xhr.status; - if (status == 200) { - data = JSON.parse(xhr.responseText); - cb(data); - } else { - throw new Error(status) - } +=== "game.js - XMLHttpRequest 😩" + + ```js linenums="1" + fetchConfig(cb) { + var xhr = typeof XMLHttpRequest != 'undefined' + ? new XMLHttpRequest() + : new ActiveXObject('Microsoft.XMLHTTP'); + + xhr.open('get', environment.api.host + '/board?size=' + this._size, true); + + xhr.onreadystatechange = function() { + var status; + var data; + // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate + if (xhr.readyState == 4) { // `DONE` + status = xhr.status; + if (status == 200) { + data = JSON.parse(xhr.responseText); + cb(data); + } else { + throw new Error(status) + } + } + }; + xhr.send(); } - }; - xhr.send(); -} -``` + ``` -@tab game.js - fetch + promise 🙂 - -```js -export class GameComponent extends Component { - fetchConfig() { - return fetch(`${environment.api.host}/board?size=${this._size}`).then( - (response) => response.json() - ); - } -} -``` +=== "game.js - fetch + promise 🙂" -@tab game.js - fetch + async/await 😎 + ```js linenums="1" + export class GameComponent extends Component { + fetchConfig() { + return fetch(`${environment.api.host}/board?size=${this._size}`).then( + (response) => response.json() + ); + } + } + ``` -```js -export class GameComponent extends Component { - async fetchConfig() { - const response = await fetch( - `${environment.api.host}/board?size=${this._size}` - ); - return response.json(); - } -} -``` +=== "game.js - fetch + async/await 😎" -::: + ```js linenums="1" + export class GameComponent extends Component { + async fetchConfig() { + const response = await fetch( + `${environment.api.host}/board?size=${this._size}` + ); + return response.json(); + } + } + ``` ## fetch + promises + async <Diy /> <BadgeMedium /> @@ -211,32 +207,31 @@ export class GameComponent extends Component { - Rewrite the method `GameComponent.init()` to use the returned `Promise` instead of passing a callback. - > **warning** Remember, an `async` method can only be _awaited_ from a method that is `async` itself. - - ::::spoiler Show the game.js file - :::code-tabs +!!!warning "Warning" + Remember, an `async` method can only be _awaited_ from a method that is `async` itself. - @tab game.js +???note "Show the game.js file" + === "game.js" - ```js{4,5,12} - // ... + ```js linenums="1" + // ... - export class GameComponent extends Component { - async init() { - this._config = await this.fetchConfig(); - this._boardElement = document.querySelector(".cards"); - // ... - } + export class GameComponent extends Component { + async init() { + this._config = await this.fetchConfig(); + this._boardElement = document.querySelector(".cards"); + // ... + } - // ... + // ... - async fetchConfig() { - return fetch(`${environment.api.host}/board?size=${this._size}`).then( - (r) => r.json() - ); - } - } - ``` + async fetchConfig() { + return fetch(`${environment.api.host}/board?size=${this._size}`).then( + (r) => r.json() + ); + } + } + ``` #### <i class="fas fa-folder-tree"></i> Modified files diff --git a/resources/docs/docs/chapters/tp/babel.md b/resources/docs/docs/chapters/tp/babel.md index 66a1c370c27a7c8ff7e05ad88478842a7f1e0031..ab90f02f81c3c7a5c9e3d65eea809a14bfe14dd1 100644 --- a/resources/docs/docs/chapters/tp/babel.md +++ b/resources/docs/docs/chapters/tp/babel.md @@ -36,38 +36,37 @@ We are going to use [**_Babel_**](https://babeljs.io/) in this project, probably #### Configuration - Create a new file at the root of the `front-end/` folder and call it [`.babelrc`](https://babeljs.io/docs/en/config-files). - :::code-tabs - @tab .babelrc - - ```json - { - "presets": [["@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 }]], - "plugins": [] - } - ``` - ::: + === ".babelrc" + + ```json + { + "presets": [["@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 }]], + "plugins": [] + } + ``` In this file, we can precisely configure the way _Babel_ transpiles our code. In our case, we use a preset called [`@babel/preset-env`](https://babeljs.io/docs/en/babel-preset-env) which automatically defines the transpilation level. - > **info** Under the hood, `@babel/preset-env` uses [browserslist](https://github.com/browserslist/browserslist). Browserlist is an open-source project that lists all most famous platforms (browsers, nodejs, electron, ...), as well as their supported features. +!!!info "Infos" + Under the hood, `@babel/preset-env` uses [browserslist](https://github.com/browserslist/browserslist). Browserlist is an open-source project that lists all most famous platforms (browsers, nodejs, electron, ...), as well as their supported features. - At the root of the `front-end/` folder, create a new file and call it `browserslist`. With this file, we can configure the platforms we want to support. - :::code-tabs - @tab browserslist - ``` - > 0.25% - ie 9 - ``` - ::: +=== "browserslist" + + ``` + > 0.25% + ie 9 + ``` With the config above, we tell _Babel_ to adjust the transpilation level, so our code is: - compatible with at least 99.75% users - compatible with Internet Explorer 9 - > **danger** **Transpilation has a cost**. Transpiled code is heavier and its perfomance is worse than modern code ; whereas modern code is less compatible with old browsers. Adjusting the transpiler level is a **tradeoff between performance and compatibility**. +!!!danger "Danger" + **Transpilation has a cost**. Transpiled code is heavier and its perfomance is worse than modern code ; whereas modern code is less compatible with old browsers. Adjusting the transpiler level is a **tradeoff between performance and compatibility**. ### <i class="fa fa-cog"></i> Transpile the code @@ -79,47 +78,45 @@ We are going to use [**_Babel_**](https://babeljs.io/) in this project, probably - Have a look at the generated `utils.js` file in the `dist/` folder: - :::code-tabs - @tab dist/utils.js +=== "dist/utils.js" - ```js{3,13,15,17} - "use strict"; + ```js linenums="1" + "use strict"; - require("core-js/modules/es.symbol.js"); + require("core-js/modules/es.symbol.js"); - // ... + // ... - function ownKeys(object, enumerableOnly) { /* ... */ } - function _objectSpread(target) { /* ... */ } + function ownKeys(object, enumerableOnly) { /* ... */ } + function _objectSpread(target) { /* ... */ } - // ... + // ... - function parseUrl() { - var _window$location$href; + function parseUrl() { + var _window$location$href; - return ((_window$location$href = window.location.href.split("?")[1]) /* ... */).split("&").map(function (q) { - return q.split("="); - }).reduce(function (params, _ref) { - var _ref2 = _slicedToArray(_ref, 2), - k = _ref2[0], - v = _ref2[1]; + return ((_window$location$href = window.location.href.split("?")[1]) /* ... */).split("&").map(function (q) { + return q.split("="); + }).reduce(function (params, _ref) { + var _ref2 = _slicedToArray(_ref, 2), + k = _ref2[0], + v = _ref2[1]; - return _objectSpread(_objectSpread({}, params), {}, _defineProperty({}, k, v)); - }, {}); - } - ``` + return _objectSpread(_objectSpread({}, params), {}, _defineProperty({}, k, v)); + }, {}); + } + ``` - @tab utils.js +=== "utils.js" - ```js{} - export function parseUrl() { - return (window.location.href.split("?")[1] ?? "") - .split("&") - .map((q) => q.split("=")) - .reduce((params, [k, v]) => ({ ...params, [k]: v }), {}); - } - ``` - ::: + ```js linenums="1" + export function parseUrl() { + return (window.location.href.split("?")[1] ?? "") + .split("&") + .map((q) => q.split("=")) + .reduce((params, [k, v]) => ({ ...params, [k]: v }), {}); + } + ``` - There are several requirements on `core-js/...`. - `let` / `const` have been replaced with `var`. @@ -128,25 +125,25 @@ We are going to use [**_Babel_**](https://babeljs.io/) in this project, probably As we can see, _Babel_ has converted our code to old _ES5_. However, the transpiled code still uses the new features (eg: `Array.map`, `Array.reduce`), -> **question** -> -> - How did _Babel_ transpile `game.component.js`? -> - Edit `browserslist` to lower the compatibility level: -> :::code-tabs -> @tab browserslist -> -> ``` -> > 1.00% -> not dead -> ``` -> -> ::: -> What does the transpiled code look like? What is its new size? +!!!question "Question" + + - How did _Babel_ transpile `game.component.js`? + - Edit `browserslist` to lower the compatibility level: + + === "browserslist" + + ``` + > 1.00% + not dead + ``` + + What does the transpiled code look like? What is its new size? ## Polyfills -> **info** Transpilers like _Babel_ only transform the modern syntax (eg: `let` => `var`; `() => {}` => `function() {}`) to an old one. -> To support new features, _Babel_ relies on external _polyfills_ like the `core-js` library. +!!!info "Infos" + Transpilers like _Babel_ only transform the modern syntax (eg: `let` => `var`; `() => {}` => `function() {}`) to an old one. + To support new features, _Babel_ relies on external _polyfills_ like the `core-js` library. ### `core-js` <Diy/> @@ -156,7 +153,8 @@ As we can see, _Babel_ has converted our code to old _ES5_. However, the transpi npm install core-js@3 ``` - > **danger** Transpilers are `devDependencies` but, **polyfills have to be installed as `dependencies`**. +!!!danger "Danger" + Transpilers are `devDependencies` but, **polyfills have to be installed as `dependencies`**. _Babel_ integrates automatically with `core-js`, so there is nothing more to do 👍. @@ -174,27 +172,28 @@ Fortunately, _Webpack_ can automate this step with the [`webpack-babel-loader`]( ``` - Edit `webpack.config.js` and add a rule to use `webpack-babel-loader` on `*.js` files: - :::code-tabs - @tab webpack.config.js - ```js - // ... - module: { - rules: [ - // ... - { - test: /\.m?js$/, - exclude: /(node_modules|bower_components)/, - use: { - loader: "babel-loader", - options: { - presets: ["@babel/preset-env"], + +=== "webpack.config.js" + + ```js linenums="1" + // ... + module: { + rules: [ + // ... + { + test: /\.m?js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: "babel-loader", + options: { + presets: ["@babel/preset-env"], + }, }, }, - }, - ]; - } - ``` - ::: + ]; + } + ``` + - Build the application again: ```bash @@ -203,28 +202,25 @@ Fortunately, _Webpack_ can automate this step with the [`webpack-babel-loader`]( Look at the sources generated in the `dist/` folder and ensure everything is properly transpiled. - > **question** What was the size of the `dist/` folder before transpilation? What is its size after? - > - > ::::spoiler Show the `dist/` folder size - > :::code-tabs - > @tab before babel - > - > ``` - > [4.0K] dist/ - > ├── [ 729] index.html - > └── [294K] main.js - > ``` - > - > @tab after babel - > - > ``` - > [4.0K] dist/ - > ├── [ 729] index.html - > └── [328K] main.js - > ``` - > - > ::: - > :::: +!!!question "What was the size of the `dist/` folder before transpilation? What is its size after?" + +??? "Show the `dist/` folder size" + + === "before babel" + + ``` + [4.0K] dist/ + ├── [ 729] index.html + └── [294K] main.js + ``` + + === "after babel" + + ``` + [4.0K] dist/ + ├── [ 729] index.html + └── [328K] main.js + ``` #### <i class="fas fa-folder-tree"></i> Modified files diff --git a/resources/docs/docs/chapters/tp/components.md b/resources/docs/docs/chapters/tp/components.md index 87f85bd9a0d566381672eb4d02b4f4447df16a26..21491129f3cdf5047b18687f4a61138952422031 100644 --- a/resources/docs/docs/chapters/tp/components.md +++ b/resources/docs/docs/chapters/tp/components.md @@ -9,20 +9,20 @@ tag: Nowadays, most of the front-ends are designed using the _Component Oriented Architecture_. - + -> **info** Simply put, a component is a piece of code (eg: a _class_) that defines one specific element on the page. -> Components are usually **small**, **standalone** and **reusable**. +!!!info "Infos" + Simply put, a component is a piece of code (eg: a _class_) that defines one specific element on the page. + Components are usually **small**, **standalone** and **reusable**. ## Separation of technology The application has three pages: _Welcome_, _Game_ and _Score_, using the [_MVC architecture_](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). -:::spoiler What is MVC? +???question "What is MVC?" -> **info** The _Model-View-Controller_ (**MVC**) architecture is a software architectural pattern commonly used to develop user interfaces. This pattern divides the source code into three interconnected type of elements: the model, the view and the controller. [source: Wikipedia](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) - -::: + !!!info + The _Model-View-Controller_ (**MVC**) architecture is a software architectural pattern commonly used to develop user interfaces. This pattern divides the source code into three interconnected type of elements: the model, the view and the controller. [source: Wikipedia](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) Let's have a quick look at the current application file structure: @@ -36,19 +36,17 @@ Although this architecture was very common long time ago *(in a galaxy, far far It is more convenient to group files by domain/concern rather than technology to **isolate the changes**. -:::tabs - -@tab MVC (separation of technologies) - +=== "MVC (separation of technologies)" +  -@tab Components Oriented (separation of concerns) - +=== "Components Oriented (separation of concerns)" +  -::: ## Separation of concerns -> **tip** With component oriented programming, pages and features are encapsulated into reusable components. This way, we promote better **separation of concerns** rather than **separation of technologies**. +!!!tip "Tips" + With component oriented programming, pages and features are encapsulated into reusable components. This way, we promote better **separation of concerns** rather than **separation of technologies**. #### <i class="fa fa-folder-tree"></i> Let's change our file structure <Diy/> @@ -58,16 +56,14 @@ It is more convenient to group files by domain/concern rather than technology to - `src/app/components/game/card` - `src/app/components/score` - :::spoiler Show the commands - - ```bash - mkdir -p src/app/components/welcome - mkdir -p src/app/components/score - mkdir -p src/app/components/game - mkdir -p src/app/components/game/card - ``` +???note "Show the commands" - ::: + ```bash linenums="1" + mkdir -p src/app/components/welcome + mkdir -p src/app/components/score + mkdir -p src/app/components/game + mkdir -p src/app/components/game/card + ``` #### <i class="fab fa-html5"></i> <i class="fab fa-js"></i> Isolate _HTML_ and _JS_ <Diy /> @@ -78,35 +74,35 @@ It is more convenient to group files by domain/concern rather than technology to src/app/views/X.html => src/app/components/X.component.html ``` - > **tip** The `.component` suffix is a convention to tell `X.component.html` and `X.component.js` relate to the same concern _X_. +!!!tip "Tips" + The `.component` suffix is a convention to tell `X.component.html` and `X.component.js` relate to the same concern _X_. - :::spoiler Show the commands +???note "Show the commands" - ```bash - mv ./src/app/scripts/welcome.js ./src/app/components/welcome/welcome.component.js - mv ./src/app/views/welcome.html ./src/app/components/welcome/welcome.component.html - sed -i -E 's/views\/welcome.html/welcome\/welcome.component.html/' ./src/app/components/welcome/welcome.component.js - sed -i -E 's/scripts\/welcome/components\/welcome\/welcome.component/' ./src/main.js + ```bash linenums="1" + mv ./src/app/scripts/welcome.js ./src/app/components/welcome/welcome.component.js + mv ./src/app/views/welcome.html ./src/app/components/welcome/welcome.component.html + sed -i -E 's/views\/welcome.html/welcome\/welcome.component.html/' ./src/app/components/welcome/welcome.component.js + sed -i -E 's/scripts\/welcome/components\/welcome\/welcome.component/' ./src/main.js - mv ./src/app/scripts/game.js ./src/app/components/game/game.component.js - mv ./src/app/views/game.html ./src/app/components/game/game.component.html - sed -i -E 's/views\/game.html/game\/game.component.html/' ./src/app/components/game/game.component.js - sed -i -E 's/scripts\/game/components\/game\/game.component/' ./src/main.js + mv ./src/app/scripts/game.js ./src/app/components/game/game.component.js + mv ./src/app/views/game.html ./src/app/components/game/game.component.html + sed -i -E 's/views\/game.html/game\/game.component.html/' ./src/app/components/game/game.component.js + sed -i -E 's/scripts\/game/components\/game\/game.component/' ./src/main.js - mv ./src/app/scripts/score.js ./src/app/components/score/score.component.js - mv ./src/app/views/score.html ./src/app/components/score/score.component.html - sed -i -E 's/views\/score.html/score\/score.component.html/' ./src/app/components/score/score.component.js - sed -i -E 's/scripts\/score/components\/score\/score.component/' ./src/main.js + mv ./src/app/scripts/score.js ./src/app/components/score/score.component.js + mv ./src/app/views/score.html ./src/app/components/score/score.component.html + sed -i -E 's/views\/score.html/score\/score.component.html/' ./src/app/components/score/score.component.js + sed -i -E 's/scripts\/score/components\/score\/score.component/' ./src/main.js - sed -i -E 's/.\/utils/..\/..\/scripts\/utils/' ./src/app/components/game/game.component.js - sed -i -E 's/.\/utils/..\/..\/scripts\/utils/' ./src/app/components/score/score.component.js - - sed -i -E 's/.\/component/..\/..\/scripts\/component/' ./src/app/components/game/game.component.js - sed -i -E 's/.\/component/..\/..\/scripts\/component/' ./src/app/components/score/score.component.js - sed -i -E 's/.\/component/..\/..\/scripts\/component/' ./src/app/components/welcome/welcome.component.js - ``` - ::: + sed -i -E 's/.\/utils/..\/..\/scripts\/utils/' ./src/app/components/game/game.component.js + sed -i -E 's/.\/utils/..\/..\/scripts\/utils/' ./src/app/components/score/score.component.js + sed -i -E 's/.\/component/..\/..\/scripts\/component/' ./src/app/components/game/game.component.js + sed -i -E 's/.\/component/..\/..\/scripts\/component/' ./src/app/components/score/score.component.js + sed -i -E 's/.\/component/..\/..\/scripts\/component/' ./src/app/components/welcome/welcome.component.js + ``` + Don't forget to change the `*.component.js` path in the HTML file. #### <i class="fab fa-css3-alt"></i> Isolate _CSS_ <Diy /> @@ -114,69 +110,70 @@ It is more convenient to group files by domain/concern rather than technology to At the moment, the whole application style is defined in `styles/style.css`. - For each view, create a new `*.css` file called `X.component.css` (where `X` is the component name). - :::spoiler Show the commands - ```bash - touch ./src/app/components/game/game.component.css - touch ./src/app/components/welcome/welcome.component.css - touch ./src/app/components/score/score.component.css - ``` - ::: + +???note "Show the commands" + ```bash + touch ./src/app/components/game/game.component.css + touch ./src/app/components/welcome/welcome.component.css + touch ./src/app/components/score/score.component.css + ``` - Edit `styles/style.css` and move the corresponding pieces of code to the corresponding `X.component.css` file. - Do not forget to import the _CSS_ file in the related component. - ::::spoiler Show the imports - :::code-tabs - @tab game.component.js - ```js{7} - import { parseUrl } from "../../scripts/utils"; - import { Component } from "../../scripts/component"; +???note "Show the imports" - import { CardComponent } from "./card/card.component"; + === "game.component.js" - import template from "./game.component.html"; - import "./game.component.css"; + ```js linenums="1" + import { parseUrl } from "../../scripts/utils"; + import { Component } from "../../scripts/component"; - export class GameComponent extends Component { - constructor() { - // ... - } - // ... - } - ``` + import { CardComponent } from "./card/card.component"; - @tab score.component.js - ```js{5} - import { parseUrl } from "../../scripts/utils"; - import { Component } from "../../scripts/component"; + import template from "./game.component.html"; + import "./game.component.css"; - import template from "./score.component.html"; - import "./score.component.css"; - - export class ScoreComponent extends Component { - constructor() { - // ... - } - // ... - } - ``` + export class GameComponent extends Component { + constructor() { + // ... + } + // ... + } + ``` - @tab score.component.js - ```js{4} - import { Component } from "../../scripts/component"; + === "score.component.js" + + ```js linenums="1" + import { parseUrl } from "../../scripts/utils"; + import { Component } from "../../scripts/component"; + + import template from "./score.component.html"; + import "./score.component.css"; + + export class ScoreComponent extends Component { + constructor() { + // ... + } + // ... + } + ``` + + === "score.component.js" + + ```js linenums="1" + import { Component } from "../../scripts/component"; - import template from "../welcome/welcome.component.html"; - import "./welcome.component.css"; + import template from "../welcome/welcome.component.html"; + import "./welcome.component.css"; - export class WelcomeComponent extends Component { - constructor() { - // ... - } - } - ``` - ::: - :::: + export class WelcomeComponent extends Component { + constructor() { + // ... + } + } + ``` ### Single responsibility @@ -184,15 +181,14 @@ It's time to remove the `CardComponent` class from the `game.component.js` file <Diy /> - Create the `*.html`, `*.js` and `*.css` files for `CardComponent`. - :::spoiler Show the commands - ```bash - touch -p src/app/components/game/card/card.component.js - touch -p src/app/components/game/card/card.component.html - touch -p src/app/components/game/card/card.component.css - ``` +???note "Show the commands" - ::: + ```bash linenums="1" + touch -p src/app/components/game/card/card.component.js + touch -p src/app/components/game/card/card.component.html + touch -p src/app/components/game/card/card.component.css + ``` - Move the code related to `CardComponent` from `game.component.js` to `card.component.js`.(Do not forget to export the `CardComponent` class). - Add the import statement for `CardComponent` in `game.component.js`. @@ -224,80 +220,77 @@ In this chapter, we will create reusable components for the _navbar_ and the _fo <Diy /> - Create the _HTML_, _CSS_ and _JS_ files for our new `NavbarComponent`. - :::spoiler Show the commands - ```bash - cd front-end/ - mkdir -p src/app/components/navbar - touch src/app/components/navbar/navbar.component.js - touch src/app/components/navbar/navbar.component.css - touch src/app/components/navbar/navbar.component.html - ``` - ::: - +???note "Show the commands" + ```bash + cd front-end/ + mkdir -p src/app/components/navbar + touch src/app/components/navbar/navbar.component.js + touch src/app/components/navbar/navbar.component.css + touch src/app/components/navbar/navbar.component.html + ``` + - Move the code related to the _navbar_ template from `*.component.html` to `navbar.component.html`. - In `navbar.component.js`, define and export a class called `NavbarComponent` that extends `HTMLElement`. - > **info** A _Web Component_ is a custom HTML element. + +!!!info "Infos" + A _Web Component_ is a custom HTML element. + - Move the code related to the _navbar_ style from `styles.css` to `navbar.component.css`. - Use an _ES default import_ to import `navbar.component.html` as `template`. - Use an _ES side-effects import_ to import `navbar.component.css`. - Define a `NavbarComponent` constructor. It has to call `super()` and assign `this.innerHTML` to the `template` variable. - ::::spoiler Show the navbar.component.js file - :::code-tabs - @tab navbar.component.js - - ```js - export class NavbarComponent extends HTMLElement { - constructor() { - super(); - this.innerHTML = template; - // ... - } - } - ``` - ::: - :::: + +???note "Show the navbar.component.js file" + === "navbar.component.js" + + ```js linenums="1" + export class NavbarComponent extends HTMLElement { + constructor() { + super(); + this.innerHTML = template; + // ... + } + } + ``` - Edit `main.js`. Call [`CustomElementRegistry.define()`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define) to register the `NavbarComponent` as the `my-navbar` custom HTML element - :::code-tabs - @tab main.js - ```js{4} - // ... - import { NavbarComponent } from "./app/components/navbar/navbar.component"; +=== "main.js" - customElements.define("my-navbar", NavbarComponent); - ``` + ```js linenums="1" + // ... + import { NavbarComponent } from "./app/components/navbar/navbar.component"; - ::: + customElements.define("my-navbar", NavbarComponent); + ``` - > **info** _Web Components_ should have a [`tagName` with at least one hyphen](https://github.com/WICG/webcomponents/issues/658) +!!!info "Infos" + _Web Components_ should have a [`tagName` with at least one hyphen](https://github.com/WICG/webcomponents/issues/658) - With the lines above, you can now use the `<my-navbar>` tag to invoke the `NavbarComponent` in `index.html`. - ::::spoiler Show the index.html file - :::code-tabs - @tab index.html - - ```html{5} - <!DOCTYPE html> - <html lang="en"> - <!-- ... --> - - <body> - <my-navbar></my-navbar> - <section class="overflow-auto flex-grow-1 d-flex flex-column"> - <div class="container-fluid flex-grow-1"> - <div id="content-outlet" class="h-100 w-100 d-flex flex-column"></div> - </div> - <!-- ... --> - </section> - </body> - </html> - ``` - ::: - :::: +???note "Show the index.html file" + + === "index.html" + + ```html linenums="1" + <!DOCTYPE html> + <html lang="en"> + <!-- ... --> + + <body> + <my-navbar></my-navbar> + <section class="overflow-auto flex-grow-1 d-flex flex-column"> + <div class="container-fluid flex-grow-1"> + <div id="content-outlet" class="h-100 w-100 d-flex flex-column"></div> + </div> + <!-- ... --> + </section> + </body> + </html> + ``` - Do the same changes to create a `FooterComponent` to display the footer. diff --git a/resources/docs/docs/chapters/tp/css-loader.md b/resources/docs/docs/chapters/tp/css-loader.md index f16da51f17d4e1cb170cc9f69fca34b6c6ad7224..8a67da086c98bcbade607c258df5f952ddfca0d2 100644 --- a/resources/docs/docs/chapters/tp/css-loader.md +++ b/resources/docs/docs/chapters/tp/css-loader.md @@ -145,8 +145,8 @@ so we can use the package manager to install it. - **Use the installed _Bootstrap_ package** - Edit all `*.html` files to make them use the newly installed package. - Solve all the `TODO #npm-bootstrap` comments. + Edit all `*.html` files to remove all styles import. + Solve the `TODO #npm-bootstrap` only inside main.js. #### :fontawesome-solid-folder-tree: Modified files