David Soyez @2016

Sommaire

  • Qu'est ce que Webpack?
  • Quelques chiffres
  • Pourquoi Webpack?
  • Prerequis
  • Installation
  • Usage simple
  • Usage avance
  • Watch Mode & dev-server
  • et ensuite...?

Qu'est ce que Webpack?

Webpack prend des modules avec dépendances et génère des assets représentant ces modules.

Webpack est comparable aux outils tels que Grunt, Gulp, RequireJs, Browserify...

Quelques chiffres

Popularité:

Quelques chiffres

Tendance:

Pourquoi Webpack?

  • Diviser l'arbre de dépendance en morceaux chargés sur demande
  • Gardez le temps de chargement initial faible
  • Chaque asset statique doit pouvoir être un module
  • Possibilité d'intégrer des bibliothèques 3e partie sous forme de modules
  • Possibilité de personnaliser presque chaque partie du module bundler
  • Adaptés pour les grands projets

Objectifs:

Pourquoi Webpack?

  • Regroupez vos fichiers js dans un seul
  • Utilisez les paquets NPM dans sur le frontend
  • Ecrire du JavaScript ES2015 / ES2017  (avec l'aide de Babel)
  • Minify / Optimize
  • Convertir Less / SCSS en CSS
  • Utilisez HMR (Hot Module Replacement)
  • Inclure tout type de fichier dans votre JavaScript
  • et beaucoup d'autres...

Plus concrètement:

Prerequis

  • nodejs >=4
  • npm
  • Connaissance de CommonJs, AMD ou ES2015

Installation

// installation globale
$ npm install --save-dev webpack

// usage global
$ webpack

// installation locale dans un projet
$ npm init
$ npm install --save-dev webpack

// usage local dans un projet
$ nodejs ./node_modules/webpack/bin/webpack.js
$ vim entry.js
document.write("Ca fonctionne.");
$ vim index.html
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
    </body>
</html>
$ webpack ./entry.js bundle.js

Hash: e50979b7c38d7547d9e8
Version: webpack 1.12.14
Time: 33ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.42 kB       0  [emitted]  main
   [0] ./entry.js 34 bytes {0} [built]
// création du bundle

Usage simple 

sans module

bundle.js
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports) {

	document.write("Ca fonctionne.");


/***/ }
/******/ ]);

Usage simple 

sans module

$ vim entry.js
var monModule = require('./monModule');

var module1 = new monModule();
document.write(module1.bonjour());
document.write('<br>');
document.write(module1.auRevoir());
$ vim monModule.js
function monModule() {
  this.bonjour = function() {
    return 'bonjour!';
  }

  this.auRevoir = function() {
    return 'au revoir!';
  }
}

module.exports = monModule;
$ webpack ./entry.js bundle.js
// création du bundle

Usage simple 

avec module en CommonJs

bonjour!
au revoir!

Usage simple 

avec module en CommonJs

Usage simple 

$ vim entry.js
// define integrera tout le code dans bundle.js sans faire de requete ajax
define(['./monModule'] , function (module1) {
    document.write(module1.bonjour());
    document.write('<br>');
    document.write(module1.auRevoir());    
});
$ vim monModule.js
define([], function() {

  return {
    bonjour: function() {
      return 'bonjour';
    },
    auRevoir: function() {
      return 'au revoir';
    }
  };
});
$ webpack ./entry.js bundle.js
// création du bundle

L'utilisation de define() générera un bundle.js complet.

module AMD avec define()

Usage simple 

module AMD avec define()

L'utilisation de define() générera un bundle.js intégrant tous les modules

$ vim entry.js
require(['./monModule'] , function (module1) {
    document.body.innerHTML += module1.bonjour();
    document.body.innerHTML += '<br>';
    document.body.innerHTML += module1.auRevoir();
});
$ webpack ./entry.js bundle.js
Hash: 3235bc0333357bac68a4
Version: webpack 1.12.14
Time: 43ms
      Asset       Size  Chunks             Chunk Names
  bundle.js    3.91 kB       0  [emitted]  main
1.bundle.js  540 bytes       1  [emitted]  
   [0] ./entry.js 192 bytes {0} [built]
   [1] ./monModule.js 161 bytes {1} [built]
// création du bundle

L'utilisation de require() générera un bundle.js sans monModule.js et effectuera un chargement ajax pour charger ce dernier.

Usage simple 

AMD avec require()

Usage simple 

AMD avec require()

L'utilisation de require() générera un bundle.js sans monModule.js et effectuera un chargement ajax pour charger ce dernier

Usage avancé 

avec fichier de configuration

Afin de sauvegarder les paramètres et gagner du temps nous pouvons creer un fichier de configuration webpack.config.js

module.exports = {
    entry: "./entry.js",
    output: {
        path: __dirname,
        filename: "bundle.js"
    }
};
$ vim webpack.config.js

Et ensuite lancer simplement la commande webpack:

$ webpack

Hash: cd6d42419beaf70c1a14
Version: webpack 1.12.14
Time: 42ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.81 kB       0  [emitted]  main
   [0] ./entry.js 167 bytes {0} [built]
   [1] ./monModule.js 172 bytes {0} [built]

