Skip to content

Instantly share code, notes, and snippets.

@t8g
Last active April 11, 2017 18:38
Show Gist options
  • Save t8g/47ffa8b8119cd54504e4 to your computer and use it in GitHub Desktop.
Save t8g/47ffa8b8119cd54504e4 to your computer and use it in GitHub Desktop.
Webpack : introduction

Webpack

Installation

  • > mkdir projet && cd projet
  • > npm init
  • > npm i webpack --save-dev

Préparation

  • > mkdir app
  • > touch webpack.config.js
module.exports = {
  context: __dirname + '/app',
  entry: './index.js',

  output: {
    path: __dirname + '/app',
    filename: 'bundle.js'
  }
}
  • > touch app/index.js
alert('Oh yeah !')

Compilation !

Note : npm_exec est un alias vers ./node_modules/.bin

  • > npm_exec webpack
  • Oh magie, regardez dans app ... un zouli bundle.js
  • > npm_exec webpack --watch
  • Modifiez index.js

Utilisation en mode serveur

  • > touch app/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Webpack</title>
</head>
<body>
    <h1>Webpack !</h1>
    <script src="bundle.js"></script>
</body>
</html>
  • > npm i webpack-dev-server --save-dev
  • Modification de package.json
...
"scripts": {
    "start": "webpack-dev-server --content-base app"
},
...
  • npm start
  • Ouvrez un navigateur http://localhost:8080
  • Et pouf joie !
  • Note en passant : vous pouvez supprimer le fichier bundle.js (le dev server le regenère et le sert depuis la mémoire)

Angular en CommonJS

  • > npm i angular --save-dev
  • Modifiez index.html
...
<body ng-app="app">
...
  • et index.js
var angular = require('angular')
var ngModule = angular.module('app', [])

ngModule.run(function () {
    console.log('Angular !')
})
  • Et paf ça marche !

Require d'une directive

  • mkdir app/directives
  • touch app/directives/index.js
  • touch app/directives/poly-hello.js
  • touch app/directives/poly-hello.html
module.exports = function (ngModule) {
    require('./poly-hello')(ngModule)
}
module.exports = function (ngModule) {
  ngModule.directive('polyHello', function () {
    return {
      restrict: 'E',
      scope: {},
      templateUrl: 'directives/poly-hello.html',
      controllerAs: 'vm',
      controller: function () {
        var vm = this
        vm.name = 'Polypodes'

      }
    }
  })
}
<h1 class="poly-hello">Hello {{ vm.name }}</h1>
  • Et on modifie app/index.js et index.html
var angular = require('angular')
var ngModule = angular.module('app', [])

require('./directives')(ngModule)
...
<body ng-app="app">
    <poly-hello></poly-hello>
    <script src="bundle.js"></script>
</body>
...
  • Et paf une directive !

Componentisation avec du require de html

  • On modifie la directive (poly-hello.js)
