├── packages ├── novice │ ├── koans │ │ ├── src │ │ │ └── .gitkeep │ │ ├── webpack.config.js │ │ ├── package.json │ │ └── index.html │ ├── basic │ │ ├── webpack.config.js │ │ ├── package.json │ │ ├── src │ │ │ ├── title.js │ │ │ └── color.js │ │ └── index.html │ ├── code-assets │ │ ├── assets │ │ │ ├── main.css │ │ │ └── landscape.jpg │ │ ├── src │ │ │ ├── title.js │ │ │ └── color.js │ │ ├── index.html │ │ ├── package.json │ │ └── webpack.config.js │ ├── outputs │ │ ├── assets │ │ │ └── landscape.jpg │ │ ├── src │ │ │ ├── title.js │ │ │ └── color.js │ │ ├── index.html │ │ ├── package.json │ │ └── webpack.config.js │ └── static-assets │ │ ├── assets │ │ └── landscape.jpg │ │ ├── src │ │ ├── title.js │ │ └── color.js │ │ ├── index.html │ │ ├── webpack.config.js │ │ └── package.json ├── advanced │ ├── loaders │ │ ├── pokemon.loader.js │ │ ├── src │ │ │ ├── main.js │ │ │ ├── index.html │ │ │ ├── app.js │ │ │ └── bulbasaur.pokemon │ │ ├── package.json │ │ └── webpack.config.js │ └── plugins │ │ ├── src │ │ ├── assets │ │ │ └── banner.jpg │ │ ├── app.js │ │ ├── index.html │ │ ├── main.js │ │ ├── router.js │ │ ├── pokemon.service.js │ │ ├── pages │ │ │ ├── home.js │ │ │ └── details.js │ │ └── components │ │ │ └── pokemon.js │ │ ├── package.json │ │ └── webpack.config.js └── intermediate │ ├── koans │ ├── src │ │ ├── assets │ │ │ └── banner.jpg │ │ └── index.html │ └── package.json │ ├── dev │ ├── src │ │ ├── pokemon.service.js │ │ ├── index.html │ │ ├── main.js │ │ └── pokemon.component.js │ ├── package.json │ └── webpack.config.js │ ├── babel │ ├── src │ │ ├── pokemon.service.js │ │ ├── index.html │ │ ├── main.js │ │ └── pokemon.component.js │ ├── package.json │ └── webpack.config.js │ ├── compression │ ├── src │ │ ├── app.vue │ │ ├── assets │ │ │ └── banner.jpg │ │ ├── app.sass │ │ ├── index.html │ │ ├── main.js │ │ ├── router.js │ │ ├── pokemon.service.js │ │ ├── pages │ │ │ ├── home.vue │ │ │ └── details.vue │ │ └── components │ │ │ └── pokemon.vue │ ├── .babelrc │ ├── package.json │ └── webpack.config.js │ ├── style │ ├── src │ │ ├── pokemon.service.js │ │ ├── index.html │ │ ├── main.js │ │ └── pokemon.component.js │ ├── package.json │ └── webpack.config.js │ ├── modern-build │ ├── src │ │ ├── app.vue │ │ ├── assets │ │ │ └── banner.jpg │ │ ├── app.sass │ │ ├── index.html │ │ ├── main.js │ │ ├── router.js │ │ ├── pokemon.service.js │ │ ├── pages │ │ │ ├── home.vue │ │ │ └── details.vue │ │ └── components │ │ │ └── pokemon.vue │ ├── .babelrc │ ├── package.json │ └── webpack.config.js │ ├── reduce-bundle-size │ ├── src │ │ ├── assets │ │ │ └── banner.jpg │ │ ├── app.js │ │ ├── index.html │ │ ├── main.js │ │ ├── router.js │ │ ├── pokemon.service.js │ │ ├── pages │ │ │ ├── home.js │ │ │ └── details.js │ │ └── components │ │ │ └── pokemon.js │ ├── package.json │ └── webpack.config.js │ └── alias │ ├── src │ ├── my │ │ └── own │ │ │ └── strange │ │ │ └── way │ │ │ └── to │ │ │ └── structrure │ │ │ └── my │ │ │ └── project │ │ │ └── services │ │ │ └── pokemon.service.js │ ├── index.html │ ├── main.js │ └── pokemon.component.js │ ├── package.json │ └── webpack.config.js ├── docs ├── fr │ ├── workshops │ │ ├── novice │ │ │ ├── README.md │ │ │ ├── novice-koans.md │ │ │ ├── code-assets.md │ │ │ ├── basics.md │ │ │ ├── outputs.md │ │ │ └── static-assets.md │ │ ├── img │ │ │ ├── build.png │ │ │ └── elias-arnar-1309173-unsplash.jpg │ │ ├── intermediate │ │ │ ├── intermediate-koans.md │ │ │ ├── babel.md │ │ │ ├── alias.md │ │ │ ├── compression.md │ │ │ ├── reduce-bundle-size.md │ │ │ ├── dev.md │ │ │ └── style.md │ │ ├── README.md │ │ └── advanced │ │ │ ├── plugins.md │ │ │ └── loaders.md │ ├── README.md │ └── why.md ├── workshops │ ├── advanced │ │ ├── README.md │ │ └── plugins.md │ ├── novice │ │ ├── README.md │ │ ├── novice-koans.md │ │ ├── code-assets.md │ │ ├── basics.md │ │ ├── outputs.md │ │ └── static-assets.md │ ├── intermediate │ │ ├── README.md │ │ ├── intermediate-koans.md │ │ ├── babel.md │ │ ├── compression.md │ │ ├── reduce-bundle-size.md │ │ ├── dev.md │ │ ├── style.md │ │ └── modern-build.md │ ├── img │ │ ├── build.png │ │ └── elias-arnar-1309173-unsplash.jpg │ └── README.md ├── .vuepress │ ├── styles │ │ ├── palette.styl │ │ └── index.styl │ ├── public │ │ ├── google95fef9d7caa23f30.html │ │ ├── favicon.ico │ │ ├── webpack.png │ │ └── .well-known │ │ │ └── brave-rewards-verification.txt │ └── config.js ├── assets │ └── lighthouse.png ├── README.md └── why.md ├── .gitignore ├── package.json ├── .github └── workflows │ └── node.js.yml ├── LICENSE ├── README.md └── CODE_OF_CONDUCT.md /packages/novice/koans/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/advanced/loaders/pokemon.loader.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/fr/workshops/novice/README.md: -------------------------------------------------------------------------------- 1 | # Novice 2 | -------------------------------------------------------------------------------- /docs/workshops/advanced/README.md: -------------------------------------------------------------------------------- 1 | # Advanced 2 | -------------------------------------------------------------------------------- /docs/workshops/novice/README.md: -------------------------------------------------------------------------------- 1 | # Novice 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .vscode 4 | dist/ -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | $accentColor = #1e72b2 -------------------------------------------------------------------------------- /docs/workshops/intermediate/README.md: -------------------------------------------------------------------------------- 1 | # Intermediate 2 | -------------------------------------------------------------------------------- /packages/novice/basic/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /packages/novice/koans/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | summary { 2 | font-style italic 3 | } -------------------------------------------------------------------------------- /packages/novice/code-assets/assets/main.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 24px; 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vuepress/public/google95fef9d7caa23f30.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google95fef9d7caa23f30.html 2 | -------------------------------------------------------------------------------- /docs/assets/lighthouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/assets/lighthouse.png -------------------------------------------------------------------------------- /docs/workshops/img/build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/workshops/img/build.png -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /docs/.vuepress/public/webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/.vuepress/public/webpack.png -------------------------------------------------------------------------------- /docs/fr/workshops/img/build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/fr/workshops/img/build.png -------------------------------------------------------------------------------- /packages/novice/outputs/assets/landscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/novice/outputs/assets/landscape.jpg -------------------------------------------------------------------------------- /packages/advanced/plugins/src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/advanced/plugins/src/assets/banner.jpg -------------------------------------------------------------------------------- /packages/novice/code-assets/assets/landscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/novice/code-assets/assets/landscape.jpg -------------------------------------------------------------------------------- /packages/intermediate/koans/src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/intermediate/koans/src/assets/banner.jpg -------------------------------------------------------------------------------- /packages/novice/static-assets/assets/landscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/novice/static-assets/assets/landscape.jpg -------------------------------------------------------------------------------- /docs/workshops/img/elias-arnar-1309173-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/workshops/img/elias-arnar-1309173-unsplash.jpg -------------------------------------------------------------------------------- /packages/advanced/loaders/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./app.js"; 3 | 4 | new Vue({ 5 | render: h => h(App) 6 | }).$mount("#app"); 7 | -------------------------------------------------------------------------------- /packages/intermediate/dev/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | exports.getPokemons = () => 2 | fetch("https://pokeapi.co/api/v2/pokemon/").then(response => response.json()); 3 | -------------------------------------------------------------------------------- /docs/fr/workshops/img/elias-arnar-1309173-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/docs/fr/workshops/img/elias-arnar-1309173-unsplash.jpg -------------------------------------------------------------------------------- /packages/intermediate/babel/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export const getPokemons = () => 2 | fetch("https://pokeapi.co/api/v2/pokemon/").then(response => response.json()); 3 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/app.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/intermediate/compression/src/assets/banner.jpg -------------------------------------------------------------------------------- /packages/intermediate/style/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export const getPokemons = () => 2 | fetch("https://pokeapi.co/api/v2/pokemon/").then(response => response.json()); 3 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/app.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/intermediate/modern-build/src/assets/banner.jpg -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slashgear/webpack-workshop/HEAD/packages/intermediate/reduce-bundle-size/src/assets/banner.jpg -------------------------------------------------------------------------------- /packages/intermediate/alias/src/my/own/strange/way/to/structrure/my/project/services/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export const getPokemons = () => 2 | fetch("https://pokeapi.co/api/v2/pokemon/").then(response => response.json()); 3 | -------------------------------------------------------------------------------- /docs/.vuepress/public/.well-known/brave-rewards-verification.txt: -------------------------------------------------------------------------------- 1 | This is a Brave Rewards publisher verification file. 2 | 3 | Domain: webpack-workshop.netlify.com 4 | Token: 7627ea18c93559625a5a31e46dce12070fac5629fc3936125125342484cd6835 5 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: "App", 3 | template: ` 4 |
5 |

Pokedex

6 | 7 |
8 | ` 9 | }; 10 | -------------------------------------------------------------------------------- /packages/intermediate/compression/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "usage" 7 | } 8 | ] 9 | ], 10 | "plugins": ["@babel/plugin-syntax-dynamic-import"] 11 | } -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: "App", 3 | template: ` 4 |
5 |

Pokedex

6 | 7 |
8 | ` 9 | }; 10 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "usage", 7 | "debug": true 8 | } 9 | ] 10 | ], 11 | "plugins": ["@babel/plugin-syntax-dynamic-import"] 12 | } -------------------------------------------------------------------------------- /docs/workshops/intermediate/intermediate-koans.md: -------------------------------------------------------------------------------- 1 | # Intermediate Koâns :pushpin: 2 | 3 | > To start this exercise, be sure to be in `./packages/novice/koans` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | :construction: WIP :construction: 7 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/app.sass: -------------------------------------------------------------------------------- 1 | @charset "utf-8" 2 | 3 | @import "~bulma/sass/utilities/_all.sass" 4 | @import "~bulma/sass/base/_all.sass" 5 | @import "~bulma/sass/components/card.sass" 6 | @import "~bulma/sass/elements/title.sass" 7 | @import "~bulma/sass/grid/columns.sass" -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/app.sass: -------------------------------------------------------------------------------- 1 | @charset "utf-8" 2 | 3 | @import "~bulma/sass/utilities/_all.sass" 4 | @import "~bulma/sass/base/_all.sass" 5 | @import "~bulma/sass/components/card.sass" 6 | @import "~bulma/sass/elements/title.sass" 7 | @import "~bulma/sass/grid/columns.sass" -------------------------------------------------------------------------------- /packages/advanced/loaders/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/novice/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@novice/basic", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "lodash": "^4.17.11" 8 | }, 9 | "devDependencies": { 10 | "webpack": "^4.28.4", 11 | "webpack-cli": "^3.2.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import router from "./router"; 4 | import App from "./app.js"; 5 | 6 | import "bulma/bulma.sass"; 7 | 8 | Vue.use(VueRouter); 9 | 10 | new Vue({ 11 | router, 12 | render: h => h(App) 13 | }).$mount("#app"); 14 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import router from "./router"; 4 | import App from "./app.vue"; 5 | 6 | import "./app.sass"; 7 | 8 | Vue.use(VueRouter); 9 | 10 | new Vue({ 11 | router, 12 | render: h => h(App) 13 | }).$mount("#app"); 14 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import router from "./router"; 4 | import App from "./app.vue"; 5 | 6 | import "./app.sass"; 7 | 8 | Vue.use(VueRouter); 9 | 10 | new Vue({ 11 | router, 12 | render: h => h(App) 13 | }).$mount("#app"); 14 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import router from "./router"; 4 | import App from "./app.js"; 5 | 6 | import "bulma/bulma.sass"; 7 | 8 | Vue.use(VueRouter); 9 | 10 | new Vue({ 11 | router, 12 | render: h => h(App) 13 | }).$mount("#app"); 14 | -------------------------------------------------------------------------------- /packages/novice/basic/src/title.js: -------------------------------------------------------------------------------- 1 | const { getRandomColor } = require("./color.js"); 2 | 3 | let changeCount = 0; 4 | 5 | const el = document.querySelector("h1"); 6 | 7 | setInterval(() => { 8 | changeCount++; 9 | el.innerHTML = `This title will change! ${changeCount}`; 10 | el.style.color = getRandomColor(); 11 | }, 1000); 12 | -------------------------------------------------------------------------------- /packages/intermediate/alias/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/intermediate/babel/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/intermediate/dev/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/intermediate/style/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/novice/outputs/src/title.js: -------------------------------------------------------------------------------- 1 | const { getRandomColor } = require("./color.js"); 2 | 3 | let changeCount = 0; 4 | 5 | const el = document.querySelector("h1"); 6 | 7 | setInterval(() => { 8 | changeCount++; 9 | el.innerHTML = `This title will change ! ${changeCount}`; 10 | el.style.color = getRandomColor(); 11 | }, 1000); 12 | -------------------------------------------------------------------------------- /packages/novice/code-assets/src/title.js: -------------------------------------------------------------------------------- 1 | const { getRandomColor } = require("./color.js"); 2 | 3 | let changeCount = 0; 4 | 5 | const el = document.querySelector("h1"); 6 | 7 | setInterval(() => { 8 | changeCount++; 9 | el.innerHTML = `This title will change ! ${changeCount}`; 10 | el.style.color = getRandomColor(); 11 | }, 1000); 12 | -------------------------------------------------------------------------------- /packages/novice/static-assets/src/title.js: -------------------------------------------------------------------------------- 1 | const { getRandomColor } = require("./color.js"); 2 | 3 | let changeCount = 0; 4 | 5 | const el = document.querySelector("h1"); 6 | 7 | setInterval(() => { 8 | changeCount++; 9 | el.innerHTML = `This title will change ! ${changeCount}`; 10 | el.style.color = getRandomColor(); 11 | }, 1000); 12 | -------------------------------------------------------------------------------- /packages/novice/outputs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |

This title will change !

10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/novice/code-assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |

This title will change !

10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/novice/static-assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |

This title will change !

10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/novice/static-assets/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/title.js", // The source module of our dependency graph 5 | output: { 6 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 7 | filename: "main.js", 8 | path: path.resolve(__dirname, "dist") 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | import Home from "./pages/home"; 4 | import Details from "./pages/details"; 5 | 6 | Vue.use(Router); 7 | 8 | export default new Router({ 9 | routes: [ 10 | { path: "/", component: Home }, 11 | { path: "/details/:id", component: Details, props: true } 12 | ] 13 | }); 14 | -------------------------------------------------------------------------------- /packages/advanced/loaders/src/app.js: -------------------------------------------------------------------------------- 1 | import Bulbasaur from "./bulbasaur.pokemon"; 2 | 3 | export default { 4 | name: "App", 5 | template: ` 6 |
7 |

Pokedex

