Publié par

Il y a 3 années -

Temps de lecture 6 minutes

Webpack : choisir SASS ou LESS ?

logo-webpack-sass

Le rôle de Webpack

Comme expliqué dans ce précédent article (Webpack + ES6 + Babel + Angular1.x), Webpack nous permet de modulariser le code Javascript. Ce n’est toutefois pas là son seul argument puisqu’il permet aussi de disposer de toutes les ressources statiques de notre projet (CSS, images, polices de caractères) en tant que module.

Plus besoin de task-runner comme Gulp ou Grunt, il suffit d’inclure la ressource dans un des fichiers Javascript pour que la ressource soit ajoutée au « pack » (aussi appelé bundle) généré par Webpack.

Exemple en EcmaScript 5

require('../path/to/my/style.css');

Exemple en EcmaScript 6

import './myImage.png';

Nous allons nous intéresser à l’une de ces ressources statiques, la feuille CSS, à travers un exemple. Voyons tout d’abord une configuration simple de Webpack faite en ES6 permettant de charger les feuilles de style.

Configuration Webpack

import webpack from 'webpack';
const DIRNAME = __dirname;

export default {
  context: DIRNAME,
  entry: [
    DIRNAME + '/app.js'
  ],
  output: {
    path: DIRNAME + 'dist',
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      { test: /\.css$/, loaders: ['style', 'css']) }
    ]
  }
};
./style.css
.my-class{
  text-align: center;
}
./app.js
/* ... */
import './style.css';
/* ... */

Le css-loader va ajouter au fichier bundle.js le contenu du ./style.css importé et le style-loader ajoutera la balise <link rel="stylesheet"> référençant l’ensemble des CSS du pack.

Dossier output

dist
|_ bundle.js

bundle.js

Webpack generated code...
 
/*!********************************!*\
  !*** ./~/css-loader!./style.css ***!
  \**********************************/
/***/ function(module, exports, __webpack_require__) {
 exports = module.exports = __webpack_require__(/*! ./../~/css-loader/lib/css-base.js */ 12)();
 // imports
 
 // module
 exports.push([module.id, ".my-class{text-align: center;}"]);

 // exports

/***/ },
 
Webpack generated code...

Pré-processeurs

Si l’on souhaite utiliser un pré-processeur comme SASS ou LESS les étapes seront les mêmes que pour n’importe quelle ressource, à savoir:

  1. Installer le loader adéquat
    npm install sass-loader
    // ou
    npm install less-loader
  2. Ajouter le loader à la configuration de Webpack
    { test: /\.scss$/, loaders: ['style', 'css', 'sass']}
    // ou 
    { test: /\.less$/, loaders: ['style', 'css', 'less']}
  3. Importer les feuilles de style dans le code Javascript
    import '../path/to/styles.scss';
    // ou
    import './styles.less';
  4. Lancer Webpack afin qu’il puisse packager ces ressources

En dehors des différences inhérentes aux pré-processeurs il faut savoir qu’utiliser l’un ou l’autre avec Webpack n’est pas sans conséquence. Nous allons donc définir quelles sont ces contraintes afin de faciliter le choix entre SASS ou LESS.

Webpack et SASS

Avantage : la ré-écriture d’URL

L’intégration de SASS avec Webpack profite de la popularité du pré-processeur: le projet sur Github (https://github.com/jtangelder/sass-loader) est plus avancé que son concurrent. Néanmoins comme SASS ne fournit pas de ré-écriture d’url, un loader supplémentaire devra être installé (resolve-url-loader).

Prenons par exemple le cas suivant: nous souhaitons utiliser une image enregistrée localement comme background d’une classe CSS. Il est même possible de passer par une variable.

Répertoire du projet

projet
|_ app.js
|_ index.html
|_ assets
|   |_ fonts
|   |_ images
|       |_ image1.png
|       |_ image2.png
|_ style.scss
|_ dist

./style.scss

@path-to-images: './assets/images/';
.my-class{
  background: url(@path-to-images + 'image1.png') no-repeat;
  /* le loader resolve-url va transformer le chemin
  * './assets/images/image1.png' en '/img/image1.png'
  */
}

Voici maintenant la configuration permettant au loader file-loader de copier les images png dans le répertoire du bundle Webpack (dist).

Loaders de Webpack

...
  module: {
    loaders: [
      { test: /\.scss$/, loaders: ['style', 'css', 'resolve-url', 'sass']) },
      { test: /\.png$/, loader: "file-loader?name=img/[name].png"}
        /* Tous les fichiers png seront copiés vers l'url 
        * ./dist/img/<nom-fichier>.png 
        */
    ]
  }
...

Dossier output

dist
|_ bundle.js
|_ img
|   |_ image1.png
|   |_ image2.png