// templateUrl: 'directives/poly-hello.html',
template: require('./poly-hello.html')
  • Et bim ça marche plus :(
  • On a besoin d'un loader
  • npm i raw-loader --save-dev
  • Modification de webpack.config.js
module.exports = {
  context: __dirname + '/app',
  entry: './index.js',

  output: {
    path: __dirname + '/app',
    filename: 'bundle.js'
  },

  module: {
    loaders: [
      { test: /\.html$/, loader: 'raw', exclude: /node_modules/ }
    ]
  }

}

Encore plus de componentisation avec du require de css

  • On va avoir besoin de 2 loaders : style et css
  • npm i css-loader style-loader --save-dev
  • style : ajoute le style dans le dom
  • css : chargement des fichiers css
  • Qu'on va s'empresser d'utiliser dans webpack.config.js
...
  module: {
    loaders: [
      { test: /\.html$/, loader: 'raw', exclude: /node_modules/ },
      { test: /\.css$/, loader: 'style!css', exclude: /node_modules/ }
    ]
  }
...
  • On crée un fichier poly-hello.css
  • touch app/directives/poly-hello.css
.poly-hello { color: pink }
  • Et un require suffit (on le fait dans poly-hello.js)
require('./poly-hello.css')
...
  • Oh c'est rose !

Tu es hype tu veux faire de l'ECMA2015 ?

  • > npm i babel-loader --save-dev
  • Et devinez-quoi ? On va l'utiliser dans webpack.config.js
...
{ test: /\.js$/, loader: 'babel', exclude: /node_modules/ }
...
  • Et vazi les const et let et arrow function de bôgoss
const angular = require('angular') // regarde maman ... une constante
const ngModule = angular.module('app', [])

require('./directives')(ngModule)

Et gérer des assets, ça te dit ?

@font-face {
    font-family: Dashley;
    src: url(./Dashley.ttf);
}
.poly-hello {
    font-family: Dashley;
    color: pink;
}
  • Un nouveau loader
  • > npm i file-loader --save-dev
  • Et on modifie webpack.config.json (ça commence à être routinier, non ?)
{ test: /\.ttf$|\.otf$/, loader: "file" }
  • T'as vu comme ça claque ?
  • Et maintenant une image
  • Imaginons que l'on ait une image polypode.jpg dans /app/directives/ et que l'on s'en serve dans le template poly-hello.html
<h1 class="poly-hello">
    Hello {{ vm.name }}
    <img src="polypode.jpg" alt="polypode">
</h1>

  • Il faut ajouter l'extension de l'image (jpg) pour le loader file
{ test: /\.ttf$|\.otf$|\.jpg$/, loader: "file" }
  • Mais ça marche pas ?
  • Il nous faut un autre loader pour le html !
  • > npm i html-loader --save-dev
  • Et remplacer raw par html dans webpack.config.js
...
{ test: /\.html$/, loader: 'html', exclude: /node_modules/ },
...
  • Et banco !

Et si on buildait pour la prod ?

  • On va utiliser la variable d'environnement NODE_ENV
  • Et changer le chemin de sortie lorsque cette variable est à "production"
var  config = {
  context: __dirname + '/app',
  entry: './index.js',

  output: {
    path: __dirname + '/app',
    filename: 'bundle.js'
  },

  module: {
    loaders: [
      { test: /\.js$/, loader: 'babel', exclude: /node_modules/ },
      { test: /\.html$/, loader: 'html', exclude: /node_modules/ },
      { test: /\.css$/, loader: 'style!css', exclude: /node_modules/ },
      { test: /\.ttf$|\.otf$|\.jpg$/, loader: "file" }
    ]
  }

}

if (process.env.NODE_ENV === 'production') {
    config.output.path = __dirname + '/dist'
}

module.exports = config
  • Il suffit alors de lancer webpack en mode production et de copier index.html
  • > NODE_ENV=production ./node_modules/.bin/webpack && cp app/index.html dist/index.html
  • Et tant qu'à faire mettre ça dans package.json
...
  "scripts": {
    "start": "webpack-dev-server --content-base app",
    "build": "NODE_ENV=production ./node_modules/.bin/webpack && cp app/index.html dist/index.html"
  },
...
  • > npm run build
  • > lrhs --dir dist/
  • Note : lrhs (lr-http-server) ne sert qu'à tester, n'importe quel serveur web fait l'affaire

Mais wait ! c'est pas minifié ça !

  • Ben il suffit de rajouter "-p" comme option de webpack lors du build
  • Oui mais angular, il aime pas la minification avec l'injection ..
  • Par exemple : si on modifie notre directive
controller: function ($timeout) {
  var vm = this
  vm.name = 'Polypodes'
  $timeout(function () {
    vm.name = 'ByteClub'
  }, 1000)
}
  • Après le builde (qui compresse) ça marche plus
  • Vite un nouveau loader
  • > npm i ng-annotate-loader --save-dev
  • Et on remplace le loader de js pour la conf de production
if (process.env.NODE_ENV === 'production') {
    config.output.path = __dirname + '/dist'
    config.module.loaders[0] = { test: /\.js$/, loader: 'ng-annotate!babel', exclude: /node_modules/ }
}
  • Et ça remarche !

Plus loin avec les plugins

  • Un exemple : i18n
@fakhrizaki
Copy link

Thanks a lot for this. If you could add SCSS and image loaders in this setup too, it would be great - may be that's what is next :)

Once again thank you very much for this awesome Webpack-Angular compilation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment