web-dev-qa-db-fra.com

Webpack ProvidePlugin vs externals?

J'explore l'idée d'utiliser Webpack avec Backbone.js .

J'ai suivi le guide de démarrage rapide et une idée générale du fonctionnement de Webpack, mais je ne sais pas trop comment charger une bibliothèque de dépendances telle que jquery/backbone/underscore.

Devraient-ils être chargés à l'extérieur avec <script> ou est-ce quelque chose que Webpack peut gérer comme le shim de RequireJS?

Selon le doc de webpack: modules de calage , ProvidePlugin et externals semblent être liés à cela (il en est de même de bundle! _ chargeur quelque part) mais je ne sais pas quand utiliser lequel.

Merci

80
Henry

C'est possible: vous pouvez inclure des bibliothèques avec un <script> (C'est-à-dire utiliser une bibliothèque à partir d'un CDN) ou les inclure dans le paquet généré.

Si vous le chargez via la balise <script>, Vous pouvez utiliser l'option externals pour permettre d'écrire require(...) dans vos modules.

Exemple avec la bibliothèque de CDN:

<script src="https://code.jquery.com/jquery-git2.min.js"></script>

// the artifial module "jquery" exports the global var "jQuery"
externals: { jquery: "jQuery" }

// inside any module
var $ = require("jquery");

Exemple avec la bibliothèque incluse dans le paquet:

copy `jquery-git2.min.js` to your local filesystem

// make "jquery" resolve to your local copy of the library
// i. e. through the resolve.alias option
resolve: { alias: { jquery: "/path/to/jquery-git2.min.js" } }

// inside any module
var $ = require("jquery");

Le ProvidePlugin peut mapper des modules sur des variables (libres). Ainsi, vous pourriez définir: "Chaque fois que j'utilise la variable (gratuite) xyz dans un module, vous (webpack) devez définir xyz sur require("abc")."

Exemple sans ProvidePlugin:

// You need to require underscore before you can use it
var _ = require("underscore");
_.size(...);

Exemple avec ProvidePlugin:

plugins: [
  new webpack.ProvidePlugin({
    "_": "underscore"
  }) 
]

// If you use "_", underscore is automatically required
_.size(...)

Sommaire:

  • Bibliothèque à partir de CDN: Utilisez les balises <script> Et l'option externals
  • Bibliothèque à partir du système de fichiers: incluez la bibliothèque dans le paquet. (Peut-être modifier les options resolve pour trouver la bibliothèque)
  • externals: Rendre les vars globaux disponibles en tant que module
  • ProvidePlugin: Rendre les modules disponibles sous forme de variables libres à l'intérieur des modules
147
Tobias K.

Il est intéressant de noter que si vous utilisez la combinaison ProvidePlugin avec la propriété externals, cela vous permettra d’avoir jQuery passé dans la fermeture du module de votre pack Web sans avoir à explicitement require il. Cela peut être utile pour refactoriser le code hérité avec beaucoup de fichiers différents référençant $.

//webpack.config.js
module.exports = {
  entry: './index.js',
  output: { 
    filename: '[name].js' 
  },
  externals: {
    jquery: 'jQuery'
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
    })
  ]
};

maintenant dans index.js

console.log(typeof $ === 'function');

aura une sortie compilée avec quelque chose comme ci-dessous passée dans la fermeture webpackBootstrap:

/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

    /* WEBPACK VAR INJECTION */(function($) {
        console.log(typeof $ === 'function');

    /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1)))

/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

    module.exports = jQuery;

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

Par conséquent, vous pouvez voir que $ fait référence au global/window jQuery à partir du CDN, mais est passé dans la fermeture. Je ne sais pas s'il s'agit d'une fonctionnalité ou d'un hack chanceux, mais cela semble bien fonctionner pour mon cas d'utilisation.

22
dtothefp

Je sais que ceci est un ancien message, mais je pense qu’il serait utile de mentionner que le chargeur de script Webpack peut également être utile dans ce cas. À partir des documents Webpack:

"script: Exécute un fichier JavaScript une fois dans un contexte global (comme dans une balise de script), ne nécessite pas d'analyse."

http://webpack.github.io/docs/list-of-loaders.html

https://github.com/webpack/script-loader

J'ai trouvé cela particulièrement utile lors de la migration d'anciens processus de construction qui concaténent les fichiers du fournisseur JS et les fichiers d'application. Un mot d'avertissement est que le chargeur de script semble fonctionner uniquement par surcharge require() et ne fonctionne pas aussi loin que je peux le dire en étant spécifié dans un fichier webpack.config. Bien que beaucoup soutiennent que surcharger require est une mauvaise pratique, cela peut être très utile pour concilier vendeur et script d'application dans un seul paquet, tout en exposant JS Globals qu'il n'est pas nécessaire de placer dans un paquet Webpack supplémentaire. liasses. Par exemple:

require('script!jquery-cookie/jquery.cookie');
require('script!history.js/scripts/bundled-uncompressed/html4+html5/jquery.history');
require('script!momentjs');

require('./scripts/main.js');

Cela rendrait $ .cookie, History et moment globalement disponible à l'intérieur et à l'extérieur de ce paquet et lierait ces bibliothèques du vendeur avec le script main.js et tous ses fichiers required.

Aussi, utile avec cette technique est:

resolve: {
  extensions: ["", ".js"],
  modulesDirectories: ['node_modules', 'bower_components']
},
plugins: [
  new webpack.ResolverPlugin(
    new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
   )
]

qui utilise Bower, examinera le fichier main de chaque librairie required package.json. Dans l'exemple ci-dessus, History.js n'a pas spécifié de fichier main. Le chemin d'accès au fichier est donc nécessaire.

11
dtothefp