8 | 9 | {{ Bulbasaur }} 10 |
11 | `, 12 | data() { 13 | return { 14 | Bulbasaur 15 | }; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /packages/intermediate/style/src/main.js: -------------------------------------------------------------------------------- 1 | import PokemonComponent from "./pokemon.component"; 2 | import { getPokemons } from "./pokemon.service"; 3 | 4 | const pokemonList = document.querySelector("#pokemons"); 5 | 6 | getPokemons().then(response => { 7 | response.results.map(({ name }, index) => { 8 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | import Home from "./pages/home"; 4 | import Details from "./pages/details"; 5 | 6 | Vue.use(Router); 7 | 8 | export default new Router({ 9 | routes: [ 10 | { path: "/", component: Home }, 11 | { path: "/details/:id", component: Details, props: true } 12 | ] 13 | }); 14 | -------------------------------------------------------------------------------- /packages/novice/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 8 | 9 |

This title will change!

10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/novice/basic/src/color.js: -------------------------------------------------------------------------------- 1 | const _ = require("lodash"); 2 | 3 | let colors = [ 4 | "#ffebee", 5 | "#ffcdd2", 6 | "#ef9a9a", 7 | "#e57373", 8 | "#ef5350", 9 | "#f44336", 10 | "#e53935", 11 | "#d32f2f", 12 | "#c62828", 13 | "#b71c1c", 14 | "#ff8a80", 15 | "#ff5252", 16 | "#ff1744", 17 | "#d50000" 18 | ]; 19 | 20 | exports.getRandomColor = () => _.sample(colors); 21 | -------------------------------------------------------------------------------- /packages/novice/outputs/src/color.js: -------------------------------------------------------------------------------- 1 | const _ = require("lodash"); 2 | 3 | let colors = [ 4 | "#ffebee", 5 | "#ffcdd2", 6 | "#ef9a9a", 7 | "#e57373", 8 | "#ef5350", 9 | "#f44336", 10 | "#e53935", 11 | "#d32f2f", 12 | "#c62828", 13 | "#b71c1c", 14 | "#ff8a80", 15 | "#ff5252", 16 | "#ff1744", 17 | "#d50000" 18 | ]; 19 | 20 | exports.getRandomColor = () => _.sample(colors); 21 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | 4 | Vue.use(Router); 5 | 6 | export default new Router({ 7 | routes: [ 8 | { path: "/", component: () => import("./pages/home.vue") }, 9 | { 10 | path: "/details/:id", 11 | component: () => import("./pages/details.vue"), 12 | props: true 13 | } 14 | ] 15 | }); 16 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | 4 | Vue.use(Router); 5 | 6 | export default new Router({ 7 | routes: [ 8 | { path: "/", component: () => import("./pages/home.vue") }, 9 | { 10 | path: "/details/:id", 11 | component: () => import("./pages/details.vue"), 12 | props: true 13 | } 14 | ] 15 | }); 16 | -------------------------------------------------------------------------------- /packages/novice/code-assets/src/color.js: -------------------------------------------------------------------------------- 1 | const _ = require("lodash"); 2 | 3 | let colors = [ 4 | "#ffebee", 5 | "#ffcdd2", 6 | "#ef9a9a", 7 | "#e57373", 8 | "#ef5350", 9 | "#f44336", 10 | "#e53935", 11 | "#d32f2f", 12 | "#c62828", 13 | "#b71c1c", 14 | "#ff8a80", 15 | "#ff5252", 16 | "#ff1744", 17 | "#d50000" 18 | ]; 19 | 20 | exports.getRandomColor = () => _.sample(colors); 21 | -------------------------------------------------------------------------------- /packages/novice/static-assets/src/color.js: -------------------------------------------------------------------------------- 1 | const _ = require("lodash"); 2 | 3 | let colors = [ 4 | "#ffebee", 5 | "#ffcdd2", 6 | "#ef9a9a", 7 | "#e57373", 8 | "#ef5350", 9 | "#f44336", 10 | "#e53935", 11 | "#d32f2f", 12 | "#c62828", 13 | "#b71c1c", 14 | "#ff8a80", 15 | "#ff5252", 16 | "#ff1744", 17 | "#d50000" 18 | ]; 19 | 20 | exports.getRandomColor = () => _.sample(colors); 21 | -------------------------------------------------------------------------------- /packages/novice/static-assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@novice/static-assets", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "lodash": "^4.17.11" 8 | }, 9 | "devDependencies": { 10 | "webpack": "^4.28.4", 11 | "webpack-cli": "^3.2.1", 12 | "file-loader": "^5.0.0" 13 | }, 14 | "scripts": { 15 | "build": "webpack" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/intermediate/babel/src/main.js: -------------------------------------------------------------------------------- 1 | import "bulma/css/bulma.css"; 2 | import PokemonComponent from "./pokemon.component"; 3 | import { getPokemons } from "./pokemon.service"; 4 | 5 | const pokemonList = document.querySelector("#pokemons"); 6 | 7 | getPokemons().then(response => { 8 | response.results.map(({ name }, index) => { 9 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/intermediate/alias/src/main.js: -------------------------------------------------------------------------------- 1 | import PokemonComponent from "./pokemon.component"; 2 | import { getPokemons } from "./my/own/strange/way/to/structrure/my/project/services/pokemon.service"; 3 | 4 | const pokemonList = document.querySelector("#pokemons"); 5 | 6 | getPokemons().then(response => { 7 | response.results.map(({ name }, index) => { 8 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export function getPokemons() { 2 | return fetch("https://pokeapi.co/api/v2/pokemon/").then(response => 3 | response.json() 4 | ); 5 | } 6 | 7 | export function getPokemon(id) { 8 | return fetch(`https://pokeapi.co/api/v2/pokemon/${id}/`).then(response => 9 | response.json() 10 | ); 11 | } 12 | 13 | export function getRandomPokemon() { 14 | return console.log("YEAH"); 15 | } 16 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export function getPokemons() { 2 | return fetch("https://pokeapi.co/api/v2/pokemon/").then(response => 3 | response.json() 4 | ); 5 | } 6 | 7 | export function getPokemon(id) { 8 | return fetch(`https://pokeapi.co/api/v2/pokemon/${id}/`).then(response => 9 | response.json() 10 | ); 11 | } 12 | 13 | export function getRandomPokemon() { 14 | return console.log("YEAH"); 15 | } 16 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export function getPokemons() { 2 | return fetch("https://pokeapi.co/api/v2/pokemon/").then(response => 3 | response.json() 4 | ); 5 | } 6 | 7 | export function getPokemon(id) { 8 | return fetch(`https://pokeapi.co/api/v2/pokemon/${id}/`).then(response => 9 | response.json() 10 | ); 11 | } 12 | 13 | export function getRandomPokemon() { 14 | return console.log("YEAH"); 15 | } 16 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/pokemon.service.js: -------------------------------------------------------------------------------- 1 | export function getPokemons() { 2 | return fetch("https://pokeapi.co/api/v2/pokemon/").then(response => 3 | response.json() 4 | ); 5 | } 6 | 7 | export function getPokemon(id) { 8 | return fetch(`https://pokeapi.co/api/v2/pokemon/${id}/`).then(response => 9 | response.json() 10 | ); 11 | } 12 | 13 | export function getRandomPokemon() { 14 | return console.log("YEAH"); 15 | } 16 | -------------------------------------------------------------------------------- /packages/novice/koans/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@novice/koans", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "bulma": "^0.8.0", 6 | "lodash": "^4.17.11" 7 | }, 8 | "devDependencies": { 9 | "webpack": "^4.28.4", 10 | "webpack-cli": "^3.2.1", 11 | "file-loader": "^5.0.0", 12 | "html-webpack-plugin": "^3.2.0", 13 | "clean-webpack-plugin": "^3.0.0" 14 | }, 15 | "scripts": { 16 | "build": "webpack" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/intermediate/dev/src/main.js: -------------------------------------------------------------------------------- 1 | require("bulma/css/bulma.css"); 2 | const _ = require("lodash"); 3 | 4 | const PokemonComponent = require("./pokemon.component"); 5 | const { getPokemons } = require("./pokemon.service"); 6 | 7 | const pokemonList = document.querySelector("#pokemons"); 8 | 9 | getPokemons().then(response => { 10 | response.results.map(({ name }, index) => { 11 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/novice/code-assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@novice/code-assets", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "lodash": "^4.17.11" 8 | }, 9 | "devDependencies": { 10 | "webpack": "^4.28.4", 11 | "webpack-cli": "^3.2.1", 12 | "file-loader": "^5.0.0", 13 | "css-loader": "^3.2.0", 14 | "style-loader": "^1.0.0" 15 | }, 16 | "scripts": { 17 | "build": "webpack" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/novice/outputs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@novice/outputs", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "lodash": "^4.17.11" 8 | }, 9 | "devDependencies": { 10 | "webpack": "^4.28.4", 11 | "webpack-cli": "^3.2.1", 12 | "file-loader": "^5.0.0", 13 | "html-webpack-plugin": "^3.2.0", 14 | "clean-webpack-plugin": "^3.0.0" 15 | }, 16 | "scripts": { 17 | "build": "webpack" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/intermediate/dev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@intermediate/dev", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11" 9 | }, 10 | "devDependencies": { 11 | "webpack": "^4.28.4", 12 | "webpack-cli": "^3.2.1", 13 | "file-loader": "^5.0.0", 14 | "css-loader": "^3.2.0", 15 | "style-loader": "^1.0.0", 16 | "html-webpack-plugin": "^3.2.0", 17 | "clean-webpack-plugin": "^3.0.0", 18 | "webpack-dev-server": "^3.1.14" 19 | }, 20 | "scripts": { 21 | "build": "webpack" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/pages/home.js: -------------------------------------------------------------------------------- 1 | import { getPokemons } from "../pokemon.service"; 2 | import Pokemon from "../components/pokemon"; 3 | 4 | export default { 5 | name: "Home", 6 | components: { 7 | Pokemon 8 | }, 9 | template: ` 10 |
11 |
12 | 13 |
14 |
15 | `, 16 | data() { 17 | return { 18 | pokemons: [] 19 | }; 20 | }, 21 | created() { 22 | getPokemons().then(pokemons => (this.pokemons = pokemons)); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/pages/home.js: -------------------------------------------------------------------------------- 1 | import { getPokemons } from "../pokemon.service"; 2 | import Pokemon from "../components/pokemon"; 3 | 4 | export default { 5 | name: "Home", 6 | components: { 7 | Pokemon 8 | }, 9 | template: ` 10 |
11 |
12 | 13 |
14 |
15 | `, 16 | data() { 17 | return { 18 | pokemons: [] 19 | }; 20 | }, 21 | created() { 22 | getPokemons().then(pokemons => (this.pokemons = pokemons)); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /packages/novice/code-assets/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/title.js", // The source module of our dependency graph 5 | output: { 6 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 7 | filename: "main.js", 8 | path: path.resolve(__dirname, "dist") 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.jpg$/, 14 | use: [ 15 | { 16 | loader: "file-loader", 17 | options: { 18 | outputPath: "assets", 19 | publicPath: "dist/assets" 20 | } 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/pages/home.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 33 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/pages/home.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 33 | -------------------------------------------------------------------------------- /packages/intermediate/babel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@intermediate/babel", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11" 9 | }, 10 | "devDependencies": { 11 | "@babel/core": "^7.2.2", 12 | "@babel/preset-env": "^7.3.1", 13 | "webpack": "^4.28.4", 14 | "webpack-cli": "^3.2.1", 15 | "file-loader": "^5.0.0", 16 | "css-loader": "^3.2.0", 17 | "babel-loader": "^8.0.5", 18 | "style-loader": "^1.0.0", 19 | "html-webpack-plugin": "^3.2.0", 20 | "clean-webpack-plugin": "^3.0.0", 21 | "webpack-dev-server": "^3.1.14" 22 | }, 23 | "scripts": { 24 | "build": "webpack", 25 | "start": "webpack-dev-server" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/components/pokemon.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export default { 4 | name: "Pokemon", 5 | template: ` 6 | 7 |
8 |
9 | 10 |

{{formatName}}

11 |
12 |
13 |
14 | `, 15 | props: ["id", "name"], 16 | computed: { 17 | url() { 18 | return `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${this.id}.png`; 19 | }, 20 | to() { 21 | return `/details/${this.id}`; 22 | }, 23 | formatName() { 24 | return _.capitalize(this.name); 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/pages/details.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/pages/details.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /packages/novice/outputs/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/title.js", // The source module of our dependency graph 5 | output: { 6 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 7 | filename: "main.js", 8 | path: path.resolve(__dirname, "dist") 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.jpg$/, 14 | use: [ 15 | { 16 | loader: "file-loader", 17 | options: { 18 | outputPath: "assets", 19 | publicPath: "dist/assets" 20 | } 21 | } 22 | ] 23 | }, 24 | { 25 | test: /\.css$/, 26 | use: ["style-loader", "css-loader"] 27 | } 28 | ] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/components/pokemon.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export default { 4 | name: "Pokemon", 5 | template: ` 6 | 7 |
8 |
9 | 10 |

{{formatName}}