Dans un projet npm vous pouvez également configurer le paramètre start ou make afin de lancer webpack avec un npm start ou npm run make

Ou par exemple parametrer watch pour lancer le watch mode avec un npm run watch

Usage avancé 

les loaders

Les loaders sont des transformations qui sont appliquées sur un fichier de ressources de votre application. Ils prennent une source en entrée et renvoient une nouvelle source modifiées.
Par exemple, il y a des loaders pour CoffeeScript ou JSX.


Les principales fonctionnalités des loaders sont:

  • Les loaders peuvent être chaînés.
  • Les loaders  peuvent être synchrones ou asynchrones.
  • Les loaders fonctionnent en node.js et peuvent faire tout ce qui est possible avec.
  • Les loaders acceptent des paramètres d’entrée.
  • Les loaders peuvent être attachés à des extensions.
  • Les loaders peuvent être installés par npm.
  • Les loaders peuvent accéder à la configuration.
  • Les plugins peuvent rajouter des fonctionnalités aux loaders.
  • etc.

Usage avancé 

les loaders

Reprenons l'exemple précédent pour y ajouter un loader pour inclure du css:

$ npm install css-loader style-loader --save-dev

Nous devons d'abord installer les loaders css et style:

module.exports = {
    entry: "./entry.js",
    output: {
        path: __dirname,
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" }
        ]
    }
};

Nous modifions ensuite webpack.config.js pour y ajouter notre loader:

$ vim webpack.config.js

Usage avancé 

les loaders

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
    </body>
</html>

Le code source de index.html ne change pas:

require("./style.css");

var monModule = require('./monModule');

var module1 = new monModule();
document.write(module1.bonjour());
document.write('<br>');
document.write(module1.auRevoir());

Nous modifions ensuite entry.js pour y ajouter le require de notre style.css qui aura pour effet de l'inclure dans notre bundle en tant que module:

$ vim entry.js

On peut maintenant créer le bundle.js:

$ webpack

Usage avancé 

les loaders

Le css est alors ajouté a l’intérieur de <head> par bundle.js:

/* 2 */
/***/ function(module, exports, __webpack_require__) {

	exports = module.exports = __webpack_require__(3)();

	exports.push([module.id, "body {\n    background: blue;\n    color: white;\n}\n", ""]);

/***/ },

Un module est généré et ajouté dans bundle.js:

Usage avancé 

les loaders

De la même façon nous pouvons ajouter des fonts et des images avec url-loader. Il permet de traiter et copier nos assets dans le répertoire désiré.

$ npm install url-loader --save-dev

The url loader works like the file loader, but can return a Data Url if the file is smaller than a limit.

Rajoutons notre loader une limite pour que nos assets soit directement inclus en data:base64 en fonction de leurs tailles.

module.exports = {
    entry: "./public/entry.js",
    output: {
        path: "./public/assets", // The output directory as absolute path (required) 
        publicPath: "/assets/", // specifies the public URL address of the output files when referenced in a browser
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" },
            { test: /\.(png|jpg|ttf)$/, loader: 'url-loader?limit=8192' } 
        ]
    }
};

Installons le packet npm:

$ vim webpack.config.js

Usage avancé 

les loaders

@font-face {
    font-family: "Roboto";
    src: url('./Roboto-Black.ttf');
}
body {
    background-image: url(./webpack_logo.png);
    color: black;
}
.smile {
    background-image: url(./smile.png);
    width: 48px;
    height: 48px;
    display: block;
}
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <script type="text/javascript" src="./assets/bundle.js" charset="utf-8"></script>
        <div>
        <span class="smile"></span> 
        </div>
    </body>
</html>
$ vim public/style.css
$ vim public/index.html

Usage avancé 

les loaders

Watch Mode & dev-server

$ webpack --progress --colors --watch

L'option watch permet de reconstruire automatiquement après un changement du code source.

$ npm install webpack-dev-server -g
$ webpack-dev-server --progress --colors

webpack-dev-server permet la même chose mais en créant un mini serveur http en NodeJs .

http://localhost:8080/ ou http://localhost:8080/webpack-dev-server/

module.exports = {
    entry: "./public/entry.js",
    output: {
        path: "./public/assets", // The output directory as absolute path (required) 
        publicPath: "/assets/", // specifies the public URL address of the output files when referenced in a browser
        filename: "bundle.js"
    },
    devServer: {
        contentBase: 'public'
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" },
            { test: /\.(png|jpg|ttf)$/, loader: 'url-loader?limit=8192' } 
        ]
    }
};
$ vim webpack.config.js

Watch Mode & dev-server

$ webpack-dev-server --hot --inline

Avec --hot --online comme parametre, les modules sont recharges a chaud:

Il faut egalement ajouter module.hot.accept() dans les modules

et ensuite...?

  • Ajouter un loader css, less, sass, minify etc..
  • AJouter un loader ES2015(babel)
  • Ajouter un loader JSX
  • Ajouter un loader React
  • Flux, Redux
  • ...

Webpack

By David Soyez

Webpack

  • 1,127