Les images sont désormais accessibles par le bundle au chemin /img, néanmoins sass-loader ne peut pas remplacer les URL automatiquement. C’est donc le loader resolve-url-loader qui s’en chargera.

Inconvénient : les multiples imports

Le plus gros désavantage de SASS concerne les multiples imports : un fichier commonStyle.scss sera par exemple importé dans plusieurs autres feuilles de style.

./commonStyles.scss

.commonClass{
  ...
}
./style1.scss
@import './commonStyles.scss';
.firstClass{
  .commonClass;
  ...
}

./style2.scss

@import './commonStyles.scss';
.anotherClass{
  .commonClass;
  ...
}

Chaque import supplémentaire entrainera une duplication du code dans le bundle généré. Dans ce cas Webpack aura généré deux fois le code de variables.scss.

Il n’y a pas, à l’heure actuelle, de façon propre de régler ce problème :

  • La première solution consiste à importer une seule fois tous les fichiers de style dans un fichier main.scss importé dans l’application. On perd néanmoins l’aspect isolé et indépendant des modules ES6.
./commonStyles.scss
.commonClass{
  ...
}

./style1.scss

//Plus d'import
.firstClass{
  .commonClass;
  ...
}

./style2.scss

//Plus d'import
.anotherClass{
  .commonClass;
  ...
}
./main.scss
// Import all stylesheets here
@import './variables.scss';
@import '.commonStyles.scss/';
@import './style1.scss';
@import './style2.scss';
app.js
/* ... */
 
import './main.scss';
 
/* ... */
  • Il est enfin possible de contourner le problème avec node-sass-import-once mais dans ce cas on n’utilise plus Webpack pour gérer les feuilles de style.

Webpack et LESS

Avantage: les multiples imports

LESS est moins utilisé que son homologue, sa communauté est de ce fait moins importante. Néanmoins ce pré-processeur corrige les inconvénients de SASS concernant la gestion des multiples imports.

Si l’on reprend l’exemple écrit en LESS, les classes de commonStyles.less ne seront écrites qu’une seule fois dans le bundle de Webpack si l’on spécifie le mot clé « reference » lors de l’import d’une ressource externe.

./commonStyles.less
.commonClass{
  ...
}
.anotherCommonClass{
  ...
}
./style1.less
@import (reference) './commonStyles.less';
.firstClass{
  .commonClass;
  ...
}

./style2.less

@import (reference) './commonStyles.less';
.anotherClass{
  .commonClass;
  ...
}

Inconvénient: la ré-écriture d’url

LESS gère la ré-écriture d’URL sans avoir besoin d’un autre loader (resolve-url de SASS). Néanmoins il subsiste à l’heure actuelle un bug qui empêche de passer une variable comme paramètre d’url.

Reprenons le précédent projet:

Configuration Webpack gérant les ressources LESS et PNG
...
  module: {
    loaders: [
      { test: /\.scss$/, loaders: ['style', 'css', 'less']) },
      { test: /\.png$/, loader: "file-loader?name=img/[name].png"} 
      /* images disponible dans le bundle à l'url /img/[nom-image].png */
    ]
  }
...
Répertoire du projet
projet
|_ app.js
|_ index.html
|_ assets
|   |_ fonts
|   |_ images
|       |_ image1.png
|       |_ image2.png
|_ style.scss
|_ dist

Url en dur

./style.scss

.my-class{
  background: url('./assets/images/image1.png') no-repeat;
}
Classe dans le bundle de Webpack
.my-class{background: url('/img/image1.png') no-repeat;}
/* L'url a bien été remplacée par less-loader */

Url par une variable
./style.scss
@path-to-image1: './assets/images/image1.png';
.my-class{
  background: url(@path-to-image1) no-repeat;
}
Classe dans le bundle de Webpack
.my-class{background: url('./assets/images/image1.png') no-repeat;}
/* L'url n'a pas été remplacée et n'est donc pas disponible */

Conclusion

Aucun des deux choix ne sera mauvais cependant LESS permet de rester dans la philosophie de Webpack sans aucun ajout tiers. SASS possède une communauté plus importante, plus active, mais sa complémentarité avec Webpack n’est pas encore parfaite.

Et vous, quel sera votre choix ?

Publié par

Commentaire

3 réponses pour " Webpack : choisir SASS ou LESS ? "

  1. Publié par , Il y a 3 années

    Merci pour l’article,

    Il y’a une coquille sur le bloc de code contenant
    { test: /\.scss$/, loaders: [‘style’, ‘css’, ‘resolve-url’, ‘sass’]) },
    Il faut supprimer la ) après ‘sass’]

  2. Publié par , Il y a 3 années

    Bravo, Bastien.
    Article tres interessant sur un probleme souvent rencontre lorsqu’on cherche a eviter l’utilisation de Gulp

    Merci

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Xebian, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.