11 |
12 |
13 |
14 | `, 15 | props: ["id", "name"], 16 | computed: { 17 | url() { 18 | return `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${this.id}.png`; 19 | }, 20 | to() { 21 | return `/details/${this.id}`; 22 | }, 23 | formatName() { 24 | return _.capitalize(this.name); 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /webpack.png 4 | actionText: Get Started → 5 | actionLink: /workshops/ 6 | tagline: Learn webpack concepts with examples 7 | features: 8 | - title: Novice or expert 9 | details: You will find something to learn for sure, even if you are a webpack rock star. 10 | - title: 5min setup 11 | details: Thanks to yarn workspaces, every workshop will up and ready for you within few seconds. 12 | - title: Open source 13 | details: If you think a workshop is missing, open an issue, publish a pull request ! 14 | footer: MIT Licensed | Copyright © 2019-present Antoine Caron 15 | meta: 16 | - name: description 17 | content: Learn webpack concepts by example, How to set up webpack? How to configure webpack? Babel, Scss? From beginner workshops to advanced exercises 18 | --- 19 | -------------------------------------------------------------------------------- /packages/advanced/plugins/src/pages/details.js: -------------------------------------------------------------------------------- 1 | import { getPokemon } from "../pokemon.service"; 2 | import Pokemon from "../components/pokemon"; 3 | 4 | import banner from "../assets/banner.jpg"; 5 | 6 | export default { 7 | name: "Details", 8 | components: { 9 | Pokemon 10 | }, 11 | template: ` 12 |
13 | Home 14 |
15 | 16 |
17 | 18 |
19 | `, 20 | data() { 21 | return { 22 | pokemon: {}, 23 | banner 24 | }; 25 | }, 26 | created() { 27 | getPokemon(this.$route.params.id).then(pokemon => (this.pokemon = pokemon)); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /packages/intermediate/compression/src/components/pokemon.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | -------------------------------------------------------------------------------- /packages/intermediate/modern-build/src/components/pokemon.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/src/pages/details.js: -------------------------------------------------------------------------------- 1 | import { getPokemon } from "../pokemon.service"; 2 | import Pokemon from "../components/pokemon"; 3 | 4 | import banner from "../assets/banner.jpg"; 5 | 6 | export default { 7 | name: "Details", 8 | components: { 9 | Pokemon 10 | }, 11 | template: ` 12 |
13 | Home 14 |
15 | 16 |
17 | 18 |
19 | `, 20 | data() { 21 | return { 22 | pokemon: {}, 23 | banner 24 | }; 25 | }, 26 | created() { 27 | getPokemon(this.$route.params.id).then(pokemon => (this.pokemon = pokemon)); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /docs/fr/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /webpack.png 4 | actionText: Installation → 5 | actionLink: /fr/workshops/ 6 | tagline: Apprendre les concepts de webpack par l'exemple 7 | features: 8 | - title: Novice or expert 9 | details: Vous trouverez quelque chose à apprendre, même si vous êtes une rock star avec webpack. 10 | - title: Prêt en 5min 11 | details: Grâce aux workspaces de Yarn, tous les ateliers seront prêts en quelques secondes. 12 | - title: Libre 13 | details: Si vous pensez qu'il manque un atelier, ouvrez une Issue ou une Pull Request ! 14 | footer: MIT Licensed | Copyright © 2019-present Antoine Caron 15 | meta: 16 | - name: description 17 | content: Apprendre les concepts de webpack par l'exemple, Comment mettre en place webpack ? Comment configurer webpack ? Babel, Scss ? Des ateliers pour débutants jusqu'à des exercices avancés 18 | --- 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-workshop", 3 | "version": "1.0.0", 4 | "description": "Workshop about webpack", 5 | "main": "index.js", 6 | "author": "Antoine Caron ", 7 | "license": "MIT", 8 | "private": true, 9 | "workspaces": [ 10 | "./packages/**/*" 11 | ], 12 | "husky": { 13 | "hooks": { 14 | "pre-commit": "pretty-quick --staged" 15 | } 16 | }, 17 | "scripts": { 18 | "docs:dev": "vuepress dev docs", 19 | "docs:build": "vuepress build docs", 20 | "lint": "yarn prettier --list-different 'packages/**/*.{js,md}' 'docs/**/*.{js,md}'" 21 | }, 22 | "devDependencies": { 23 | "husky": "4.2.2", 24 | "prettier": "1.19.0", 25 | "pretty-quick": "^2.0.0", 26 | "vuepress": "1.3.1", 27 | "vuepress-plugin-sitemap": "2.2.0" 28 | }, 29 | "resolutions": { 30 | "lodash": "4.17.15" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/intermediate/alias/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@intermediate/alias", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11" 9 | }, 10 | "devDependencies": { 11 | "@babel/core": "^7.2.2", 12 | "@babel/preset-env": "^7.3.1", 13 | "webpack": "^4.28.4", 14 | "webpack-cli": "^3.2.1", 15 | "file-loader": "^5.0.0", 16 | "css-loader": "^3.2.0", 17 | "babel-loader": "^8.0.5", 18 | "style-loader": "^1.0.0", 19 | "node-sass": "^4.11.0", 20 | "sass-loader": "^8.0.0", 21 | "postcss-loader": "^3.0.0", 22 | "autoprefixer": "^9.4.7", 23 | "html-webpack-plugin": "^3.2.0", 24 | "clean-webpack-plugin": "^3.0.0", 25 | "webpack-dev-server": "^3.1.14", 26 | "mini-css-extract-plugin": "^0.9.0" 27 | }, 28 | "scripts": { 29 | "build": "webpack" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/intermediate/style/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@intermediate/style", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11" 9 | }, 10 | "devDependencies": { 11 | "@babel/core": "^7.2.2", 12 | "@babel/preset-env": "^7.3.1", 13 | "webpack": "^4.28.4", 14 | "webpack-cli": "^3.2.1", 15 | "file-loader": "^5.0.0", 16 | "css-loader": "^3.2.0", 17 | "babel-loader": "^8.0.5", 18 | "style-loader": "^1.0.0", 19 | "node-sass": "^4.11.0", 20 | "sass-loader": "^8.0.0", 21 | "postcss-loader": "^3.0.0", 22 | "autoprefixer": "^9.4.7", 23 | "html-webpack-plugin": "^3.2.0", 24 | "clean-webpack-plugin": "^3.0.0", 25 | "webpack-dev-server": "^3.1.14", 26 | "mini-css-extract-plugin": "^0.9.0" 27 | }, 28 | "scripts": { 29 | "build": "webpack" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/intermediate/dev/src/pokemon.component.js: -------------------------------------------------------------------------------- 1 | module.exports = (name, id) => { 2 | const pokemonRoot = document.createElement("div"); 3 | pokemonRoot.classList.add("column"); 4 | pokemonRoot.classList.add("is-2"); 5 | pokemonRoot.classList.add("has-text-centered"); 6 | 7 | const card = document.createElement("div"); 8 | card.classList.add("card"); 9 | 10 | const cardContent = document.createElement("div"); 11 | card.classList.add("card-content"); 12 | 13 | const image = document.createElement("img"); 14 | image.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`; 15 | 16 | const p = document.createElement("p"); 17 | p.innerHTML = _.capitalize(name); 18 | 19 | cardContent.appendChild(image); 20 | cardContent.appendChild(p); 21 | 22 | card.appendChild(cardContent); 23 | 24 | pokemonRoot.appendChild(card); 25 | 26 | return pokemonRoot; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/intermediate/alias/src/pokemon.component.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export default (name, id) => { 4 | const pokemonRoot = document.createElement("div"); 5 | pokemonRoot.classList.add("column"); 6 | pokemonRoot.classList.add("is-2"); 7 | pokemonRoot.classList.add("has-text-centered"); 8 | 9 | const card = document.createElement("div"); 10 | card.classList.add("card"); 11 | 12 | const cardContent = document.createElement("div"); 13 | card.classList.add("card-content"); 14 | 15 | const image = document.createElement("img"); 16 | image.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`; 17 | 18 | const p = document.createElement("p"); 19 | p.innerHTML = _.capitalize(name); 20 | 21 | cardContent.appendChild(image); 22 | cardContent.appendChild(p); 23 | 24 | card.appendChild(cardContent); 25 | 26 | pokemonRoot.appendChild(card); 27 | 28 | return pokemonRoot; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/intermediate/babel/src/pokemon.component.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export default (name, id) => { 4 | const pokemonRoot = document.createElement("div"); 5 | pokemonRoot.classList.add("column"); 6 | pokemonRoot.classList.add("is-2"); 7 | pokemonRoot.classList.add("has-text-centered"); 8 | 9 | const card = document.createElement("div"); 10 | card.classList.add("card"); 11 | 12 | const cardContent = document.createElement("div"); 13 | card.classList.add("card-content"); 14 | 15 | const image = document.createElement("img"); 16 | image.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`; 17 | 18 | const p = document.createElement("p"); 19 | p.innerHTML = _.capitalize(name); 20 | 21 | cardContent.appendChild(image); 22 | cardContent.appendChild(p); 23 | 24 | card.appendChild(cardContent); 25 | 26 | pokemonRoot.appendChild(card); 27 | 28 | return pokemonRoot; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/intermediate/style/src/pokemon.component.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export default (name, id) => { 4 | const pokemonRoot = document.createElement("div"); 5 | pokemonRoot.classList.add("column"); 6 | pokemonRoot.classList.add("is-2"); 7 | pokemonRoot.classList.add("has-text-centered"); 8 | 9 | const card = document.createElement("div"); 10 | card.classList.add("card"); 11 | 12 | const cardContent = document.createElement("div"); 13 | card.classList.add("card-content"); 14 | 15 | const image = document.createElement("img"); 16 | image.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`; 17 | 18 | const p = document.createElement("p"); 19 | p.innerHTML = _.capitalize(name); 20 | 21 | cardContent.appendChild(image); 22 | cardContent.appendChild(p); 23 | 24 | card.appendChild(cardContent); 25 | 26 | pokemonRoot.appendChild(card); 27 | 28 | return pokemonRoot; 29 | }; 30 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: Continous Integration 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | node-version: [10.x, 12.x] 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Yarn cache 20 | uses: actions/cache@v2 21 | with: 22 | path: "**/node_modules" 23 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 24 | 25 | - name: Use Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | - run: yarn install 30 | - run: yarn lint 31 | - run: yarn docs:build 32 | 33 | - uses: actions/upload-artifact@v2 34 | with: 35 | name: dist-site 36 | path: docs/.vuepress/dist/ 37 | -------------------------------------------------------------------------------- /packages/intermediate/alias/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./src/main.js", // The source module of our dependency graph 6 | output: { 7 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 8 | filename: "main.bundle.js", 9 | path: path.resolve(__dirname, "dist") 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.jpg$/, 15 | use: [ 16 | { 17 | loader: "file-loader", 18 | options: { 19 | outputPath: "assets", 20 | publicPath: "dist/assets" 21 | } 22 | } 23 | ] 24 | }, 25 | { 26 | test: /\.css$/, 27 | use: ["style-loader", "css-loader"] 28 | } 29 | ] 30 | }, 31 | plugins: [ 32 | new HtmlWebpackPlugin({ 33 | template: "./src/index.html" 34 | }) 35 | ] 36 | }; 37 | -------------------------------------------------------------------------------- /packages/intermediate/babel/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./src/main.js", // The source module of our dependency graph 6 | output: { 7 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 8 | filename: "main.bundle.js", 9 | path: path.resolve(__dirname, "dist") 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.jpg$/, 15 | use: [ 16 | { 17 | loader: "file-loader", 18 | options: { 19 | outputPath: "assets", 20 | publicPath: "dist/assets" 21 | } 22 | } 23 | ] 24 | }, 25 | { 26 | test: /\.css$/, 27 | use: ["style-loader", "css-loader"] 28 | } 29 | ] 30 | }, 31 | plugins: [ 32 | new HtmlWebpackPlugin({ 33 | template: "./src/index.html" 34 | }) 35 | ] 36 | }; 37 | -------------------------------------------------------------------------------- /packages/intermediate/dev/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./src/main.js", // The source module of our dependency graph 6 | output: { 7 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 8 | filename: "main.bundle.js", 9 | path: path.resolve(__dirname, "dist") 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.jpg$/, 15 | use: [ 16 | { 17 | loader: "file-loader", 18 | options: { 19 | outputPath: "assets", 20 | publicPath: "dist/assets" 21 | } 22 | } 23 | ] 24 | }, 25 | { 26 | test: /\.css$/, 27 | use: ["style-loader", "css-loader"] 28 | } 29 | ] 30 | }, 31 | plugins: [ 32 | new HtmlWebpackPlugin({ 33 | template: "./src/index.html" 34 | }) 35 | ] 36 | }; 37 | -------------------------------------------------------------------------------- /packages/intermediate/style/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./src/main.js", // The source module of our dependency graph 6 | output: { 7 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 8 | filename: "main.bundle.js", 9 | path: path.resolve(__dirname, "dist") 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.jpg$/, 15 | use: [ 16 | { 17 | loader: "file-loader", 18 | options: { 19 | outputPath: "assets", 20 | publicPath: "dist/assets" 21 | } 22 | } 23 | ] 24 | }, 25 | { 26 | test: /\.css$/, 27 | use: ["style-loader", "css-loader"] 28 | } 29 | ] 30 | }, 31 | plugins: [ 32 | new HtmlWebpackPlugin({ 33 | template: "./src/index.html" 34 | }) 35 | ] 36 | }; 37 | -------------------------------------------------------------------------------- /packages/advanced/loaders/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@advanced/loaders", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11", 9 | "vue": "2.6.10", 10 | "vue-router": "^3.0.2" 11 | }, 12 | "devDependencies": { 13 | "@babel/core": "^7.2.2", 14 | "@babel/preset-env": "^7.3.1", 15 | "webpack": "^4.28.4", 16 | "webpack-cli": "^3.2.1", 17 | "file-loader": "^5.0.0", 18 | "css-loader": "^3.2.0", 19 | "babel-loader": "^8.0.5", 20 | "style-loader": "^1.0.0", 21 | "node-sass": "^4.11.0", 22 | "sass-loader": "^8.0.0", 23 | "postcss-loader": "^3.0.0", 24 | "autoprefixer": "^9.4.7", 25 | "html-webpack-plugin": "^3.2.0", 26 | "clean-webpack-plugin": "^3.0.0", 27 | "webpack-dev-server": "^3.1.14", 28 | "mini-css-extract-plugin": "^0.9.0", 29 | "webpack-bundle-analyzer": "^3.0.4" 30 | }, 31 | "scripts": { 32 | "build": "webpack", 33 | "start": "webpack-dev-server" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/advanced/plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@advanced/plugins", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11", 9 | "vue": "2.6.10", 10 | "vue-router": "^3.0.2" 11 | }, 12 | "devDependencies": { 13 | "@babel/core": "^7.2.2", 14 | "@babel/preset-env": "^7.3.1", 15 | "webpack": "^4.28.4", 16 | "webpack-cli": "^3.2.1", 17 | "file-loader": "^5.0.0", 18 | "css-loader": "^3.2.0", 19 | "babel-loader": "^8.0.5", 20 | "style-loader": "^1.0.0", 21 | "node-sass": "^4.11.0", 22 | "sass-loader": "^8.0.0", 23 | "postcss-loader": "^3.0.0", 24 | "autoprefixer": "^9.4.7", 25 | "html-webpack-plugin": "^3.2.0", 26 | "clean-webpack-plugin": "^3.0.0", 27 | "webpack-dev-server": "^3.1.14", 28 | "mini-css-extract-plugin": "^0.9.0", 29 | "webpack-bundle-analyzer": "^3.0.4" 30 | }, 31 | "scripts": { 32 | "build": "webpack", 33 | "start": "webpack-dev-server" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/intermediate/reduce-bundle-size/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@intermediate/reduce-bundle-size", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "dependencies": { 7 | "bulma": "^0.8.0", 8 | "lodash": "^4.17.11", 9 | "vue": "2.6.10", 10 | "vue-router": "^3.0.2" 11 | }, 12 | "devDependencies": { 13 | "@babel/core": "^7.2.2", 14 | "@babel/preset-env": "^7.3.1", 15 | "webpack": "^4.28.4", 16 | "webpack-cli": "^3.2.1", 17 | "file-loader": "^5.0.0", 18 | "css-loader": "^3.2.0", 19 | "babel-loader": "^8.0.5", 20 | "style-loader": "^1.0.0", 21 | "node-sass": "^4.11.0", 22 | "sass-loader": "^8.0.0", 23 | "postcss-loader": "^3.0.0", 24 | "autoprefixer": "^9.4.7", 25 | "html-webpack-plugin": "^3.2.0", 26 | "clean-webpack-plugin": "^3.0.0", 27 | "webpack-dev-server": "^3.1.14", 28 | "mini-css-extract-plugin": "^0.9.0", 29 | "webpack-bundle-analyzer": "^3.0.4" 30 | }, 31 | "scripts": { 32 | "build": "webpack", 33 | "start": "webpack-dev-server" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/fr/workshops/novice/novice-koans.md: -------------------------------------------------------------------------------- 1 | # Auto évaluation novice (Koâns) :pushpin: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/novice/koans`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ::: tip 7 | Cet exercice n'est pas à faire pendant un workshop. 8 | Vous pouvez le faire à tête reposée, pour vérifiez que vous validez toutes les compétences d'un utilisateur novice de webpack. 9 | 10 | Vous avez ici une page web très simple où tout a été hardcodé dans l'`index.html`. 11 | Vous avez déjà toutes les dépendances nécessaire pour faire cette évaluation. 12 | ::: 13 | 14 | ## "Definition of done" 15 | 16 | - Définir la configuration du webpack 17 | - Vous devez générer un bundle `main.js`. 18 | - Votre fichier `index.html` doit être généré avec webpack et les bundles doivent être ajoutés automatiquement. 19 | - Les librairies externes doivent être importées par webpack et non par _CDN_. 20 | - Tous les fichiers générés doivent se trouver dans le dossier `dist`. 21 | - ` 27 | 28 | 29 |
30 | Click Me ! 31 | Oh No! Click Me ! 32 |
33 | 46 | 51 | 56 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Welcome to webpack-workshop 👋

2 |

3 | Version 4 | 5 | Netlify Status 6 | 7 | license 8 | stars 9 | fork me 10 | 11 | Twitter: Slashgear_ 12 | 13 | 14 | Greenkeeper badge 15 | 16 |

17 | 18 | > webpack workshops to learn concepts, API and best practices 19 | 20 | ### 🏠 [Homepage](https://webpack-workshop.netlify.com/) 21 | 22 | ## Usage 23 | 24 | Just go to https://webpack-workshop.netlify.com/ 25 | 26 | ## Author 27 | 28 | 👤 **Antoine CARON** 29 | 30 | - Twitter: [@Slashgear\_](https://twitter.com/Slashgear_) 31 | - Github: [@Slashgear](https://github.com/Slashgear) 32 | 33 | ## Show your support 34 | 35 | Give a ⭐️ if this project helped you! 36 | 37 | ## 📝 License 38 | 39 | Copyright © 2019 [Antoine CARON](https://github.com/Slashgear).
40 | This project is [MIT](https://github.com/Slashgear/webpack-workshop/blob/master/LICENSE) licensed. 41 | 42 | --- 43 | 44 | _This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_ 45 | -------------------------------------------------------------------------------- /docs/why.md: -------------------------------------------------------------------------------- 1 | # Why learn Webpack? 2 | 3 | webpack is nowdays a very widespread tool in the world of web frontend development. 4 | It is either used directly or via toolkit (Vue-CLI, Angular-CLI, CRA, etc...). 5 | 6 | Its use may seem complicated at first, but the internal magic is relatively easy to grasp. 7 | 8 | > If its use can be hidden by a toolkit, why should we learn it then? 9 | 10 | It turns out that webpack, even if embedded in a toolkit, is a tool on which the web developer will have to act in order to be able to integrate his specific configuration. 11 | The developer may also want to play on the performance of his _build_. 12 | 13 | Tackling the evolution of a self-generated webpack configuration can be very complicated. 14 | As always, the self-generated code can save a lot of time at first, but will waste a lot later. 15 | 16 | To avoid this situation, it is very interesting to learn the concepts and basics of webpack through some examples. 17 | 18 | ## What is Webpack? 19 | 20 | Ok it is interesting to learn how to use webpack. But what is webpack? 21 | 22 | webpack is a tool for _packaging_ JS files for the web. 23 | It allows developers to write modular JS code (without requiring it to write everything to a file, or having to manage a file concatenation by hand). 24 | 25 | By _packaging_, we do not mean packaging or _package_ in the NPM sense. It is a _prepared_ archive for the web. 26 | 27 | webpack provides several major features: 28 | 29 | - It solves the dependency tree of the modules it has in input in order to build a complete graph of all dependencies (internal or NPM dependency). 30 | - It concatenates the files in the form of _bundles_ by following the configuration of its _outputs (output)_ while keeping the JS scopes. 31 | - It allows you to load only the JS required for the page. 32 | 33 | How many times have you seen this message when using tools like PageSpeed, Dareboost, Speedcurve, LightHouse or others? 34 | 35 | ![lighthouse results](./assets/lighthouse.png) 36 | 37 | The use of webpack is not limited to the JS, to a web target. 38 | You will be able, through the different workshops available here, to learn how to use advanced features. 39 | -------------------------------------------------------------------------------- /docs/fr/why.md: -------------------------------------------------------------------------------- 1 | # Pourquoi apprendre à utiliser Webpack ? 2 | 3 | webpack est aujourd'hui un outil très rependu dans le monde du développement web frontend. 4 | Il est soit utilisé directement ou soit par l'intermédiaire de toolkit (Vue-CLI, Angular-CLI, CRA, etc...). 5 | 6 | Son usage peut sembler compliquer dans un premier temps, mais la magie interne est relativement simple à appréhender. 7 | 8 | > Si son usage peut être masqué par un toolkit, pourquoi devrait-on l'apprendre alors ? 9 | 10 | Il se trouve que webpack, même si embarqué dans un toolkit, est un outil sur lequel le développeur web va devoir agir afin de pouvoir y intégrer sa configuration spécifique. 11 | Le développeur peut aussi vouloir jouer sur les performances de son _build_. 12 | 13 | S'attaquer à faire évoluer une configuration webpack auto générée peut être très compliquée. 14 | Comme toujours, le code auto généré peut faire gagner beaucoup de temps au début, mais en fera perdre beaucoup par la suite. 15 | 16 | Pour ne pas se retrouver dans cette situation, il est très intéressant d'apprendre les concepts et les bases de webpack par le biais de quelques exemples. 17 | 18 | ## Qu'est ce que Webpack ? 19 | 20 | Ok il est intéressant d'apprendre à utiliser webpack. Mais qu'est-ce que webpack ? 21 | 22 | webpack est un outil de _packaging_ de fichiers JS pour le web. 23 | Il permet aux développeur d'écrire du code JS modulaire (sans l'obliger à tout écrire dans un fichier, ou de devoir gérer une concaténation de fichier à la main). 24 | 25 | Par _packaging_, on ne parle pas d'emballage ou de _package_ au sens NPM. Il s'agit d'un archive _préparée_ pour le web. 26 | 27 | webpack apporte plusieurs fonctionnalités majeures: 28 | 29 | - Il résout l'arbre de dépendance des modules qu'il a en entrée afin de construire un graph complet de toutes les dépendances (interne ou dépendance NPM). 30 | - Il concatène les fichiers sous la forme de _bundles_ en suivant la configuration de ses _sorties (output)_ tout en conservant les scopes JS. 31 | - Il permet de charger uniquement le JS nécessaire pour la page. 32 | 33 | Combien de fois avez vous vu ce message lors de l'usage d'outils comme PageSpeed, Dareboost, Speedcurve, LightHouse ou autres ? 34 | 35 | ![lighthouse results](../assets/lighthouse.png) 36 | 37 | L'usage de webpack ne se limite pas qu'au JS,à une cible web. 38 | Vous pourrez, par les différents ateliers disponible ici apprendre à utiliser des fonctionnalités avancées. 39 | -------------------------------------------------------------------------------- /docs/workshops/intermediate/babel.md: -------------------------------------------------------------------------------- 1 | # Use Babel 2 | 3 | > To start this exercise, be sure to be in `./packages/intermediate/babel` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | > "Use next generation JavaScript, today." - Babel 9 | 10 | ::: tip 11 | If for you Babel role is not clear, don't hesitate to take a look at it's [documentation](https://babeljs.io/docs/en/index.html). 12 | ::: 13 | 14 | If you try to load your current application with an old browser which does not support latest features of EcmaScript. 15 | You will have some issues. :sob: 16 | When you encounter those issues, you often want to generate ES5 javascript in order to let your code run on every browser. 17 | That's where babel can help a lot. 18 | 19 | _Does webpack babelify your code automagically ?_ 20 | 21 | **No** 22 | 23 | The simplest way to do so is to use a specific loader for `.js` files which will babelify every Javascript files in the dependency graph. 24 | 25 | ## Setup _babel-loader_ 26 | 27 | The current application is very simple, your webpack configuration is working well but it does not use babel. 28 | Setup _babel-loader_ for every `.js` files. 29 | 30 | 31 | 32 |
33 | Solution 34 | 35 | ```js{29-39} 36 | const path = require("path"); 37 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 38 | 39 | module.exports = { 40 | entry: "./src/main.js", // The source module of our dependency graph 41 | output: { 42 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 43 | filename: "main.bundle.js", 44 | path: path.resolve(__dirname, "dist") 45 | }, 46 | module: { 47 | rules: [ 48 | { 49 | test: /\.jpg$/, 50 | use: [ 51 | { 52 | loader: "file-loader", 53 | options: { 54 | outputPath: "assets", 55 | publicPath: "dist/assets" 56 | } 57 | } 58 | ] 59 | }, 60 | { 61 | test: /\.css$/, 62 | use: ["style-loader", "css-loader"] 63 | }, 64 | { 65 | test: /\.js$/, 66 | exclude: /node_modules/, 67 | use: { 68 | loader: "babel-loader", 69 | options: { 70 | presets: ["@babel/preset-env"], 71 | cacheDirectory: true 72 | } 73 | } 74 | } 75 | ] 76 | }, 77 | plugins: [ 78 | new HtmlWebpackPlugin({ 79 | template: "./src/index.html" 80 | }) 81 | ] 82 | }; 83 | ``` 84 | 85 |
86 | -------------------------------------------------------------------------------- /docs/workshops/novice/code-assets.md: -------------------------------------------------------------------------------- 1 | # Handling :nail_care: assets 2 | 3 | > To start this exercise, be sure to be in `./packages/novice/code-assets` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | A web application is not only JS and HTML, you need CSS to pimp it! 9 | In this workshop we will try to load `style` in our application. 10 | 11 | ``` 12 | title.js 13 | <- color.js 14 | <- node_modules/lodash 15 | <- main.css 16 | ``` 17 | 18 | If you're not familiar with _Loaders_, you should do [static assets workshop](./static-assets.md) first. 19 | 20 | ## More loaders ! 21 | 22 | We added two loaders for you `css-loaders`, `style-loader` in dependencies. 23 | A very tiny stylesheet has been defined too. 24 | 25 | Try to define the configuration for loading your style with webpack and import `main.css` file in the entry module. 26 | 27 |
28 | Solution 29 | 30 | ```js{24-27} 31 | const path = require("path"); 32 | 33 | module.exports = { 34 | entry: "./src/title.js", // The source module of our dependency graph 35 | output: { 36 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 37 | filename: "main.js", 38 | path: path.resolve(__dirname, "dist") 39 | }, 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.jpg$/, 44 | use: [ 45 | { 46 | loader: "file-loader", 47 | options: { 48 | outputPath: "assets", 49 | publicPath: "dist/assets" 50 | } 51 | } 52 | ] 53 | }, 54 | { 55 | test: /\.css$/, 56 | use: ["style-loader", "css-loader"] 57 | } 58 | ] 59 | } 60 | }; 61 | ``` 62 | 63 | ```js{2} 64 | const { getRandomColor } = require("./color.js"); 65 | require("../assets/main.css"); 66 | 67 | let changeCount = 0; 68 | 69 | const el = document.querySelector("h1"); 70 | 71 | setInterval(() => { 72 | changeCount++; 73 | el.innerHTML = `This title will change ! ${changeCount}`; 74 | el.style.color = getRandomColor(); 75 | }, 1000); 76 | ``` 77 | 78 | :::tip 79 | You should look at the generated bundle. There is no generated CSS file. The CSS should be in the JS bundle. 80 | ::: 81 | 82 |
83 | 84 | ## Loader magic ! 85 | 86 | This time we will try to add a dependency in our css file by including this code: 87 | 88 | ```css 89 | body { 90 | background: url("./landscape.jpg") center center; 91 | } 92 | ``` 93 | 94 | :::tip 95 | Boum ! webpack loader can add files in the dependency graph. 96 | That's why your file is correctly resolved. 97 | ::: 98 | -------------------------------------------------------------------------------- /docs/fr/workshops/novice/code-assets.md: -------------------------------------------------------------------------------- 1 | # Le faire avec style :nail_care: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/novice/code-assets`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | Si vous n'êtes pas familiés avec _Loaders_, vous devriez faire [static assets workshop](./static-assets.md) en premier. 7 | 8 | ## Plus de loaders ! 9 | 10 | Nous avons ajouté deux loaders pour vous `css-loaders`, `style-loader` dans les dépendances. 11 | Une très petite feuille de style a également été définie. 12 | 13 | Essayez de définir la configuration pour charger votre style avec webpack et importez le fichier `main.css` dans le module d'entrée. 14 | 15 | [Doc de CSS Loader](https://github.com/webpack-contrib/css-loader) 16 | 17 |
18 | Solution 19 | 20 | ```js{24-27} 21 | const path = require("path"); 22 | 23 | module.exports = { 24 | entry: "./src/title.js", // The source module of our dependency graph 25 | output: { 26 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 27 | filename: "main.js", 28 | path: path.resolve(__dirname, "dist") 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.jpg$/, 34 | use: [ 35 | { 36 | loader: "file-loader", 37 | options: { 38 | outputPath: "assets", 39 | publicPath: "dist/assets" 40 | } 41 | } 42 | ] 43 | }, 44 | { 45 | test: /\.css$/, 46 | use: ["style-loader", "css-loader"] 47 | } 48 | ] 49 | } 50 | }; 51 | ``` 52 | 53 | ```js{2} 54 | const { getRandomColor } = require("./color.js"); 55 | require("../assets/main.css"); 56 | 57 | let changeCount = 0; 58 | 59 | const el = document.querySelector("h1"); 60 | 61 | setInterval(() => { 62 | changeCount++; 63 | el.innerHTML = `This title will change ! ${changeCount}`; 64 | el.style.color = getRandomColor(); 65 | }, 1000); 66 | ``` 67 | 68 |
69 | 70 | :::tip 71 | Vous devriez regarder le bundle généré. Il n'y a pas de fichier CSS généré. Le CSS doit être dans le bundle JS. 72 | ::: 73 | 74 | ## La magie des Loaders ! 75 | 76 | Cette fois, nous allons essayer d'ajouter une dépendance dans notre fichier css en incluant ce code : 77 | 78 | ```css 79 | body { 80 | background: url("./landscape.jpg") center center; 81 | } 82 | ``` 83 | 84 | :::tip 85 | Et la ça marche ! 86 | 87 | webpack peut, grâce à des loaders, détecter d'autres dépendances et les ajouter dans son graphe. 88 | 89 | ``` 90 | title.js 91 | <- color.js 92 | <- node_modules/lodash 93 | <- main.css 94 | <- landscape.jpg 95 | ``` 96 | 97 | ::: 98 | -------------------------------------------------------------------------------- /packages/advanced/loaders/src/bulbasaur.pokemon: -------------------------------------------------------------------------------- 1 | { 2 | "abilities": [ 3 | { 4 | "ability": { 5 | "name": "chlorophyll", 6 | "url": "https://pokeapi.co/api/v2/ability/34/" 7 | }, 8 | "is_hidden": true, 9 | "slot": 3 10 | }, 11 | { 12 | "ability": { 13 | "name": "overgrow", 14 | "url": "https://pokeapi.co/api/v2/ability/65/" 15 | }, 16 | "is_hidden": false, 17 | "slot": 1 18 | } 19 | ], 20 | "base_experience": 64, 21 | "forms": [ 22 | { "name": "bulbasaur", "url": "https://pokeapi.co/api/v2/pokemon-form/1/" } 23 | ], 24 | "height": 7, 25 | "held_items": [], 26 | "id": 1, 27 | "is_default": true, 28 | "location_area_encounters": "https://pokeapi.co/api/v2/pokemon/1/encounters", 29 | "name": "bulbasaur", 30 | "order": 1, 31 | "species": { 32 | "name": "bulbasaur", 33 | "url": "https://pokeapi.co/api/v2/pokemon-species/1/" 34 | }, 35 | "sprites": { 36 | "back_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/1.png", 37 | "back_female": null, 38 | "back_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/1.png", 39 | "back_shiny_female": null, 40 | "front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png", 41 | "front_female": null, 42 | "front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/1.png", 43 | "front_shiny_female": null 44 | }, 45 | "stats": [ 46 | { 47 | "base_stat": 45, 48 | "effort": 0, 49 | "stat": { "name": "speed", "url": "https://pokeapi.co/api/v2/stat/6/" } 50 | }, 51 | { 52 | "base_stat": 65, 53 | "effort": 0, 54 | "stat": { 55 | "name": "special-defense", 56 | "url": "https://pokeapi.co/api/v2/stat/5/" 57 | } 58 | }, 59 | { 60 | "base_stat": 65, 61 | "effort": 1, 62 | "stat": { 63 | "name": "special-attack", 64 | "url": "https://pokeapi.co/api/v2/stat/4/" 65 | } 66 | }, 67 | { 68 | "base_stat": 49, 69 | "effort": 0, 70 | "stat": { "name": "defense", "url": "https://pokeapi.co/api/v2/stat/3/" } 71 | }, 72 | { 73 | "base_stat": 49, 74 | "effort": 0, 75 | "stat": { "name": "attack", "url": "https://pokeapi.co/api/v2/stat/2/" } 76 | }, 77 | { 78 | "base_stat": 45, 79 | "effort": 0, 80 | "stat": { "name": "hp", "url": "https://pokeapi.co/api/v2/stat/1/" } 81 | } 82 | ], 83 | "types": [ 84 | { 85 | "slot": 2, 86 | "type": { "name": "poison", "url": "https://pokeapi.co/api/v2/type/4/" } 87 | }, 88 | { 89 | "slot": 1, 90 | "type": { "name": "grass", "url": "https://pokeapi.co/api/v2/type/12/" } 91 | } 92 | ], 93 | "weight": 69 94 | } 95 | -------------------------------------------------------------------------------- /docs/fr/workshops/intermediate/babel.md: -------------------------------------------------------------------------------- 1 | # Elle est Babel la vie ? 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/intermediate/babel`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | > "Utiliser le Javascript de demain, aujourd'hui" - Babel 9 | 10 | ::: tip 11 | Si pour vous le rôle de Babel n'est pas clair, n'hésitez pas à consulter sa [documentation](https://babeljs.io/docs/en/index.html). 12 | ::: 13 | 14 | Si vous essayez de charger votre application actuelle avec un ancien navigateur qui ne supporte pas les dernières fonctionnalités d'EcmaScript. 15 | Vous aurez des problèmes. :sob: 16 | Lorsque vous rencontrez ces problèmes, vous voulez souvent générer du javascript ES5 afin de laisser tourner votre code sur chaque navigateur. 17 | C'est là que Babel peut beaucoup aider. 18 | 19 | _Est-ce que webpack babelify votre code automatiquement ?_ 20 | 21 | **Non** 22 | 23 | La façon la plus simple de le faire est d'utiliser un chargeur spécifique pour les fichiers `.js` qui va babélifier tous les fichiers Javascript de l'arbre de dépendance. 24 | 25 | ## Initialiser le _babel-loader_ 26 | 27 | L'application actuelle est très simple, votre configuration webpack fonctionne bien mais n'utilise pas babel. 28 | Configurez _babel-loader_ pour chaque fichier `.js`. 29 | 30 | - Essayer de mettre en place le _babel-loader_ en suivant la [documentation](https://github.com/babel/babel-loader) 31 | - Essayer d'accéder à votre application avec un navigateur moins à jour que Firefox ou Chrome. 32 | 33 |
34 | Solution 35 | 36 | ```js{29-39} 37 | const path = require("path"); 38 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 39 | 40 | module.exports = { 41 | entry: "./src/main.js", // The source module of our dependency graph 42 | output: { 43 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 44 | filename: "main.bundle.js", 45 | path: path.resolve(__dirname, "dist") 46 | }, 47 | module: { 48 | rules: [ 49 | { 50 | test: /\.jpg$/, 51 | use: [ 52 | { 53 | loader: "file-loader", 54 | options: { 55 | outputPath: "assets", 56 | publicPath: "dist/assets" 57 | } 58 | } 59 | ] 60 | }, 61 | { 62 | test: /\.css$/, 63 | use: ["style-loader", "css-loader"] 64 | }, 65 | { 66 | test: /\.js$/, 67 | exclude: /node_modules/, 68 | use: { 69 | loader: "babel-loader", 70 | options: { 71 | presets: ["@babel/preset-env"], 72 | cacheDirectory: true 73 | } 74 | } 75 | } 76 | ] 77 | }, 78 | plugins: [ 79 | new HtmlWebpackPlugin({ 80 | template: "./src/index.html" 81 | }) 82 | ] 83 | }; 84 | ``` 85 | 86 |
87 | -------------------------------------------------------------------------------- /docs/fr/workshops/intermediate/alias.md: -------------------------------------------------------------------------------- 1 | # Les alias :alien: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/intermediate/alias`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Le problème 7 | 8 | Structurer un projet web peut être compliqué. 9 | La structure de dossier peut vite devenir capilotractée. 10 | 11 | Exemple ici avec le fichier `main.js`: 12 | 13 | ```js{2} 14 | import PokemonComponent from "./pokemon.component"; 15 | import { getPokemons } from "./my/own/strange/way/to/structrure/my/project/services/pokemon.service"; 16 | 17 | const pokemonList = document.querySelector("#pokemons"); 18 | 19 | getPokemons().then(response => { 20 | response.results.map(({ name }, index) => { 21 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 22 | }); 23 | }); 24 | ``` 25 | 26 | Ici, l'import vers le fichier `pokemon.service` est extrêmement long et compliqué. 27 | Il n'est ni pratique à l'usage ni à la lecture. 28 | 29 | Parfois, le fichier est très "haut" dans l'arborescence et votre _path_ va ressembler à `../../../../../../../../../../../`. 30 | 31 | ## La solution proposée par webpack 32 | 33 | Sur votre machine, vous auriez mis en place un lien symbolique. 34 | Mais utiliser des liens symbolique dans un projet géré par NPM peut créer des problèmes avec l'usage des `link`. 35 | 36 | Il est plutôt recommandé d'utiliser un `alias` de résolution. 37 | 38 | Dans l'exemple, essayez de mettre en place un alias de résolution qui vous permettra de transformer 39 | 40 | ```js 41 | import { getPokemons } from "./my/own/strange/way/to/structrure/my/project/services/pokemon.service"; 42 | ``` 43 | 44 | en 45 | 46 | ```js 47 | import { getPokemons } from "services/pokemon.service"; 48 | ``` 49 | 50 | N'hésitez pas à vous aider de la [doc de webpack sur les alias](https://webpack.js.org/configuration/resolve/). 51 | 52 |
53 | Solution 54 | 55 | ```js{11-15} 56 | const path = require("path"); 57 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 58 | 59 | module.exports = { 60 | entry: "./src/main.js", // The source module of our dependency graph 61 | output: { 62 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 63 | filename: "main.bundle.js", 64 | path: path.resolve(__dirname, "dist") 65 | }, 66 | resolve: { 67 | alias: { 68 | services: path.resolve( 69 | __dirname, 70 | "src/my/own/strange/way/to/structrure/my/project/services" 71 | ) 72 | } 73 | }, 74 | module: { 75 | rules: [ 76 | { 77 | test: /\.jpg$/, 78 | use: [ 79 | { 80 | loader: "file-loader", 81 | options: { 82 | outputPath: "assets", 83 | publicPath: "dist/assets" 84 | } 85 | } 86 | ] 87 | }, 88 | { 89 | test: /\.css$/, 90 | use: ["style-loader", "css-loader"] 91 | } 92 | ] 93 | }, 94 | plugins: [ 95 | new HtmlWebpackPlugin({ 96 | template: "./src/index.html" 97 | }) 98 | ] 99 | }; 100 | ``` 101 | 102 |
103 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at antoine395.caron@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /docs/fr/workshops/novice/basics.md: -------------------------------------------------------------------------------- 1 | # Les bases 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/novice/basic`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Ce premier exemple a pour but de vous aider à comprendre pourquoi webpack existe et son usage basique. 9 | 10 | Dans cette application, nous avons défini deux modules CommonJS (modules utilisés [sur NodeJS](https://nodejs.org/docs/latest/api/modules.html)). 11 | Ils sont tous les deux chargés dans `index.html`. 12 | 13 | Si vous n'êtes pas familiés avec les capacités des navigateurs, sachez que les modules CommonJS n'y sont pas fonctionnels. 14 | Un navigateur ne peut pas gérer l'import direct de dépendance NodeJS. 15 | 16 | Ici le graphe de dépendance de l'application ressemble à: 17 | 18 | ``` 19 | title.js 20 | <- color.js 21 | <- node_modules/lodash 22 | ``` 23 | 24 | ## La solution webpack 25 | 26 | webpack est un package NodeJS qui génère un _bundle_ (concaténation de modules), basé sur la résolution d'un arbre de dépendances. 27 | 28 | ### Étape 1: Mise en place d'une configuration simple 29 | 30 | Pour configurer webpack, vous devez créer un fichier nommé `webpack.config.js` à la racine de votre projet. Dans ce fichier, exporter un module. 31 | Couplé avec un outil comme `webpack-cli`, vous pourrez alors facilement lancer un _build_. 32 | 33 | ```js 34 | const path = require("path"); 35 | 36 | module.exports = { 37 | entry: "./src/title.js", // Le module racine de l'arbre de dépendance. 38 | output: { 39 | filename: "main.js", 40 | path: path.resolve(__dirname, "dist") 41 | } 42 | }; 43 | ``` 44 | 45 | Après avoir lancé la commande `yarn webpack`, un nouveau fichier `main.js` devrait être généré dans le dossier `dist`. 46 | 47 | ### Étape 2: Changer les cibles des scripts d'index.html 48 | 49 | Pour l'instant, `index.html` ne référence pas le fichier _output_, nous devons donc changer cela. 50 | Il suffit de changer le tag ` 63 | 64 | 65 | ``` 66 | 67 | ### Étape 3: Définir un script pour lancer webpack 68 | 69 | Grâce à un `npm script`, vous allez définir une commande pour lancer le build de webpack. 70 | 71 | ```json{13,14,15} 72 | { 73 | "name": "@novice/basic", 74 | "version": "1.0.0", 75 | "license": "MIT", 76 | "private": true, 77 | "dependencies": { 78 | "lodash": "^4.17.11" 79 | }, 80 | "devDependencies": { 81 | "webpack": "^4.28.4", 82 | "webpack-cli": "^3.2.1" 83 | }, 84 | "scripts": { 85 | "build": "webpack" 86 | } 87 | } 88 | ``` 89 | 90 | Maintenant lancez le `build` et ouvrez le fichier `index.html` dans un navigateur. 91 | 92 | ```bash 93 | yarn build 94 | ``` 95 | 96 | Regardez le _bundle_ généré et testez l'application. 97 | 98 | ### Que s'est-il passé ? 99 | 100 | ici webpack, grâce à son fichier de configuration, a construit un arbre de dépendance en se basant sur l'entry `title.js`. 101 | Une fois cet arbre résolu, en suivant sa configuration de "sortie", il a généré un fichier `main.js` contenant l'ensemble des modules de l'arbre de dépendances sous la forme de chunks. 102 | 103 | N'hésitez pas à jeter un coup d'oeil à ce qui est contenu dans ce fichier généré. 104 | -------------------------------------------------------------------------------- /docs/workshops/novice/basics.md: -------------------------------------------------------------------------------- 1 | # Basics 2 | 3 | > To start this exercise, be sure to be in `./packages/novice/basic` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | This first example is here to help you why webpack exists and its basic usage. 9 | 10 | In this app, we define two CommonJS modules (commonly used [in a NodeJS env](https://nodejs.org/docs/latest/api/modules.html)). 11 | They are both loaded in `index.html`. 12 | 13 | If you're not familiar enough with the browser env, it won't be able to load CommonJS bundle. 14 | A browser can't handle NodeJS-like dependencies. 15 | 16 | Here is the dependency graph of those modules: 17 | 18 | ``` 19 | title.js 20 | <- color.js 21 | <- node_modules/lodash 22 | ``` 23 | 24 | ## Old way 25 | 26 | If we were few years ago, we would have to load all those files in the browser without the `require` syntax and by keeping the dependency order. 27 | For `lodash` library we would have used a cdn to load it. 28 | 29 | This way works perfectly... But for a long time project, it would generate a lot of ` 74 | 75 | 76 | ``` 77 | 78 | ### Step 3: Script the build with webpack-cli 79 | 80 | As you can figure out, we will trigger the build a lot! A good practice is to add a new `build` script in `package.json` . 81 | 82 | ```json{13,14,15} 83 | { 84 | "name": "@novice/basic", 85 | "version": "1.0.0", 86 | "license": "MIT", 87 | "private": true, 88 | "dependencies": { 89 | "lodash": "^4.17.11" 90 | }, 91 | "devDependencies": { 92 | "webpack": "^4.28.4", 93 | "webpack-cli": "^3.2.1" 94 | }, 95 | "scripts": { 96 | "build": "webpack" 97 | } 98 | } 99 | ``` 100 | 101 | Now launch the `build` and open your `index.html` in your browser: 102 | 103 | ```bash 104 | yarn build 105 | ``` 106 | 107 | Look at the generated _bundle_ 108 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | sitemap: { 4 | hostname: "https://webpack-workshop.netlify.com" 5 | } 6 | }, 7 | locales: { 8 | "/": { 9 | lang: "en-US", // this will be set as the lang attribute on 10 | title: "webpack Workshop", 11 | description: "webpack discovering and mastering workshops" 12 | }, 13 | "/fr/": { 14 | lang: "fr-FR", 15 | title: "Ateliers autour de webpack", 16 | description: "Ateliers pour découvrir et maîtriser webpack" 17 | } 18 | }, 19 | themeConfig: { 20 | editLinkText: "Edit cette page sur Github", 21 | lastUpdated: "Mis à jour le", 22 | repo: "Slashgear/webpack-workshop", 23 | repoLabel: "Contribue !", 24 | docsRepo: "Slashgear/webpack-workshop", 25 | docsDir: "docs", 26 | editLinks: true, 27 | algolia: { 28 | apiKey: "5f0c4bd6212a8fc141c63283636d5228", 29 | indexName: "webpack_workshop" 30 | }, 31 | locales: { 32 | "/": { 33 | selectText: "Languages", 34 | label: "English", 35 | nav: [ 36 | { text: "Home", link: "/" }, 37 | { text: "Workshops", link: "/workshops/" } 38 | ], 39 | sidebar: [ 40 | "/workshops/", 41 | "/why.md", 42 | { 43 | title: "Novice", 44 | collapsable: false, 45 | children: [ 46 | "/workshops/novice/basics", 47 | "/workshops/novice/static-assets", 48 | "/workshops/novice/code-assets", 49 | "/workshops/novice/outputs", 50 | "/workshops/novice/novice-koans" 51 | ] 52 | }, 53 | { 54 | title: "Intermediate", 55 | collapsable: false, 56 | children: [ 57 | "/workshops/intermediate/dev", 58 | "/workshops/intermediate/babel", 59 | "/workshops/intermediate/style", 60 | "/workshops/intermediate/reduce-bundle-size", 61 | "/workshops/intermediate/modern-build", 62 | "/workshops/intermediate/compression", 63 | "/workshops/intermediate/intermediate-koans" 64 | ] 65 | }, 66 | { 67 | title: "Advanced", 68 | collapsable: false, 69 | children: ["/workshops/advanced/plugins"] 70 | } 71 | ] 72 | }, 73 | "/fr/": { 74 | selectText: "Langues", 75 | label: "Français", 76 | nav: [{ text: "Ateliers", link: "/fr/workshops/" }], 77 | sidebar: [ 78 | "/fr/workshops/", 79 | "/fr/why.md", 80 | { 81 | title: "Débutant", 82 | collapsable: false, 83 | children: [ 84 | "/fr/workshops/novice/basics", 85 | "/fr/workshops/novice/static-assets", 86 | "/fr/workshops/novice/code-assets", 87 | "fr/workshops/novice/outputs", 88 | "fr/workshops/novice/novice-koans" 89 | ] 90 | }, 91 | { 92 | title: "Intermédiaire", 93 | collapsable: false, 94 | children: [ 95 | "fr/workshops/intermediate/dev", 96 | "fr/workshops/intermediate/babel", 97 | "fr/workshops/intermediate/alias", 98 | "fr/workshops/intermediate/style", 99 | "fr/workshops/intermediate/reduce-bundle-size", 100 | "fr/workshops/intermediate/modern-build", 101 | "fr/workshops/intermediate/compression", 102 | "fr/workshops/intermediate/intermediate-koans" 103 | ] 104 | }, 105 | { 106 | title: "Avancé", 107 | collapsable: false, 108 | children: [ 109 | "fr/workshops/advanced/plugins", 110 | "fr/workshops/advanced/loaders" 111 | ] 112 | } 113 | ] 114 | } 115 | } 116 | } 117 | }; 118 | -------------------------------------------------------------------------------- /docs/workshops/advanced/plugins.md: -------------------------------------------------------------------------------- 1 | # Your first webpack plugin :heart: 2 | 3 | > To start this exercise, be sure to be in `./packages/advanced/plugins` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | You already saw and used many plugins with webpack. 9 | It gives user possibility to add features, optimize performance, etc... 10 | 11 | An API is open to let you implement your own webpack plugin. 12 | 13 | ::: tip 14 | In your project you may need a plugin that already have been created by the community, don't hesitate to look at [awesome-webpack](https://github.com/webpack-contrib/awesome-webpack#webpack-plugins). 15 | ::: 16 | 17 | You should also know that more than 70% of webpack core code is using it's own plugin API. webpack code is a great example of _how to write a plugin ?_ 18 | 19 | ## Hooks and tapable 20 | 21 | Creating a Plugin 22 | A plugin for webpack consists of 23 | 24 | - A named JavaScript function. 25 | - Defines apply method in its prototype. 26 | - Specifies an [event hook](https://webpack.js.org/api/compiler-hooks/) to tap into. 27 | - Manipulates webpack internal instance specific data. 28 | - Invokes webpack provided callback after functionality is complete. 29 | 30 | ```javascript 31 | class MyExampleWebpackPlugin { 32 | // Define `apply` as its prototype method which is supplied with compiler as its argument 33 | apply(compiler) { 34 | // Specify the event hook to attach to 35 | compiler.hooks.done.tapAsync( 36 | "MyExampleWebpackPlugin", 37 | (compilation, callback) => { 38 | console.log("This is an example plugin!"); 39 | console.log( 40 | "Here’s the `compilation` object which represents a single build of assets:", 41 | compilation 42 | ); 43 | 44 | // Manipulate the build using the plugin API provided by webpack 45 | compilation.addModule(/* ... */); 46 | 47 | callback(); 48 | } 49 | ); 50 | } 51 | } 52 | ``` 53 | 54 | ## Create a BuildTime 55 | 56 | In order to learn to how to write a plugin. Try to define a plugin that take `stats` from `done` hooks and log build time in milliseconds. 57 | 58 |
59 | Solution 60 | 61 | ```javascript{8-16,65} 62 | const path = require("path"); 63 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 64 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 65 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 66 | const CompressionPlugin = require("compression-webpack-plugin"); 67 | 68 | class BuildTime { 69 | apply(compiler) { 70 | compiler.hooks.done.tapAsync("StatsFilePlugin", stats => { 71 | console.log( 72 | `Build took ${stats.endTime - stats.startTime} milliseconds!` 73 | ); 74 | }); 75 | } 76 | } 77 | 78 | module.exports = { 79 | mode: "production", 80 | entry: "./src/main.js", // The source module of our dependency graph 81 | devServer: { 82 | contentBase: "./dist" 83 | }, 84 | output: { 85 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 86 | filename: "[name].bundle.[hash].js", 87 | path: path.resolve(__dirname, "dist") 88 | }, 89 | module: { 90 | rules: [ 91 | { 92 | test: /\.js$/, 93 | exclude: /node_modules/, 94 | loader: "babel-loader" 95 | }, 96 | { 97 | test: /\.jpg$/, 98 | use: [ 99 | { 100 | loader: "file-loader", 101 | options: { 102 | outputPath: "assets", 103 | publicPath: "assets" 104 | } 105 | } 106 | ] 107 | }, 108 | { 109 | test: /\.(sass|css)$/, 110 | use: ["style-loader", "css-loader", "sass-loader"] 111 | }, 112 | { 113 | test: /\.vue$/, 114 | use: "vue-loader" 115 | } 116 | ] 117 | }, 118 | plugins: [ 119 | new VueLoaderPlugin(), 120 | new CleanWebpackPlugin("dist"), 121 | new HtmlWebpackPlugin({ 122 | template: "./src/index.html" 123 | }), 124 | new CompressionPlugin(), 125 | new BuildTime() 126 | ] 127 | }; 128 | ``` 129 | 130 |
131 | -------------------------------------------------------------------------------- /packages/intermediate/koans/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple JS file 6 | 7 | 11 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/fr/workshops/advanced/plugins.md: -------------------------------------------------------------------------------- 1 | # Votre premier plugin :heart: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/advanced/plugins`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Vous avez déjà vu et utilisé de nombreux plugins avec webpack. 9 | Il donne à l'utilisateur la possibilité d'ajouter des fonctionnalités, d'optimiser les performances, etc... 10 | 11 | Une API est ouverte pour vous permettre d'implémenter votre propre plugin webpack. 12 | 13 | ::: tip Petit conseil 14 | Dans votre projet vous pouvez avoir besoin d'un plugin qui a déjà été créé par la communauté, n'hésitez pas à regarder [awesome-webpack](https://github.com/webpack-contrib/awesome-webpack#webpack-plugins). 15 | ::: 16 | 17 | Vous devez également savoir que plus de 70% du code de base de webpack utilise sa propre API de plugin. 18 | Le code webpack est un excellent exemple de _comment écrire un plugin ?_ 19 | 20 | ## Hooks et Tapable 21 | 22 | Un plugin webpack c'est: 23 | 24 | - Une fonction JavaScript nommée. 25 | - Définit la méthode `apply` dans son prototype. 26 | - Spécifie un [event hook](https://webpack.js.org/api/compiler-hooks/) à utiliser. 27 | - Manipule les données spécifiques aux instances internes du webpack. 28 | 29 | Exemple ici: 30 | 31 | ```javascript 32 | class MyExampleWebpackPlugin { 33 | apply(compiler) { 34 | // Spécifie sur quel hook s'accroche le plugin 35 | compiler.hooks.done.tapAsync( 36 | "MyExampleWebpackPlugin", 37 | (compilation, callback) => { 38 | console.log("This is an example plugin!"); 39 | console.log( 40 | "Here’s the `compilation` object which represents a single build of assets:", 41 | compilation 42 | ); 43 | 44 | // Manipulation des données internes de webpack 45 | compilation.addModule(/* ... */); 46 | 47 | callback(); 48 | } 49 | ); 50 | } 51 | } 52 | ``` 53 | 54 | ## Créons un plugin pour mesurer le temps de build 55 | 56 | :::warning 57 | Ce plugin existe déjà, vous pouvez déjà avoir cette info mais c'est un prétexte pour apprendre à écrire un plugin. 58 | ::: 59 | 60 | Essayez de définir un plugin qui prend les `stats` données pas le hook `done` et afficher le temps de build en millisecondes. 61 | 62 |
63 | Solution 64 | 65 | ```javascript{7-15,64} 66 | const path = require("path"); 67 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 68 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 69 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 70 | const CompressionPlugin = require("compression-webpack-plugin"); 71 | 72 | class BuildTime { 73 | apply(compiler) { 74 | compiler.hooks.done.tapAsync("StatsFilePlugin", stats => { 75 | console.log( 76 | `Build took ${stats.endTime - stats.startTime} milliseconds!` 77 | ); 78 | }); 79 | } 80 | } 81 | 82 | module.exports = { 83 | mode: "production", 84 | entry: "./src/main.js", // The source module of our dependency graph 85 | devServer: { 86 | contentBase: "./dist" 87 | }, 88 | output: { 89 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 90 | filename: "[name].bundle.[hash].js", 91 | path: path.resolve(__dirname, "dist") 92 | }, 93 | module: { 94 | rules: [ 95 | { 96 | test: /\.js$/, 97 | exclude: /node_modules/, 98 | loader: "babel-loader" 99 | }, 100 | { 101 | test: /\.jpg$/, 102 | use: [ 103 | { 104 | loader: "file-loader", 105 | options: { 106 | outputPath: "assets", 107 | publicPath: "assets" 108 | } 109 | } 110 | ] 111 | }, 112 | { 113 | test: /\.(sass|css)$/, 114 | use: ["style-loader", "css-loader", "sass-loader"] 115 | }, 116 | { 117 | test: /\.vue$/, 118 | use: "vue-loader" 119 | } 120 | ] 121 | }, 122 | plugins: [ 123 | new VueLoaderPlugin(), 124 | new CleanWebpackPlugin("dist"), 125 | new HtmlWebpackPlugin({ 126 | template: "./src/index.html" 127 | }), 128 | new CompressionPlugin(), 129 | new BuildTime() 130 | ] 131 | }; 132 | ``` 133 | 134 |
135 | -------------------------------------------------------------------------------- /docs/workshops/novice/outputs.md: -------------------------------------------------------------------------------- 1 | # Playing with outputs 2 | 3 | > To start this exercise, be sure to be in `./packages/novice/outputs` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | Your app will normally have more and more code. 7 | In order to limit your bundle size, you will try to split it in separated files. 8 | 9 | ## Adding entries 10 | 11 | Now we will force output creation by adding another entry. 12 | This is the current dependency tree of this small app. 13 | 14 | ``` 15 | title.js 16 | <- color.js 17 | <- node_modules/lodash 18 | <- main.css 19 | <- landscape.jpg 20 | ``` 21 | 22 | Try to add `color.js` file as an entry. 23 | Then look at the dist folder. 24 | 25 | ::: warning 26 | You will probably have an error when you try to add another entry. 27 | ::: 28 | 29 |
30 | Solution 31 | 32 | ```js{4-10} 33 | const path = require("path"); 34 | 35 | module.exports = { 36 | entry: { 37 | main: "./src/title.js", 38 | color: "./src/color.js" 39 | }, // The source module of our dependency graph 40 | output: { 41 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 42 | filename: "[name].js", 43 | path: path.resolve(__dirname, "dist") 44 | }, 45 | module: { 46 | rules: [ 47 | { 48 | test: /\.jpg$/, 49 | use: [ 50 | { 51 | loader: "file-loader", 52 | options: { 53 | outputPath: "assets", 54 | publicPath: "dist/assets" 55 | } 56 | } 57 | ] 58 | }, 59 | { 60 | test: /\.css$/, 61 | use: ["style-loader", "css-loader"] 62 | } 63 | ] 64 | } 65 | }; 66 | ``` 67 | 68 |
69 | 70 | ## Generating your index file 71 | 72 | If you find out the little trick to let webpack generate the two bundles. 73 | You can still open your app and it's perfectly working. 74 | 75 | That's nice ! :clap: 76 | 77 | You can also notice that only the matching dependency tree is in each bundle. 78 | 79 | But there is an issue, your browser is only getting the main bundle. 80 | You could add manually the bundle in your index.html file. 81 | However it will be painful to do it each time you wanted to add another bundle or just when you rename it. 82 | 83 | Your `index.html` file could be generated by webpack thanks to a Plugin: The [HtmlWebpackPlugin](https://webpack.js.org/plugins/html-webpack-plugin/). 84 | For that you have to define a `plugins` key in the webpack configuration. 85 | 86 |
87 | Solution 88 | 89 | ```js{2,34-38} 90 | const path = require("path"); 91 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 92 | 93 | module.exports = { 94 | entry: { 95 | main: "./src/title.js", 96 | color: "./src/color.js" 97 | }, // The source module of our dependency graph 98 | output: { 99 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 100 | filename: "[name].js", 101 | path: path.resolve(__dirname, "dist") 102 | }, 103 | module: { 104 | rules: [ 105 | { 106 | test: /\.jpg$/, 107 | use: [ 108 | { 109 | loader: "file-loader", 110 | options: { 111 | outputPath: "assets", 112 | publicPath: "dist/assets" 113 | } 114 | } 115 | ] 116 | }, 117 | { 118 | test: /\.css$/, 119 | use: ["style-loader", "css-loader"] 120 | } 121 | ] 122 | }, 123 | plugins: [ 124 | new HtmlWebpackPlugin({ 125 | template: "./index.html" 126 | }) 127 | ] 128 | }; 129 | ``` 130 | 131 |
132 | 133 | ## Cleaning the `dist` folder 134 | 135 | As you might have noticed over the past guides and code examples, our `/dist` folder has become quite cluttered. webpack will generate the files and put them in the `/dist` folder for you, but it doesn't keep track of which files are actually in use by your project. 136 | 137 | In general it's good practice to clean the `/dist` folder before each build, so that only used files will be generated. Let's take care of that. 138 | 139 | A popular plugin to manage this is the clean-webpack-plugin so let's install and configure it. 140 | 141 |
142 | Solution 143 | Import your plugin and add this plugin configuration as first plugin. 144 | 145 | ```js 146 | new CleanWebpackPlugin(); 147 | ``` 148 | 149 |
150 | -------------------------------------------------------------------------------- /docs/workshops/intermediate/compression.md: -------------------------------------------------------------------------------- 1 | # File compression 🗜️ 2 | 3 | > To start this exercise, be sure to be in `./packages/intermediate/compression` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Why compressing your file outputs ? 7 | 8 | Gzip compression is something which is saving 30% of internet transfer volume. 9 | You could let your webserver compress your generated bundle _on the fly_ on each request but for static files you should really try to compress it in your build steps. 10 | 11 | All decent web server can serve pre-compressed files if browser asked for it. 12 | 13 | Good news, webpack has a plugin for you. :tada: 14 | 15 | ## Add Gzip compression 16 | 17 | Look at [webpack compression plugin](https://webpack.js.org/plugins/compression-webpack-plugin) configuration and try to add it. 18 | 19 |
20 | Solution 21 | 22 | ```js{5,53} 23 | const path = require("path"); 24 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 25 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 26 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 27 | const CompressionPlugin = require("compression-webpack-plugin"); 28 | 29 | module.exports = { 30 | mode: "production", 31 | entry: "./src/main.js", // The source module of our dependency graph 32 | devServer: { 33 | contentBase: "./dist" 34 | }, 35 | output: { 36 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 37 | filename: "[name].bundle.[hash].js", 38 | path: path.resolve(__dirname, "dist") 39 | }, 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.js$/, 44 | exclude: /node_modules/, 45 | loader: "babel-loader" 46 | }, 47 | { 48 | test: /\.jpg$/, 49 | use: [ 50 | { 51 | loader: "file-loader", 52 | options: { 53 | outputPath: "assets", 54 | publicPath: "assets" 55 | } 56 | } 57 | ] 58 | }, 59 | { 60 | test: /\.(sass|css)$/, 61 | use: ["style-loader", "css-loader", "sass-loader"] 62 | }, 63 | { 64 | test: /\.vue$/, 65 | use: "vue-loader" 66 | } 67 | ] 68 | }, 69 | plugins: [ 70 | new VueLoaderPlugin(), 71 | new CleanWebpackPlugin("dist"), 72 | new HtmlWebpackPlugin({ 73 | template: "./src/index.html" 74 | }), 75 | new CompressionPlugin() 76 | ] 77 | }; 78 | ``` 79 | 80 |
81 | 82 | ::: tip 83 | This [article](https://medium.com/@selvaganesh93/how-to-serve-webpack-gzipped-file-in-production-using-nginx-692eadbb9f1c) explain how to use your compressed files in an Nginx configuration. 84 | ::: 85 | 86 | ## Don't forget your assets ! :wink: 87 | 88 | It is consider a very bad practice to let browser load not optimized image. 89 | You could include image optimization 90 | 91 | ```js{6,55} 92 | const path = require("path"); 93 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 94 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 95 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 96 | const CompressionPlugin = require("compression-webpack-plugin"); 97 | const ImageminPlugin = require("imagemin-webpack-plugin").default; 98 | 99 | module.exports = { 100 | mode: "production", 101 | entry: "./src/main.js", // The source module of our dependency graph 102 | devServer: { 103 | contentBase: "./dist" 104 | }, 105 | output: { 106 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 107 | filename: "[name].bundle.[hash].js", 108 | path: path.resolve(__dirname, "dist") 109 | }, 110 | module: { 111 | rules: [ 112 | { 113 | test: /\.js$/, 114 | exclude: /node_modules/, 115 | loader: "babel-loader" 116 | }, 117 | { 118 | test: /\.jpg$/, 119 | use: [ 120 | { 121 | loader: "file-loader", 122 | options: { 123 | outputPath: "assets", 124 | publicPath: "assets" 125 | } 126 | } 127 | ] 128 | }, 129 | { 130 | test: /\.(sass|css)$/, 131 | use: ["style-loader", "css-loader", "sass-loader"] 132 | }, 133 | { 134 | test: /\.vue$/, 135 | use: "vue-loader" 136 | } 137 | ] 138 | }, 139 | plugins: [ 140 | new VueLoaderPlugin(), 141 | new CleanWebpackPlugin("dist"), 142 | new HtmlWebpackPlugin({ 143 | template: "./src/index.html" 144 | }), 145 | new CompressionPlugin(), 146 | new ImageminPlugin() 147 | ] 148 | }; 149 | ``` 150 | 151 | 152 | -------------------------------------------------------------------------------- /docs/fr/workshops/novice/outputs.md: -------------------------------------------------------------------------------- 1 | # Jouons avec les outputs 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/novice/outputs`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Ajoutons une entry 7 | 8 | Maintenant, nous allons forcer la création d'une `output` en ajoutant une autre `entry`. 9 | C'est l'arborescence des dépendances actuelles de cette petite application. 10 | 11 | ``` 12 | title.js 13 | <- color.js 14 | <- node_modules/lodash 15 | <- main.css 16 | <- landscape.jpg 17 | ``` 18 | 19 | Essayez d'ajouter le fichier `color.js` comme entrée. 20 | 21 | [Doc sur la gestion des entrypoints de webpack](https://webpack.js.org/concepts/entry-points/) 22 | 23 | Puis regardez le dossier dist. 24 | 25 | ::: warning 26 | Vous aurez probablement une erreur lorsque vous essayerez d'ajouter une autre `entry`. 27 | ::: 28 | 29 |
30 | Solution 31 | 32 | ```js{4-10} 33 | const path = require("path"); 34 | 35 | module.exports = { 36 | entry: { 37 | main: "./src/title.js", 38 | color: "./src/color.js" 39 | }, // The source module of our dependency graph 40 | output: { 41 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 42 | filename: "[name].js", 43 | path: path.resolve(__dirname, "dist") 44 | }, 45 | module: { 46 | rules: [ 47 | { 48 | test: /\.jpg$/, 49 | use: [ 50 | { 51 | loader: "file-loader", 52 | options: { 53 | outputPath: "assets", 54 | publicPath: "dist/assets" 55 | } 56 | } 57 | ] 58 | }, 59 | { 60 | test: /\.css$/, 61 | use: ["style-loader", "css-loader"] 62 | } 63 | ] 64 | } 65 | }; 66 | ``` 67 | 68 |
69 | 70 | :::tip 71 | Lors qu'on ajoute des `entry` a une configuration webpack, celui-ci va construire plusieurs arbres de dépendances. 72 | Il faut cependant noter qu'il faut alors configurer un nom d'output dynamique. 73 | On peut parler ici de code splitting mais si vous observez le contenu des deux bundles vous verrez de la redondance. 74 | ::: 75 | 76 | ## Générer votre fichier index.html 77 | 78 | Actuellement, si vous regardez votre fichier `index.html`, le chargement du fichier `main.js` est géré manuellement. 79 | Si votre bundle change de nom, vous risquez de devoir aller changer votre fichier html. 80 | 81 | Essayons d'automatiser cela grâce à [HtmlWebpackPlugin](https://webpack.js.org/plugins/html-webpack-plugin/). 82 | 83 |
84 | Solution 85 | 86 | ```js{2,34-38} 87 | const path = require("path"); 88 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 89 | 90 | module.exports = { 91 | entry: { 92 | main: "./src/title.js", 93 | color: "./src/color.js" 94 | }, // The source module of our dependency graph 95 | output: { 96 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 97 | filename: "[name].js", 98 | path: path.resolve(__dirname, "dist") 99 | }, 100 | module: { 101 | rules: [ 102 | { 103 | test: /\.jpg$/, 104 | use: [ 105 | { 106 | loader: "file-loader", 107 | options: { 108 | outputPath: "assets", 109 | publicPath: "dist/assets" 110 | } 111 | } 112 | ] 113 | }, 114 | { 115 | test: /\.css$/, 116 | use: ["style-loader", "css-loader"] 117 | } 118 | ] 119 | }, 120 | plugins: [ 121 | new HtmlWebpackPlugin({ 122 | template: "./index.html" 123 | }) 124 | ] 125 | }; 126 | ``` 127 | 128 |
129 | 130 | :::tip 131 | :bulb: Vous pouvez également tenter d'utiliser un template `handlebar` pour structurer votre page. 132 | ::: 133 | 134 | ## Nettoyer le dossier dist 135 | 136 | Comme vous l'avez peut-être remarqué au cours des guides et des exemples de code précédents, notre dossier `/dist` est devenu très encombré. 137 | webpack va générer les fichiers et les mettre dans le dossier `/dist` pour vous, mais il ne garde pas la trace des fichiers réellement utilisés par votre projet. 138 | 139 | En général, il est recommandé de nettoyer le dossier `/dist` avant chaque compilation, afin que seuls les fichiers utilisés soient générés. On va s'occuper de ça. 140 | 141 | Un plugin populaire pour y parvenir est le [clean-webpack-plugin](https://www.npmjs.com/package/clean-webpack-plugin), alors installons-le et configurons-le. 142 | 143 | :::tip 144 | Le plugin est déjà installé. 145 | ::: 146 | 147 |
148 | Solution 149 | 150 | ```js 151 | new CleanWebpackPlugin(), 152 | ``` 153 | 154 |
155 | -------------------------------------------------------------------------------- /docs/workshops/intermediate/reduce-bundle-size.md: -------------------------------------------------------------------------------- 1 | # Bundle size hunting :scissors: 2 | 3 | > To start this exercise, be sure to be in `./packages/intermediate/reduce-bundle-size` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Having a tool like webpack to generate code "bundles" is great to let it handle code dependencies. 9 | However it would be quite difficult to keep those generate bundle under a critic size. 10 | 11 | Main causes are: 12 | 13 | - Your app contains a huge quantity of code 14 | - You import huge dependencies 15 | - You are generating too few bundles. Your browser need to load and parse a huge file before rendering your all app. 16 | 17 | ## Example App 18 | 19 | This is a really simple pokedex app made with vuejs. 20 | In order to simplify build configuration, we won't use `vue-loader` here. 21 | The app have two pages : 22 | 23 | - home page displaying 20 pokemons 24 | - pokemon detail page with a specific image. 25 | 26 | You can start this application with: 27 | 28 | ```bash 29 | yarn start 30 | ``` 31 | 32 | ::: tip 33 | When you start your server, you will notice webpack warnings in the console. 34 | webpack is trying to tell you that your app bundle is too fat. 35 | 36 | Let's try to fix that ! :wink: 37 | ::: 38 | 39 | ## Analysing bundle size and content 40 | 41 | First thing, let's try to focus on what is in our bundle and you will see it is too fat. 42 | 43 | We will use [webpack Bundle Analyser](https://github.com/webpack-contrib/webpack-bundle-analyzer) 44 | 45 |
46 | Solution 47 | 48 | ```js 49 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") 50 | .BundleAnalyzerPlugin; 51 | 52 | module.exports = { 53 | plugins: [new BundleAnalyzerPlugin()] 54 | }; 55 | ``` 56 | 57 |
58 | 59 | You should normally see a lonely bundle containing: 60 | 61 | - all bulma code 62 | - all lodash lib 63 | - vue js 64 | - all your app code 65 | 66 | ## Tree shaking your code 67 | 68 | Let's try to cut tree by the big branches first: the dependencies. 69 | 70 | We are importing all bulma code, let's try to reduce bundle size by importing only whta is needed: 71 | 72 | - columns 73 | - headings 74 | - card 75 | 76 |
77 | Solution 78 | 79 | Create a file `app.sass` and only load bulma parts. 80 | 81 | ```sass 82 | @charset "utf-8" 83 | 84 | @import "~bulma/sass/utilities/_all.sass" 85 | @import "~bulma/sass/base/_all.sass" 86 | @import "~bulma/sass/components/card.sass" 87 | @import "~bulma/sass/elements/title.sass" 88 | @import "~bulma/sass/grid/columns.sass" 89 | ``` 90 | 91 |
92 | 93 | Let's try to load just one function of lodash instead of all the lib 94 | 95 |
96 | Solution 97 | 98 | ```js 99 | import _capitalize from "lodash/capitalize"; 100 | ``` 101 | 102 |
103 | 104 | ::: tip 105 | For lodash you could also use [babel plugin lodash](https://github.com/lodash/babel-plugin-lodash) if your are using babel in your app. 106 | ::: 107 | 108 | ## Code splitting 109 | 110 | Now the app is loading only the dependencies we need. 111 | Let's try to load only home page code on home page ! :smile: 112 | 113 | To do so we will need to generate two bundles: one for home, and one for details page. 114 | 115 | We could do that by adding another entry in webpack configuration **OR** we could use webpack dynamic imports. 116 | 117 | VueJS is ok by default with async component :tada: , let's try to import our page in router with dynamic import. 118 | 119 | It will generate 1 bundle for each page. 120 | 121 |
122 | Solution 123 | 124 | ```js 125 | import Vue from "vue"; 126 | import Router from "vue-router"; 127 | 128 | Vue.use(Router); 129 | 130 | export default new Router({ 131 | routes: [ 132 | { path: "/", component: () => import("./pages/home") }, 133 | { 134 | path: "/details/:id", 135 | component: () => import("./pages/details"), 136 | props: true 137 | } 138 | ] 139 | }); 140 | ``` 141 | 142 |
143 | 144 | ## Name your chunks ! 145 | 146 | Ok the two `chunk` contains your page code and that's great. 147 | You could try to load your app, the browser will only load the JS you need to display the page. 148 | 149 | Maybe we could name those chunk to help us understand what we just split. 150 | 151 | 1. Change the output filename config to `[name].bundle.js` 152 | 2. Add a comment in the dynamic import to name your chunk (`import(/* webpackChunkName: "home" */ "./pages/home")`) 153 | 154 | ## Prefetch your bundles ! 155 | 156 | You can also tell your browser, ok you don't need that bundle for now, but try to prefetch it if you have time, it is good for you. 157 | This could be done with another webpack comment, look at [related doc](https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules) 158 | -------------------------------------------------------------------------------- /docs/fr/workshops/intermediate/compression.md: -------------------------------------------------------------------------------- 1 | # La compression de fichier 🗜️ 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/intermediate/compression`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Pourquoi compresser vos fichiers ? 7 | 8 | La compression Gzip permet d'économiser en moyenne 30% du volume de transfert Internet. 9 | Vous pouvez laisser votre serveur web compresser votre paquet généré _à la volée_ à chaque demande mais pour les fichiers statiques, vous devriez vraiment essayer de le compresser dans la phase de la compilation. 10 | 11 | Tout serveur web décent peut servir des fichiers pré-compressés si le navigateur le demande. 12 | 13 | Bonne nouvelle, webpack a un plugin pour vous. :tada: 14 | 15 | ## Ajoutons la compression Gzip 16 | 17 | Regardez la configuration de [compression-webpack-plugin](https://webpack.js.org/plugins/compression-webpack-plugin) et ajoutez-la à l'application. 18 | 19 | :::tip 20 | Ce package permet également de compresser vos fichier avec Brolti, n'hésitez pas à essayer. 21 | ::: 22 | 23 |
24 | Solution 25 | 26 | ```js{5,53} 27 | const path = require("path"); 28 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 29 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 30 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 31 | const CompressionPlugin = require("compression-webpack-plugin"); 32 | 33 | module.exports = { 34 | mode: "production", 35 | entry: "./src/main.js", // The source module of our dependency graph 36 | devServer: { 37 | contentBase: "./dist" 38 | }, 39 | output: { 40 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 41 | filename: "[name].bundle.[hash].js", 42 | path: path.resolve(__dirname, "dist") 43 | }, 44 | module: { 45 | rules: [ 46 | { 47 | test: /\.js$/, 48 | exclude: /node_modules/, 49 | loader: "babel-loader" 50 | }, 51 | { 52 | test: /\.jpg$/, 53 | use: [ 54 | { 55 | loader: "file-loader", 56 | options: { 57 | outputPath: "assets", 58 | publicPath: "assets" 59 | } 60 | } 61 | ] 62 | }, 63 | { 64 | test: /\.(sass|css)$/, 65 | use: ["style-loader", "css-loader", "sass-loader"] 66 | }, 67 | { 68 | test: /\.vue$/, 69 | use: "vue-loader" 70 | } 71 | ] 72 | }, 73 | plugins: [ 74 | new VueLoaderPlugin(), 75 | new CleanWebpackPlugin("dist"), 76 | new HtmlWebpackPlugin({ 77 | template: "./src/index.html" 78 | }), 79 | new CompressionPlugin() 80 | ] 81 | }; 82 | ``` 83 | 84 |
85 | 86 | ::: tip 87 | Cet [article](https://medium.com/@selvaganesh93/how-to-serve-webpack-gzipped-file-in-production-usinging-nginx-692eadbb9f1c) explique comment utiliser vos fichiers compressés dans une configuration Nginx. 88 | ::: 89 | 90 | ## :wink: Les images aussi peuvent être compressées 91 | 92 | Il est considéré comme une très mauvaise pratique de laisser le navigateur charger une image non optimisée. 93 | Pour éviter cette situation, il est conseillé de compresser les images avec divers outils. 94 | 95 | Essayez de mettre en place [imagemin-webpack-plugin](https://www.npmjs.com/package/imagemin-webpack-plugin). 96 | 97 |
98 | Solution 99 | 100 | ```js{6,55} 101 | const path = require("path"); 102 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 103 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 104 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 105 | const CompressionPlugin = require("compression-webpack-plugin"); 106 | const ImageminPlugin = require("imagemin-webpack-plugin").default; 107 | 108 | module.exports = { 109 | mode: "production", 110 | entry: "./src/main.js", // The source module of our dependency graph 111 | devServer: { 112 | contentBase: "./dist" 113 | }, 114 | output: { 115 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 116 | filename: "[name].bundle.[hash].js", 117 | path: path.resolve(__dirname, "dist") 118 | }, 119 | module: { 120 | rules: [ 121 | { 122 | test: /\.js$/, 123 | exclude: /node_modules/, 124 | loader: "babel-loader" 125 | }, 126 | { 127 | test: /\.jpg$/, 128 | use: [ 129 | { 130 | loader: "file-loader", 131 | options: { 132 | outputPath: "assets", 133 | publicPath: "assets" 134 | } 135 | } 136 | ] 137 | }, 138 | { 139 | test: /\.(sass|css)$/, 140 | use: ["style-loader", "css-loader", "sass-loader"] 141 | }, 142 | { 143 | test: /\.vue$/, 144 | use: "vue-loader" 145 | } 146 | ] 147 | }, 148 | plugins: [ 149 | new VueLoaderPlugin(), 150 | new CleanWebpackPlugin("dist"), 151 | new HtmlWebpackPlugin({ 152 | template: "./src/index.html" 153 | }), 154 | new CompressionPlugin(), 155 | new ImageminPlugin() 156 | ] 157 | }; 158 | ``` 159 | 160 |
161 | -------------------------------------------------------------------------------- /docs/fr/workshops/intermediate/reduce-bundle-size.md: -------------------------------------------------------------------------------- 1 | # Découpons les bundles :scissors: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/intermediate/reduce-bundle-size`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Générer des gros bundle avec webpack va devenir un vrai problème, pour ces différents raisons : 9 | 10 | - Votre application contient une énorme quantité de code 11 | - Vous importez d'énormes dépendances 12 | - Vous générez trop peu de bundles. Votre navigateur doit charger et analyser un énorme fichier avant de rendre votre application. 13 | 14 | ## L'application à améliorer 15 | 16 | C'est une application de pokedex très simple faite avec vuejs. 17 | Afin de simplifier la configuration de build, nous n'utiliserons pas `vue-loader` ici. 18 | L'application possède deux pages : 19 | 20 | - une page d'accueil affichant 20 pokémons 21 | - une page de détail sur un pokémon avec une image spécifique. 22 | 23 | Vous pouvez démarrer cette application avec : 24 | 25 | ```bash 26 | yarn start 27 | ``` 28 | 29 | ::: tip 30 | Lorsque vous démarrez votre serveur, vous remarquerez des avertissements webpack dans la console. 31 | webpack essaie de vous dire que votre pack d'applications est trop gros. 32 | 33 | Essayons d'arranger ça ! :wink: 34 | ::: 35 | 36 | ## Analyser la taille et le contenu des bundles 37 | 38 | Tout d'abord, essayons de nous concentrer sur ce qu'il y a dans notre paquet et vous verrez qu'il y a bien trop de choses. 39 | 40 | Essayer de mettre en place [webpack Bundle Analyser](https://github.com/webpack-contrib/webpack-bundle-analyzer) 41 | 42 |
43 | Solution 44 | 45 | ```js 46 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") 47 | .BundleAnalyzerPlugin; 48 | 49 | module.exports = { 50 | plugins: [new BundleAnalyzerPlugin()] 51 | }; 52 | ``` 53 | 54 |
55 | 56 | Normalement, vous devriez voir un unique bundle qui contient : 57 | 58 | - tout le code de bulma 59 | - toute la librairie lodash 60 | - vue js 61 | - tout le code de votre application 62 | 63 | :::tip Autre conseil 64 | Vous pouvez également générer un fichier `stats.json` associé à votre build afin de l'analyser. 65 | 66 | En passant l'option `generateStatsFile: true` au _BundleAnalyzerPlugin_, vous pourrez ainsi utiliser des autres outils comme [https://webpack.github.io/](https://webpack.github.io/) pour analyser votre build. 67 | ::: 68 | 69 | ## le "Tree shaking" 70 | 71 | Essayons d'abord de couper les branches de l'arbre des dépendances. 72 | 73 | Nous importons tout le code bulma, essayons de réduire la taille des bundles en important seulement ce qui est nécessaire : 74 | 75 | - columns 76 | - heading 77 | - card 78 | 79 | Créez un fichier `app.sass` et ne chargez que des pièces bulma et remplacez l'importation bulma par cette importation de fichier. 80 | 81 | ```sass 82 | @charset "utf-8" 83 | 84 | @import "~bulma/sass/utilities/_all.sass" 85 | @import "~bulma/sass/base/_all.sass" 86 | @import "~bulma/sass/components/card.sass" 87 | @import "~bulma/sass/elements/title.sass" 88 | @import "~bulma/sass/grid/columns.sass" 89 | ``` 90 | 91 | Essayons de ne charger qu'une seule fonction de lodash au lieu de toute la librairie 92 | 93 | ```js 94 | import _capitalize from "lodash/capitalize"; 95 | ``` 96 | 97 | ::: tip 98 | Pour lodash vous pouvez aussi utiliser [babel plugin lodash](https://github.com/lodash/babel-plugin-lodash) si vous utilisez babel dans votre application. 99 | ::: 100 | 101 | ## Découper le code de son application: Code splitting 102 | 103 | Maintenant l'application ne charge que les dépendances dont nous avons besoin. 104 | Essayons de ne charger que le code de la page d'accueil sur la page d'accueil ! :smile: 105 | Pour ce faire, nous aurons besoin de générer deux bundle : une pour la _homepage_, et une pour la page de détails. 106 | 107 | Nous pourrions le faire en ajoutant une autre entrée dans la configuration de webpack **OU** nous pourrions utiliser les import dynamiques de webpack. 108 | 109 | VueJS fonctionne par défaut avec le composant asynchrone :tada: 110 | 111 | ```js 112 | import Vue from "vue"; 113 | import Router from "vue-router"; 114 | 115 | Vue.use(Router); 116 | 117 | export default new Router({ 118 | routes: [ 119 | { path: "/", component: () => import("./pages/home") }, 120 | { 121 | path: "/details/:id", 122 | component: () => import("./pages/details"), 123 | props: true 124 | } 125 | ] 126 | }); 127 | ``` 128 | 129 | ## Nommer vos "chunk" ! 130 | 131 | Ok les deux `chunk` contiennent votre code de page et c'est génial. 132 | Vous pouvez essayer de charger votre application, le navigateur ne chargera que les JS dont vous avez besoin pour afficher la page. 133 | 134 | On pourrait peut-être nommer ces chunks pour nous aider à comprendre ce qu'on vient de découper. 135 | 136 | 1. Changez le nom du fichier de sortie config en `[name].bundle.js`. 137 | 2. Ajoutez un commentaire dans l'import dynamique pour nommer votre morceau (`import(/* webpackChunkName : "home" */ "./pages/home")`) 138 | 139 | ## Préchargez vos bundles ! 140 | 141 | Vous pouvez aussi dire à votre navigateur, **ok vous n'avez pas besoin de ce pack pour l'instant, mais essayez de le pré-rechercher si vous avez le temps, c'est bon pour vous.** 142 | Ceci pourrait être fait avec un autre commentaire sur le webpack, regardez [doc associée](https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules). 143 | -------------------------------------------------------------------------------- /docs/fr/workshops/novice/static-assets.md: -------------------------------------------------------------------------------- 1 | # Les fichiers statiques 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/novice/static-assets`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Maintenant que nous savons comment utiliser la puissance des modules _CommonJS_ dans le navigateur grâce au processus de résolution webpack, 9 | nous voulons pouvoir utiliser d'autres types de fichiers dont une application web a besoin. 10 | 11 | Commençons simplement par un fichier statique comme une image. 12 | 13 | example of asset 14 | 15 | Cette fois, nous allons essayer d'ajouter une image après le titre. 16 | 17 | ``` 18 | title.js 19 | <- color.js 20 | <- node_modules/lodash 21 | <- landscape.jpg 22 | ``` 23 | 24 | Title va avoir color.js et landscape.jpg en dépendance. 25 | 26 | ## Essayons de l'importer ! 27 | 28 | Essayons de charger notre image comme s'il s'agissait d'un module JS et d'exécuter la commande `yarn build`. 29 | 30 | ```js{2} 31 | const { getRandomColor } = require("./color.js"); 32 | const image = require("../assets/landscape.jpg"); 33 | 34 | let changeCount = 0; 35 | 36 | const el = document.querySelector("h1"); 37 | 38 | setInterval(() => { 39 | changeCount++; 40 | el.innerHTML = `This title will change ! ${changeCount}`; 41 | el.style.color = getRandomColor(); 42 | }, 1000); 43 | ``` 44 | 45 | Vous verrez normalement un message d'erreur assez court dans votre console. 46 | 47 | ```log 48 | ERROR in ./assets/landscape.jpg 1:0 49 | Module parse failed: Unexpected character '�' (1:0) 50 | You may need an appropriate loader to handle this file type. 51 | (Source code omitted for this binary file) 52 | @ ./src/title.js 2:14-48 53 | ``` 54 | 55 | Cela signifie simplement que le webpack n'a pas réussi à charger votre fichier image. 56 | Par défaut, webpack ne peut gérer que les fichiers du module JS. 57 | Si vous voulez charger un autre type de fichier, vous avez absolument besoin d'un webpack **Loader**. 58 | 59 | Le **Loader** est une brique optionnelle de webpack qui permet de gérer d'autres format de fichier comme des fichiers JPG. 60 | 61 | Si vous regardez le fichier `package.json`, vous trouverez une nouvelle dépendance :`file-loader`. 62 | Ce Loader a été créé pour ce genre de besoin. 63 | 64 | ## Mettre en place le Loader 65 | 66 | Dans l'exemple [basic](./basics.md) nous avons vu deux objets de configuration webpack : 67 | 68 | - entry 69 | - output 70 | 71 | Maintenant nous avons besoin du `module` pour configurer d'autres types de règles de résolution/compilation de modules. 72 | 73 | Essayons d'ajouter une règle pour les fichiers `.jpg`. 74 | 75 | ```js{9-18} 76 | const path = require("path"); 77 | 78 | module.exports = { 79 | entry: "./src/title.js", 80 | output: { 81 | filename: "main.js", 82 | path: path.resolve(__dirname, "dist") 83 | }, 84 | module: { 85 | rules: [ 86 | // Here we can define/override module loading rules 87 | { 88 | test: /\.jpg$/, 89 | use: ["file-loader"] 90 | } 91 | ] 92 | } 93 | }; 94 | ``` 95 | 96 | ## Essayons d'utiliser notre image chargée 97 | 98 | webpack semble maintenant avoir le pouvoir de charger un fichier `.jpg`. Regardons ce qu'il met dans l'image "constante" que nous avons créée ci-dessus. 99 | 100 | Normalement, vous verrez un `.jpg` dans votre console. Ce message correspond au fichier webpack créé dans le dossier `dist`. 101 | 102 | ```js{10-13} 103 | const { getRandomColor } = require("./color.js"); 104 | const image = require("../assets/landscape.jpg"); 105 | 106 | console.log(image); 107 | 108 | let changeCount = 0; 109 | 110 | const el = document.querySelector("h1"); 111 | 112 | const img = document.createElement("img"); 113 | img.src = image; 114 | 115 | el.parentNode.insertBefore(img, el.nextSibling); 116 | 117 | setInterval(() => { 118 | changeCount++; 119 | el.innerHTML = `This title will change ! ${changeCount}`; 120 | el.style.color = getRandomColor(); 121 | }, 1000); 122 | ``` 123 | 124 | `yarn build` et ouvrez votre application, vous verrez normalement que votre image est cassée. 125 | 126 | Votre navigateur ne regarde pas dans le bon répertoire, le chemin vers le fichier de l'image n'est pas le bon. 127 | 128 | ### Changer le chemin 129 | 130 | Nous avons dit à webpack que le chemin de sortie est le dossier `dist`. C'est exactement là qu'il crée l'image chargée. 131 | 132 | Essayons de configurer deux choses : 133 | 134 | - faire que webpack crée un dossier `assets` pour ce type de fichiers (_outputPath_) 135 | - rendre le chemin généré à partir du module chargé correct pour le navigateur (_publicPath_) 136 | 137 | ```js{13-22} 138 | const path = require("path"); 139 | 140 | module.exports = { 141 | entry: "./src/title.js", // The source module of our dependency graph 142 | output: { 143 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 144 | filename: "main.js", 145 | path: path.resolve(__dirname, "dist") 146 | }, 147 | module: { 148 | rules: [ 149 | { 150 | test: /\.jpg$/, 151 | use: [ 152 | { 153 | loader: "file-loader", 154 | options: { 155 | outputPath: "assets", 156 | publicPath: "dist/assets" 157 | } 158 | } 159 | ] 160 | } 161 | ] 162 | } 163 | }; 164 | ``` 165 | 166 | ::: tip 167 | Maintenant, votre image devrait s'afficher sans erreur ! 👏👏👏 168 | ::: 169 | -------------------------------------------------------------------------------- /docs/workshops/novice/static-assets.md: -------------------------------------------------------------------------------- 1 | # Handling static assets 2 | 3 | > To start this exercise, be sure to be in `./packages/novice/static-assets` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Now that we know how to use _CommonJS_ modules power in the browser thanks to webpack resolution process, 9 | we clearly want to be able to use other files types that a webapp needs. 10 | 11 | Let's start simply with a static file like an image 12 | 13 | example of asset 14 | 15 | We will start with the same app that is the [basic example](./basics.md). 16 | But this time we will try to add a picture after the title. 17 | 18 | ``` 19 | title.js 20 | <- color.js 21 | <- node_modules/lodash 22 | <- landscape.jpg 23 | ``` 24 | 25 | ## Import all the things ! 26 | 27 | Let's try to load our image like it was a JS module and try to run the `yarn build` command. 28 | 29 |
30 | Solution 31 | 32 | ```js{2} 33 | const { getRandomColor } = require("./color.js"); 34 | const image = require("../assets/landscape.jpg").default; 35 | 36 | let changeCount = 0; 37 | 38 | const el = document.querySelector("h1"); 39 | 40 | setInterval(() => { 41 | changeCount++; 42 | el.innerHTML = `This title will change ! ${changeCount}`; 43 | el.style.color = getRandomColor(); 44 | }, 1000); 45 | ``` 46 | 47 |
48 | 49 | You will normally see a pretty short error message in your console 50 | 51 | ```log 52 | ERROR in ./assets/landscape.jpg 1:0 53 | Module parse failed: Unexpected character '�' (1:0) 54 | You may need an appropriate loader to handle this file type. 55 | (Source code omitted for this binary file) 56 | @ ./src/title.js 2:14-48 57 | ``` 58 | 59 | It simply means that webpack failed to load your image file. 60 | By default, webpack could only handle JS module files. 61 | If you want to load another file type, you definitely need a webpack **Loader**. 62 | 63 | If you look at the `package.json` file, you will find a new dependency: `file-loader`. 64 | This loader have been created for those kinds of need. 65 | 66 | ## Setup file loader 67 | 68 | In [basic](./basics.md) example we saw two webpack configuration objects: 69 | 70 | - entry 71 | - output 72 | 73 | Now we need the `module` to configure other kind of modules resolving/compiling rules. 74 | Let's try to add a rule for `.jpg` files. 75 | 76 |
77 | Solution 78 | 79 | ```js{10-19} 80 | const path = require("path"); 81 | 82 | module.exports = { 83 | entry: "./src/title.js", // The source module of our dependency graph 84 | output: { 85 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 86 | filename: "main.js", 87 | path: path.resolve(__dirname, "dist") 88 | }, 89 | module: { 90 | rules: [ 91 | // Here we can define/override module loading rules 92 | { 93 | test: /\.jpg$/, 94 | use: ["file-loader"] 95 | } 96 | ] 97 | } 98 | }; 99 | ``` 100 | 101 |
102 | 103 | You can also check that if you add another `.jpg` image in the folder and don't use it in your module, webpack won't load it. 104 | 105 | ## Let's use our loaded image 106 | 107 | webpack seems to have now the power to load a `.jpg` file. Let's look at what it puts in the `const image` we created above. 108 | 109 | Normally you will see a `.jpg` in your console. This message matches the file webpack created in the `dist` folder. 110 | 111 | If you use this simple trick, you can try to use your generated image in your app 112 | 113 | ```js{10-13} 114 | const { getRandomColor } = require("./color.js"); 115 | const image = require("../assets/landscape.jpg").default; 116 | 117 | console.log(image); 118 | 119 | let changeCount = 0; 120 | 121 | const el = document.querySelector("h1"); 122 | 123 | const img = document.createElement("img"); 124 | img.src = image; 125 | 126 | el.parentNode.insertBefore(img, el.nextSibling); 127 | 128 | setInterval(() => { 129 | changeCount++; 130 | el.innerHTML = `This title will change ! ${changeCount}`; 131 | el.style.color = getRandomColor(); 132 | }, 1000); 133 | ``` 134 | 135 | Rebuild and open your app, you will normally see that your image is broken. 136 | Your browser in not looking in the good directory. 137 | 138 | ### Change the path 139 | 140 | We told webpack that the output path is the `dist` folder. That's exactly where it creates the loaded image. 141 | 142 | Let's try to configure two things: 143 | 144 | - make webpack create an `assets` folder for those kind of files (_outputPath_) 145 | - make the generated path from loaded module ok for the browser (_publicPath_) 146 | 147 |
148 | Solution 149 | 150 | ```js{13-22} 151 | const path = require("path"); 152 | 153 | module.exports = { 154 | entry: "./src/title.js", // The source module of our dependency graph 155 | output: { 156 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 157 | filename: "main.js", 158 | path: path.resolve(__dirname, "dist") 159 | }, 160 | module: { 161 | rules: [ 162 | { 163 | test: /\.jpg$/, 164 | use: [ 165 | { 166 | loader: "file-loader", 167 | options: { 168 | outputPath: "assets", 169 | publicPath: "dist/assets" 170 | } 171 | } 172 | ] 173 | } 174 | ] 175 | } 176 | }; 177 | ``` 178 | 179 |
180 | 181 | ::: tip 182 | Now your image should be displayed without errors!! 👏👏👏 183 | ::: 184 | -------------------------------------------------------------------------------- /docs/fr/workshops/intermediate/dev.md: -------------------------------------------------------------------------------- 1 | # Les astuces pour un environnement de dev :rocket: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/intermediate/dev`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Mettre en place un processus de _build_ avec webpack ne doit pas empêcher ou gêner le développement. 9 | 10 | Au contraire, webpack peut apporter des solutions pratiques pour vous aider. 11 | 12 | ## Les Source maps 13 | 14 | Le javascript généré par webpack n'est pas vraiment lisible humainement. 15 | Pour que vous puissez les lire dans les devtools de votre navigateur, il vous faut des [source maps](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map). 16 | 17 | Lancer l'application de cet exercice avec: 18 | 19 | ```bash 20 | yarn build 21 | ``` 22 | 23 | Essayez d'ouvrir le bundle dans les devtools de votre navigateur. Vous devriez avoir du mal à comprendre ce que fait ce javascript. 24 | 25 | Pour générer les source maps: 26 | 27 | - activez le [mode](https://webpack.js.org/configuration/mode) developpement 28 | - definissez la clé `devtool: 'inline-source-map'` 29 | 30 | :::tip 31 | Vous pouvez également changer le mode de webpack grâce à des `flags` webpack-cli. 32 | ::: 33 | 34 |
35 | Solution A 36 | 37 | ```js{5,6} 38 | const path = require("path"); 39 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 40 | 41 | module.exports = { 42 | mode: "development", 43 | devtool: "inline-source-map", 44 | entry: "./src/main.js", // The source module of our dependency graph 45 | output: { 46 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 47 | filename: "main.bundle.js", 48 | path: path.resolve(__dirname, "dist") 49 | }, 50 | module: { 51 | rules: [ 52 | { 53 | test: /\.jpg$/, 54 | use: [ 55 | { 56 | loader: "file-loader", 57 | options: { 58 | outputPath: "assets", 59 | publicPath: "dist/assets" 60 | } 61 | } 62 | ] 63 | }, 64 | { 65 | test: /\.css$/, 66 | use: ["style-loader", "css-loader"] 67 | } 68 | ] 69 | }, 70 | plugins: [ 71 | new HtmlWebpackPlugin({ 72 | template: "./src/index.html" 73 | }) 74 | ] 75 | }; 76 | ``` 77 | 78 |
79 | 80 |
81 | Solution B 82 | 83 | ```json{20} 84 | { 85 | "name": "@intermediate/dev", 86 | "version": "1.0.0", 87 | "license": "MIT", 88 | "private": true, 89 | "dependencies": { 90 | "bulma": "^0.7.2", 91 | "lodash": "^4.17.11" 92 | }, 93 | "devDependencies": { 94 | "webpack": "^4.28.4", 95 | "webpack-cli": "^3.2.1", 96 | "file-loader": "^3.0.1", 97 | "css-loader": "^2.1.0", 98 | "style-loader": "^0.23.1", 99 | "html-webpack-plugin": "^3.2.0", 100 | "clean-webpack-plugin": "^1.0.0" 101 | }, 102 | "scripts": { 103 | "build": "webpack --progress --mode development --devtool inline-source-map" 104 | } 105 | } 106 | ``` 107 | 108 |
109 | 110 | Sur Chrome, ouvrez votre panneau devtools nommé _Source_, essayez d'ouvrir le fichier `pokemon.service.js`. 111 | Vous devriez pouvoir lire le même fichier que vous avez écrit. :tada: 112 | Vous pouvez maintenant mettre des **breakpoints** dans le navigateur pour vous aider à déboguer votre code. 113 | 114 | ## Le mode watch 115 | 116 | _Est-il possible de ne pas avoir a relancer un build à chaque fois que j'apporte une modification ?_ 117 | 118 | La solution la plus simple est d'activer la fonction [`watch`](https://webpack.js.org/configuration/watch/) de webpack. 119 | 120 | Essayez de le faire :muscle: 121 | 122 |
123 | Solution 124 | 125 | ```json{20} 126 | { 127 | "name": "@intermediate/dev", 128 | "version": "1.0.0", 129 | "license": "MIT", 130 | "private": true, 131 | "dependencies": { 132 | "bulma": "^0.7.2", 133 | "lodash": "^4.17.11" 134 | }, 135 | "devDependencies": { 136 | "webpack": "^4.28.4", 137 | "webpack-cli": "^3.2.1", 138 | "file-loader": "^3.0.1", 139 | "css-loader": "^2.1.0", 140 | "style-loader": "^0.23.1", 141 | "html-webpack-plugin": "^3.2.0", 142 | "clean-webpack-plugin": "^1.0.0" 143 | }, 144 | "scripts": { 145 | "build": "webpack --progress --mode development --devtool inline-source-map --watch" 146 | } 147 | } 148 | ``` 149 | 150 |
151 | 152 | ## Le serveur de développement 153 | 154 | _Est-il possible de démarrer un server web à partir de ce qui est généré par webpack ?_ 155 | 156 | La solution est `webpack-dev-server`, c'est un package qui peut démarrer un serveur web basé sur une configuration webpack. 157 | 158 | - Ajoutez un script `npm` nommé `start` qui utilise `webpack-dev-server` sur votre configuration webpack 159 | - Ajoutez une clé `devServer` dans votre configuration pour remplacer la clé `contentBase` pour cibler votre répertoire de sortie. 160 | 161 | Vous trouverez la doc de [webpack-dev-server ici](https://webpack.js.org/configuration/dev-server/) 162 | 163 |
164 | Solution 165 | 166 | ```js{5-7} 167 | const path = require("path"); 168 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 169 | 170 | module.exports = { 171 | devServer: { 172 | contentBase: "./dist" 173 | }, 174 | entry: "./src/main.js", // The source module of our dependency graph 175 | output: { 176 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 177 | filename: "main.bundle.js", 178 | path: path.resolve(__dirname, "dist") 179 | }, 180 | module: { 181 | rules: [ 182 | { 183 | test: /\.jpg$/, 184 | use: [ 185 | { 186 | loader: "file-loader", 187 | options: { 188 | outputPath: "assets", 189 | publicPath: "dist/assets" 190 | } 191 | } 192 | ] 193 | }, 194 | { 195 | test: /\.css$/, 196 | use: ["style-loader", "css-loader"] 197 | } 198 | ] 199 | }, 200 | plugins: [ 201 | new HtmlWebpackPlugin({ 202 | template: "./src/index.html" 203 | }) 204 | ] 205 | }; 206 | ``` 207 | 208 |
209 | -------------------------------------------------------------------------------- /docs/workshops/intermediate/dev.md: -------------------------------------------------------------------------------- 1 | # Development Tricks :rocket: 2 | 3 | > To start this exercise, be sure to be in `./packages/intermediate/dev` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | When you want to develop a web application, you need to change your code often. 9 | That's why you don't want to lose time doing repetitive actions to see the result in your browser. 10 | 11 | ``` 12 | You change your code => you build your code with webpack => your reload your browser 13 | ``` 14 | 15 | webpack introduce also the concept of `bundle`. 16 | That means the code your browser runs is not exactly the same than the code you write. 17 | All dependencies have been resolved and merged together. 18 | 19 | For this two painful new problems, webpack offers solutions. 20 | 21 | ## Source maps 22 | 23 | When your generated JS code is not humanly readable because it has been minified or bundled you need [source maps](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map). 24 | In this exercise, the app is displaying pokemons. 25 | 26 | Run: 27 | 28 | ```bash 29 | yarn build 30 | ``` 31 | 32 | Try to open the generated bundle in the browser devtools, this should be very complex JS module. 33 | 34 | To generate your source maps: 35 | 36 | - toggle development [mode](https://webpack.js.org/concepts/#mode) of your build 37 | - define devtools to `inline-source-map` 38 | 39 | :::tip 40 | You can change your webpack configuration or `webpack-cli` flags. 41 | ::: 42 | 43 |
44 | Solution A 45 | 46 | ```js{5,6} 47 | const path = require("path"); 48 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 49 | 50 | module.exports = { 51 | mode: "development", 52 | devtool: "inline-source-map", 53 | entry: "./src/main.js", // The source module of our dependency graph 54 | output: { 55 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 56 | filename: "main.bundle.js", 57 | path: path.resolve(__dirname, "dist") 58 | }, 59 | module: { 60 | rules: [ 61 | { 62 | test: /\.jpg$/, 63 | use: [ 64 | { 65 | loader: "file-loader", 66 | options: { 67 | outputPath: "assets", 68 | publicPath: "dist/assets" 69 | } 70 | } 71 | ] 72 | }, 73 | { 74 | test: /\.css$/, 75 | use: ["style-loader", "css-loader"] 76 | } 77 | ] 78 | }, 79 | plugins: [ 80 | new HtmlWebpackPlugin({ 81 | template: "./src/index.html" 82 | }) 83 | ] 84 | }; 85 | ``` 86 | 87 |
88 | 89 |
90 | Solution B 91 | 92 | ```json{20} 93 | { 94 | "name": "@intermediate/dev", 95 | "version": "1.0.0", 96 | "license": "MIT", 97 | "private": true, 98 | "dependencies": { 99 | "bulma": "^0.7.2", 100 | "lodash": "^4.17.11" 101 | }, 102 | "devDependencies": { 103 | "webpack": "^4.28.4", 104 | "webpack-cli": "^3.2.1", 105 | "file-loader": "^3.0.1", 106 | "css-loader": "^2.1.0", 107 | "style-loader": "^0.23.1", 108 | "html-webpack-plugin": "^3.2.0", 109 | "clean-webpack-plugin": "^1.0.0" 110 | }, 111 | "scripts": { 112 | "build": "webpack --progress --mode development --devtool inline-source-map" 113 | } 114 | } 115 | ``` 116 | 117 |
118 | 119 | On Chrome, open your devtools panel named _Source_, try to open file `pokemon.service.js`. 120 | You should be able to read the same file you wrote. :tada: 121 | You can now put **breakpoints** in the browser to help you debug your code. 122 | 123 | ## Watch mode 124 | 125 | > "Could you please explain me how to auto rebuild my application when I do a modification ?" - You 126 | 127 | The most _naive_ approach to auto trigger build your app on code change could be done with the [`watch` mode of webpack](https://webpack.js.org/configuration/watch/). 128 | 129 |
130 | Solution 131 | 132 | ```json{20} 133 | { 134 | "name": "@intermediate/dev", 135 | "version": "1.0.0", 136 | "license": "MIT", 137 | "private": true, 138 | "dependencies": { 139 | "bulma": "^0.7.2", 140 | "lodash": "^4.17.11" 141 | }, 142 | "devDependencies": { 143 | "webpack": "^4.28.4", 144 | "webpack-cli": "^3.2.1", 145 | "file-loader": "^3.0.1", 146 | "css-loader": "^2.1.0", 147 | "style-loader": "^0.23.1", 148 | "html-webpack-plugin": "^3.2.0", 149 | "clean-webpack-plugin": "^1.0.0" 150 | }, 151 | "scripts": { 152 | "build": "webpack --progress --mode development --devtool inline-source-map --watch" 153 | } 154 | } 155 | ``` 156 | 157 |
158 | 159 | ## webpack Dev. Server 160 | 161 | > "Is there a solution to start an http server to serve my generated file ?" - You 162 | 163 | The solution is `webpack-dev-server`, it's a community nodeJS package that can start a web server based on webpack configuration. 164 | 165 | - Add a `npm script` named `start` that uses `webpack-dev-server` on your webpack configuration 166 | - Add a `devServer` key in your configuration to override `contentBase` key to target your output directory. 167 | 168 |
169 | Solution 170 | 171 | ```js{5-7} 172 | const path = require("path"); 173 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 174 | 175 | module.exports = { 176 | devServer: { 177 | contentBase: "./dist" 178 | }, 179 | entry: "./src/main.js", // The source module of our dependency graph 180 | output: { 181 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 182 | filename: "main.bundle.js", 183 | path: path.resolve(__dirname, "dist") 184 | }, 185 | module: { 186 | rules: [ 187 | { 188 | test: /\.jpg$/, 189 | use: [ 190 | { 191 | loader: "file-loader", 192 | options: { 193 | outputPath: "assets", 194 | publicPath: "dist/assets" 195 | } 196 | } 197 | ] 198 | }, 199 | { 200 | test: /\.css$/, 201 | use: ["style-loader", "css-loader"] 202 | } 203 | ] 204 | }, 205 | plugins: [ 206 | new HtmlWebpackPlugin({ 207 | template: "./src/index.html" 208 | }) 209 | ] 210 | }; 211 | ``` 212 | 213 |
214 | -------------------------------------------------------------------------------- /docs/workshops/intermediate/style.md: -------------------------------------------------------------------------------- 1 | # Coding with style :nail_care: 2 | 3 | > To start this exercise, be sure to be in `./packages/intermediate/style` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | We often use a CSS preprocessor in our project to help us handle CSS mixins, dependencies, palette, generating classes. 9 | By chance those preprocessor have a their own specific loader to help webpack build their dependencies tree. 10 | In this workshop, we will setup `sass` loader to help use reduce the quantity of CSS generated by webpack. 11 | 12 | ::: tip 13 | We are using [Bulma](https://bulma.io/) css library here. 14 | ::: 15 | 16 | ## Sass loader to take only the CSS we need from Bulma 17 | 18 | Try to load the scss file of Bulma first and edit your configuration to include the sass loader. 19 | The needed file is `bulma/bulma.sass`. 20 | 21 |
22 | Solution 23 | 24 | ```js{25-28} 25 | const path = require("path"); 26 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 27 | 28 | module.exports = { 29 | entry: "./src/main.js", // The source module of our dependency graph 30 | output: { 31 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 32 | filename: "main.bundle.js", 33 | path: path.resolve(__dirname, "dist") 34 | }, 35 | module: { 36 | rules: [ 37 | { 38 | test: /\.jpg$/, 39 | use: [ 40 | { 41 | loader: "file-loader", 42 | options: { 43 | outputPath: "assets", 44 | publicPath: "dist/assets" 45 | } 46 | } 47 | ] 48 | }, 49 | { 50 | test: /\.sass$/, 51 | use: ["style-loader", "css-loader", "sass-loader"] 52 | } 53 | ] 54 | }, 55 | plugins: [ 56 | new HtmlWebpackPlugin({ 57 | template: "./src/index.html" 58 | }) 59 | ] 60 | }; 61 | ``` 62 | 63 | ```js{1} 64 | import "bulma/bulma.sass"; 65 | import PokemonComponent from "./pokemon.component"; 66 | import { getPokemons } from "./pokemon.service"; 67 | 68 | const pokemonList = document.querySelector("#pokemons"); 69 | 70 | getPokemons().then(response => { 71 | response.results.map(({ name }, index) => { 72 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 73 | }); 74 | }); 75 | ``` 76 | 77 |
78 | 79 | ::: warning 80 | Did you see the `node-sass` dev dependency is mandatory for "sass-loader". You can see it in the `package.json`. 81 | ::: 82 | 83 | ## Extracting your CSS in specific bundles 84 | 85 | Having your CSS in your bundle is a quick win, but it may transform your bundle into huge files containing all your CSS stuff you don't need to have to render your website. 86 | You will probably want to split your style out of the JS bundle and extract it in `css` bundles. 87 | 88 | Try to configure [Mini CSS Extract Plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) 89 | 90 |
91 | Solution 92 | 93 | ```js{3}{37-40} 94 | const path = require("path"); 95 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 96 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 97 | 98 | module.exports = { 99 | entry: "./src/main.js", // The source module of our dependency graph 100 | output: { 101 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 102 | filename: "main.bundle.js", 103 | path: path.resolve(__dirname, "dist") 104 | }, 105 | module: { 106 | rules: [ 107 | { 108 | test: /\.jpg$/, 109 | use: [ 110 | { 111 | loader: "file-loader", 112 | options: { 113 | outputPath: "assets", 114 | publicPath: "dist/assets" 115 | } 116 | } 117 | ] 118 | }, 119 | { 120 | test: /\.sass$/, 121 | use: [ 122 | { loader: MiniCssExtractPlugin.loader }, 123 | "css-loader", 124 | "sass-loader" 125 | ] 126 | } 127 | ] 128 | }, 129 | plugins: [ 130 | new MiniCssExtractPlugin({ 131 | filename: "[name].css", 132 | chunkFilename: "[id].css" 133 | }), 134 | new HtmlWebpackPlugin({ 135 | template: "./src/index.html" 136 | }) 137 | ] 138 | }; 139 | ``` 140 | 141 |
142 | 143 | ## Use a CSS post processor 144 | 145 | If you want to target many browsers with your CSS, you will need a post processor. Most commonly used is `PostCSS`. 146 | Try to change the configuration to use postCSS loader in your app to generate a cross browser compatible CSS. 147 | 148 | [PostCSS Loader](https://github.com/postcss/postcss-loader) is already installed. :wink: 149 | You will need to configure only the [autoprefixer plugin](https://www.npmjs.com/package/autoprefixer). 150 | 151 |
152 | Solution 153 | 154 | ```js{30-40} 155 | const path = require("path"); 156 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 157 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 158 | const autoprefixer = require("autoprefixer"); 159 | 160 | module.exports = { 161 | entry: "./src/main.js", // The source module of our dependency graph 162 | output: { 163 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 164 | filename: "main.bundle.js", 165 | path: path.resolve(__dirname, "dist") 166 | }, 167 | module: { 168 | rules: [ 169 | { 170 | test: /\.jpg$/, 171 | use: [ 172 | { 173 | loader: "file-loader", 174 | options: { 175 | outputPath: "assets", 176 | publicPath: "dist/assets" 177 | } 178 | } 179 | ] 180 | }, 181 | { 182 | test: /\.sass$/, 183 | use: [ 184 | { loader: MiniCssExtractPlugin.loader }, 185 | "css-loader", 186 | { 187 | loader: "postcss-loader", 188 | options: { 189 | plugins: [ 190 | autoprefixer({ 191 | browsers: ["IE >= 10", "last 2 versions", "chrome >= 28"] 192 | }) 193 | ] 194 | } 195 | }, 196 | "sass-loader" 197 | ] 198 | } 199 | ] 200 | }, 201 | plugins: [ 202 | new MiniCssExtractPlugin({ 203 | filename: "[name].css", 204 | chunkFilename: "[id].css" 205 | }), 206 | new HtmlWebpackPlugin({ 207 | template: "./src/index.html" 208 | }) 209 | ] 210 | }; 211 | ``` 212 | 213 |
214 | -------------------------------------------------------------------------------- /docs/fr/workshops/intermediate/style.md: -------------------------------------------------------------------------------- 1 | # Avoir du style :nail_care: 2 | 3 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/intermediate/style`. 4 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Nous utilisons souvent un préprocesseur CSS dans notre projet pour nous aider à gérer les mixins CSS, les dépendances, la palette, la génération de classes. 9 | Par chance, ces préprocesseurs ont leur propre loader spécifique pour aider webpack à construire leur arbre de dépendances. 10 | Dans cet atelier, nous allons installer le chargeur `sass` pour aider à réduire la quantité de CSS générée par webpack. 11 | 12 | ::: tip 13 | Nous utilisons la bibliothèque css [Bulma](https://bulma.io/) ici. 14 | ::: 15 | 16 | ## `sass-loader` charger Bulma 17 | 18 | Essayez de charger d'abord le fichier scss de Bulma et modifiez votre configuration pour inclure le chargeur sass. 19 | Le fichier nécessaire est `bulma/bulma.sass`. 20 | 21 | La [documentation de sass-loader](https://github.com/webpack-contrib/sass-loader) peut vous aider pour faire cela. 22 | 23 |
24 | Solution 25 | 26 | ```js{25-28} 27 | const path = require("path"); 28 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 29 | 30 | module.exports = { 31 | entry: "./src/main.js", // The source module of our dependency graph 32 | output: { 33 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 34 | filename: "main.bundle.js", 35 | path: path.resolve(__dirname, "dist") 36 | }, 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.jpg$/, 41 | use: [ 42 | { 43 | loader: "file-loader", 44 | options: { 45 | outputPath: "assets", 46 | publicPath: "dist/assets" 47 | } 48 | } 49 | ] 50 | }, 51 | { 52 | test: /\.sass$/, 53 | use: ["style-loader", "css-loader", "sass-loader"] 54 | } 55 | ] 56 | }, 57 | plugins: [ 58 | new HtmlWebpackPlugin({ 59 | template: "./src/index.html" 60 | }) 61 | ] 62 | }; 63 | ``` 64 | 65 | ```js{1} 66 | import "bulma/bulma.sass"; 67 | import PokemonComponent from "./pokemon.component"; 68 | import { getPokemons } from "./pokemon.service"; 69 | 70 | const pokemonList = document.querySelector("#pokemons"); 71 | 72 | getPokemons().then(response => { 73 | response.results.map(({ name }, index) => { 74 | pokemonList.appendChild(PokemonComponent(name, index + 1)); 75 | }); 76 | }); 77 | ``` 78 | 79 |
80 | 81 | ::: warning 82 | Avez-vous vu que la dépendance `node-sass` dev est obligatoire pour "sass-loader". Vous pouvez le voir dans le `package.json`. 83 | ::: 84 | 85 | ## Extraire le CSS dans des fichiers à part 86 | 87 | Avoir votre CSS dans votre paquet est un gain rapide, mais il peut transformer votre bundle en fichiers énormes contenant tous vos fichiers CSS dont vous n'avez pas besoin pour faire le rendu de votre site. 88 | Vous voudrez probablement séparer votre CSS du paquet JS et l'extraire en bundles `css`. 89 | 90 | Essayer de configurer le [Mini CSS Extract Plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) 91 | 92 |
93 | Solution 94 | 95 | ```js{37-40} 96 | const path = require("path"); 97 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 98 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 99 | 100 | module.exports = { 101 | entry: "./src/main.js", // The source module of our dependency graph 102 | output: { 103 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 104 | filename: "main.bundle.js", 105 | path: path.resolve(__dirname, "dist") 106 | }, 107 | module: { 108 | rules: [ 109 | { 110 | test: /\.jpg$/, 111 | use: [ 112 | { 113 | loader: "file-loader", 114 | options: { 115 | outputPath: "assets", 116 | publicPath: "dist/assets" 117 | } 118 | } 119 | ] 120 | }, 121 | { 122 | test: /\.sass$/, 123 | use: [ 124 | { loader: MiniCssExtractPlugin.loader }, 125 | "css-loader", 126 | "sass-loader" 127 | ] 128 | } 129 | ] 130 | }, 131 | plugins: [ 132 | new MiniCssExtractPlugin({ 133 | filename: "[name].css", 134 | chunkFilename: "[id].css" 135 | }), 136 | new HtmlWebpackPlugin({ 137 | template: "./src/index.html" 138 | }) 139 | ] 140 | }; 141 | ``` 142 | 143 |
144 | 145 | :::tip 146 | :bulb: La clé `use` d'une `rule` de webpack indique l'ordre d'application des loaders. 147 | Ici, les loaders relatifs au CSS s'appliquent dans cet order `sass-loader`, `css-loader` puis `MiniCssExtractPlugin.loader`. 148 | ::: 149 | 150 | ## Utiliser un postprocesseur CSS 151 | 152 | Si vous voulez cibler plusieurs navigateurs avec votre CSS, vous aurez besoin d'un post-processeur. Le plus communément utilisé est `PostCSS`. 153 | Essayez de changer la configuration pour utiliser postCSS loader dans votre application afin de générer un CSS compatible avec tous les navigateurs. 154 | 155 | [PostCSS Loader](https://github.com/postcss/postcss-loader) est déjà installé. :wink: 156 | Vous aurez besoin de configurer que le [plugin autoprefixer](https://www.npmjs.com/package/autoprefixer). 157 | 158 |
159 | Solution 160 | 161 | ```js{30-40} 162 | const path = require("path"); 163 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 164 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 165 | const autoprefixer = require("autoprefixer"); 166 | 167 | module.exports = { 168 | entry: "./src/main.js", // The source module of our dependency graph 169 | output: { 170 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 171 | filename: "main.bundle.js", 172 | path: path.resolve(__dirname, "dist") 173 | }, 174 | module: { 175 | rules: [ 176 | { 177 | test: /\.jpg$/, 178 | use: [ 179 | { 180 | loader: "file-loader", 181 | options: { 182 | outputPath: "assets", 183 | publicPath: "dist/assets" 184 | } 185 | } 186 | ] 187 | }, 188 | { 189 | test: /\.sass$/, 190 | use: [ 191 | { loader: MiniCssExtractPlugin.loader }, 192 | "css-loader", 193 | { 194 | loader: "postcss-loader", 195 | options: { 196 | plugins: [ 197 | autoprefixer({ 198 | browsers: ["IE >= 10", "last 2 versions", "chrome >= 28"] 199 | }) 200 | ] 201 | } 202 | }, 203 | "sass-loader" 204 | ] 205 | } 206 | ] 207 | }, 208 | plugins: [ 209 | new MiniCssExtractPlugin({ 210 | filename: "[name].css", 211 | chunkFilename: "[id].css" 212 | }), 213 | new HtmlWebpackPlugin({ 214 | template: "./src/index.html" 215 | }) 216 | ] 217 | }; 218 | ``` 219 | 220 |
221 | -------------------------------------------------------------------------------- /docs/fr/workshops/advanced/loaders.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les loaders webpack 3 | meta: 4 | - name: description 5 | content: Comment et pourquoi créer un loader webpack ? Comment charger des formats de fichiers différents avec webpack ? Un exemple simple. 6 | --- 7 | 8 | # Chargeons de nouveaux formats :truck: 9 | 10 | > Pour démarrer cet exercice, sois sûr d'être dans le dossier `./packages/advanced/loaders`. 11 | > Sois également sûr d'avoir [installé ce dépôt d'abord](../README.md#install) 12 | 13 | ## Un peu de contexte 14 | 15 | Vous le savez sûrement, mais webpack ne sais gérer par défaut que des module JS (Esm, ou CJS). 16 | Si vous souhaitez charger d'autres formats de fichier, vous devez passer par ce qu'on appelle un loader. 17 | 18 | Il en existe déjà de nombreux, vous pouvez trouver une longue liste sur la page [Awesome de webpack](https://github.com/webpack-contrib/awesome-webpack#loaders). 19 | 20 | ## Quand créer un loader 21 | 22 | Il est rare de devoir definir un loader pour webpack, ceux de la communauté couvrent 99% des besoins _mais_ dans vos projets, il est possible que vous ayez à charger un format de fichier qui vous est privé. 23 | 24 | Essayons de créer un loader sur un cas simple :bulb: pour comprendre l'API. 25 | 26 | Imaginons un fichier qui contiennent des info sur un _Pokemon_ dont l'extension serait `.pokemon`. 27 | 28 | Ce fichier contiendrait comme contenu un JSON représentant le pokemon. 29 | 30 | ```json 31 | { 32 | "abilities": [ 33 | { 34 | "ability": { 35 | "name": "chlorophyll", 36 | "url": "https://pokeapi.co/api/v2/ability/34/" 37 | }, 38 | "is_hidden": true, 39 | "slot": 3 40 | }, 41 | { 42 | "ability": { 43 | "name": "overgrow", 44 | "url": "https://pokeapi.co/api/v2/ability/65/" 45 | }, 46 | "is_hidden": false, 47 | "slot": 1 48 | } 49 | ], 50 | "base_experience": 64, 51 | "forms": [ 52 | { "name": "bulbasaur", "url": "https://pokeapi.co/api/v2/pokemon-form/1/" } 53 | ], 54 | "height": 7, 55 | "held_items": [], 56 | "id": 1, 57 | "is_default": true, 58 | "location_area_encounters": "https://pokeapi.co/api/v2/pokemon/1/encounters", 59 | "name": "bulbasaur", 60 | "order": 1, 61 | "species": { 62 | "name": "bulbasaur", 63 | "url": "https://pokeapi.co/api/v2/pokemon-species/1/" 64 | }, 65 | "sprites": { 66 | "back_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/1.png", 67 | "back_female": null, 68 | "back_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/1.png", 69 | "back_shiny_female": null, 70 | "front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png", 71 | "front_female": null, 72 | "front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/1.png", 73 | "front_shiny_female": null 74 | }, 75 | "stats": [ 76 | { 77 | "base_stat": 45, 78 | "effort": 0, 79 | "stat": { "name": "speed", "url": "https://pokeapi.co/api/v2/stat/6/" } 80 | }, 81 | { 82 | "base_stat": 65, 83 | "effort": 0, 84 | "stat": { 85 | "name": "special-defense", 86 | "url": "https://pokeapi.co/api/v2/stat/5/" 87 | } 88 | }, 89 | { 90 | "base_stat": 65, 91 | "effort": 1, 92 | "stat": { 93 | "name": "special-attack", 94 | "url": "https://pokeapi.co/api/v2/stat/4/" 95 | } 96 | }, 97 | { 98 | "base_stat": 49, 99 | "effort": 0, 100 | "stat": { "name": "defense", "url": "https://pokeapi.co/api/v2/stat/3/" } 101 | }, 102 | { 103 | "base_stat": 49, 104 | "effort": 0, 105 | "stat": { "name": "attack", "url": "https://pokeapi.co/api/v2/stat/2/" } 106 | }, 107 | { 108 | "base_stat": 45, 109 | "effort": 0, 110 | "stat": { "name": "hp", "url": "https://pokeapi.co/api/v2/stat/1/" } 111 | } 112 | ], 113 | "types": [ 114 | { 115 | "slot": 2, 116 | "type": { "name": "poison", "url": "https://pokeapi.co/api/v2/type/4/" } 117 | }, 118 | { 119 | "slot": 1, 120 | "type": { "name": "grass", "url": "https://pokeapi.co/api/v2/type/12/" } 121 | } 122 | ], 123 | "weight": 69 124 | } 125 | ``` 126 | 127 | ## Importons un fichier pokemon avec webpack 128 | 129 | Dans l'application en place, essayer de faire `yarn build`. 130 | 131 | Vous devriez avoir l'erreur suivante: 132 | 133 | ``` 134 | ERROR in ./src/bulbasaur.pokemon 2:13 135 | Module parse failed: Unexpected token (2:13) 136 | You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders 137 | | { 138 | > "abilities": [ 139 | | { 140 | | "ability": { 141 | @ ./src/app.js 1:0-44 15:6-15 142 | @ ./src/main.js 143 | ``` 144 | 145 | Cette erreur indique que le format du fichier n'est pas reconnu par webpack. 146 | 147 | Essayons d'écrire le loader qui va permettre cela. 148 | 149 | Dans le fichier `pokemon.loader.js` définissons cette fonction: 150 | 151 | ```js 152 | module.exports = function getPokemon(source) { 153 | // Une fonction qui prend une string du fichier chargé 154 | return `export default ${JSON.stringify(source)}`; // On retourne un module CJS compréhensible par webpack. 155 | }; 156 | ``` 157 | 158 | Ce loader permet de charger n'importe quel pokemon qui respecte le format JSON. 159 | Il transforme le JSON en module CommonJS. 160 | 161 | Essayons de l'appliquer à notre application: 162 | 163 | ```js{29-36} 164 | const path = require("path"); 165 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 166 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 167 | 168 | module.exports = { 169 | entry: "./src/main.js", // The source module of our dependency graph 170 | devServer: { 171 | contentBase: "./dist" 172 | }, 173 | output: { 174 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 175 | filename: "main.bundle.js", 176 | path: path.resolve(__dirname, "dist") 177 | }, 178 | module: { 179 | rules: [ 180 | { 181 | test: /\.jpg$/, 182 | use: [ 183 | { 184 | loader: "file-loader", 185 | options: { 186 | outputPath: "assets", 187 | publicPath: "assets" 188 | } 189 | } 190 | ] 191 | }, 192 | { 193 | test: /\.(pokemon)$/, 194 | use: [ 195 | { 196 | loader: path.resolve(__dirname, "pokemon.loader.js") 197 | } 198 | ] 199 | }, 200 | { 201 | test: /\.(sass|css)$/, 202 | use: ["style-loader", "css-loader", "sass-loader"] 203 | } 204 | ] 205 | }, 206 | resolve: { 207 | alias: { 208 | vue: "vue/dist/vue.js" 209 | } 210 | }, 211 | plugins: [ 212 | new CleanWebpackPlugin("dist"), 213 | new HtmlWebpackPlugin({ 214 | template: "./src/index.html" 215 | }) 216 | ] 217 | }; 218 | ``` 219 | 220 | Rebuilder le projet, et ouvrer le fichier `dist/index.html`, l'application devrait fonctionner. 221 | 222 | Vous pouvez trouvez [d'autres informations sur la création de loader dans la doc de webpack](https://webpack.js.org/contribute/writing-a-loader/). 223 | -------------------------------------------------------------------------------- /docs/workshops/intermediate/modern-build.md: -------------------------------------------------------------------------------- 1 | # Modern build :recycle: 2 | 3 | > To start this exercise, be sure to be in `./packages/intermediate/modern-build` folder. 4 | > Be sure you have [installed this repository first](../README.md#install) 5 | 6 | ## Introduction 7 | 8 | Try to start this application with `yarn build`. 9 | Open the app in your browser and look at the JS bundle size and content. 10 | 11 | ::: tip Look out ! 12 | You should notice that : 13 | 14 | - main bundle is pretty huge compared to others. 15 | - JS in bundle is pretty old for your fresh browser. 16 | - babel debug should be very verbose. 17 | ::: 18 | 19 | You should see babel debug logs like this: 20 | 21 | ```txt{9} 22 | @babel/preset-env: `DEBUG` option 23 | 24 | Using targets: 25 | { 26 | "android": "4.4.3", 27 | "chrome": "71", 28 | "edge": "17", 29 | "firefox": "64", 30 | "ie": "10", 31 | "ios": "11.3", 32 | "opera": "56", 33 | "safari": "11.1" 34 | } 35 | 36 | Using modules transform: auto 37 | 38 | Using plugins: 39 | transform-template-literals { "android":"4.4.3", "ie":"10" } 40 | transform-literals { "android":"4.4.3", "ie":"10" } 41 | transform-function-name { "android":"4.4.3", "edge":"17", "ie":"10" } 42 | transform-arrow-functions { "android":"4.4.3", "ie":"10" } 43 | transform-block-scoped-functions { "android":"4.4.3", "ie":"10" } 44 | transform-classes { "android":"4.4.3", "ie":"10" } 45 | transform-object-super { "android":"4.4.3", "ie":"10" } 46 | transform-shorthand-properties { "android":"4.4.3", "ie":"10" } 47 | transform-duplicate-keys { "android":"4.4.3", "ie":"10" } 48 | transform-computed-properties { "android":"4.4.3", "ie":"10" } 49 | transform-for-of { "android":"4.4.3", "ie":"10" } 50 | transform-sticky-regex { "android":"4.4.3", "ie":"10" } 51 | transform-dotall-regex { "android":"4.4.3", "edge":"17", "firefox":"64", "ie":"10" } 52 | transform-unicode-regex { "android":"4.4.3", "ie":"10", "ios":"11.3", "safari":"11.1" } 53 | transform-spread { "android":"4.4.3", "ie":"10" } 54 | transform-parameters { "android":"4.4.3", "edge":"17", "ie":"10" } 55 | transform-destructuring { "android":"4.4.3", "edge":"17", "ie":"10" } 56 | transform-block-scoping { "android":"4.4.3", "ie":"10" } 57 | transform-typeof-symbol { "android":"4.4.3", "ie":"10" } 58 | transform-new-target { "android":"4.4.3", "ie":"10" } 59 | transform-regenerator { "android":"4.4.3", "ie":"10" } 60 | transform-exponentiation-operator { "android":"4.4.3", "ie":"10" } 61 | transform-async-to-generator { "android":"4.4.3", "ie":"10" } 62 | proposal-async-generator-functions { "android":"4.4.3", "edge":"17", "ie":"10", "ios":"11.3", "safari":"11.1" } 63 | proposal-object-rest-spread { "android":"4.4.3", "edge":"17", "ie":"10" } 64 | proposal-unicode-property-regex { "android":"4.4.3", "edge":"17", "firefox":"64", "ie":"10" } 65 | proposal-json-strings { "android":"4.4.3", "edge":"17", "ie":"10", "ios":"11.3", "safari":"11.1" } 66 | proposal-optional-catch-binding { "android":"4.4.3", "edge":"17", "ie":"10" } 67 | transform-named-capturing-groups-regex { "android":"4.4.3", "edge":"17", "firefox":"64", "ie":"10" } 68 | ``` 69 | 70 | ![build size](../img/build.png) 71 | 72 | Notice how discontinued browsers, such as Internet Explorer, are included in this list. This is a problem because unsupported browsers won't have newer features added, and Babel continues to transpile specific syntax for them. This unnecessarily increases the size of your bundle if users are not using this browser to access your site. 73 | 74 | Babel also logs a list of transform plugins used: 75 | 76 | That's a pretty long list! These are all the plugins that Babel needs to use to transform any ES2015+ syntax to older syntax for all the targeted browsers. 77 | 78 | ## Reduce polyfill 79 | 80 | Thanks to `babel-preset-env` [useBuiltIns](https://babeljs.io/docs/en/babel-preset-env#usebuiltins) feature, we could try to remove useless polyfill. 81 | 82 | Let's try this! 83 | 84 |
85 | Solution 86 | 87 | ```json{7} 88 | { 89 | "presets": [ 90 | [ 91 | "@babel/preset-env", 92 | { 93 | "targets": "last 2 versions", 94 | "useBuiltIns": "usage", 95 | "debug": true 96 | } 97 | ] 98 | ], 99 | "plugins": ["@babel/plugin-syntax-dynamic-import"] 100 | } 101 | ``` 102 | 103 |
104 | 105 | ::: tip 106 | You should see in logs that babel did not include all the polyfills. But the size of bundles does not change much. :tada: 107 | ::: 108 | 109 | ## Focus a new target ! 110 | 111 | When you have a very large browser target (old ones and brand new ones), you _need_ to generate two targets. 112 | Thanks to `type="module"` feature of modern web browser, you can generate a big es5 like bundle and a brand new ES2018 one. 113 | 114 | To do so, let's try to generate a module target build with [Babel](https://babeljs.io/docs/en/babel-preset-env#targetsesmodules). 115 | 116 |
117 | Solution 118 | 119 | ```json{6-8} 120 | { 121 | "presets": [ 122 | [ 123 | "@babel/preset-env", 124 | { 125 | "targets": { 126 | "esmodules": true 127 | }, 128 | "useBuiltIns": "usage", 129 | "debug": true 130 | } 131 | ] 132 | ], 133 | "plugins": ["@babel/plugin-syntax-dynamic-import"] 134 | } 135 | ``` 136 | 137 | ```js{5,15,53-62} 138 | const path = require("path"); 139 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 140 | const CleanWebpackPlugin = require("clean-webpack-plugin"); 141 | const VueLoaderPlugin = require("vue-loader/lib/plugin"); 142 | const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin"); 143 | 144 | module.exports = { 145 | mode: "production", 146 | entry: "./src/main.js", // The source module of our dependency graph 147 | devServer: { 148 | contentBase: "./dist" 149 | }, 150 | output: { 151 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file) 152 | filename: "[name].bundle.[hash].mjs", 153 | path: path.resolve(__dirname, "dist") 154 | }, 155 | module: { 156 | rules: [ 157 | { 158 | test: /\.js$/, 159 | exclude: /node_modules/, 160 | loader: "babel-loader" 161 | }, 162 | { 163 | test: /\.jpg$/, 164 | use: [ 165 | { 166 | loader: "file-loader", 167 | options: { 168 | outputPath: "assets", 169 | publicPath: "assets" 170 | } 171 | } 172 | ] 173 | }, 174 | { 175 | test: /\.(sass|css)$/, 176 | use: ["style-loader", "css-loader", "sass-loader"] 177 | }, 178 | { 179 | test: /\.vue$/, 180 | use: "vue-loader" 181 | } 182 | ] 183 | }, 184 | plugins: [ 185 | new VueLoaderPlugin(), 186 | new CleanWebpackPlugin("dist"), 187 | new HtmlWebpackPlugin({ 188 | template: "./src/index.html" 189 | }), 190 | new ScriptExtHtmlWebpackPlugin({ 191 | module: /\.mjs$/, 192 | custom: [ 193 | { 194 | test: /\.js$/, 195 | attribute: "nomodule", 196 | value: "" 197 | } 198 | ] 199 | }) 200 | ] 201 | }; 202 | ``` 203 | 204 |
205 | 206 | ::: tip 207 | We will see in other steps how to use more than one webpack configuration in the same project with webpack. 208 | ::: 209 | --------------------------------------------------------------------------------