62 |
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 `` loading.
30 | Keeping the order would have been humanly difficult.
31 |
32 | ## webpack solution
33 |
34 | webpack is a NodeJS package that generate a bundle based on module dependencies graph resolution.
35 | It's very popular in the web community to generate web bundles for web applications.
36 |
37 | ### Step 1: Setup simple configuration
38 |
39 | To configure webpack, you just have to create a CommonJS module with default name `webpack.config.js` at the root of your project.
40 | Coupled with `webpack-cli` dev dependency, you can easily trigger a webpack _build_ on this small app.
41 | This is where all the webpack configuration will be defined
42 |
43 | ```js
44 | const path = require("path");
45 |
46 | module.exports = {
47 | entry: "./src/title.js", // The source module of our dependency graph
48 | output: {
49 | // Configuration of what we tell webpack to generate (here, a ./dist/main.js file)
50 | filename: "main.js",
51 | path: path.resolve(__dirname, "dist")
52 | }
53 | };
54 | ```
55 |
56 | After launching the command `yarn webpack`, a new file called `main.js` in a `dist` directory should be generated.
57 |
58 | ### Step 2: Change index.html script target
59 |
60 | For now, `index.html` doesn't reference the packaged file, so we must update it to use directly our webpack _output_.
61 | To do so, just change the `` tag in your `index.html` to reference the file generated by webpack.
62 |
63 | ```html{10}
64 |
65 |
66 |
67 |
68 | Simple JS file
69 |
70 |
71 |
72 |
This title will change !
73 |
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 |
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 |
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 | 
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 |
--------------------------------------------------------------------------------