Webpack ProvidePlugin против внешних?

84

Я изучаю идею использования Webpack с Backbone.js .

Я следил за кратким руководством по началу работы и имел общее представление о том, как работает Webpack, но мне неясно, как загрузить библиотеку зависимостей, такую ​​как jquery / backbone / underscore.

Должны ли они загружаться извне, <script>или это то, что Webpack может обрабатывать как прокладку RequireJS?

Согласно WebPack документу: шиммирования модули , ProvidePluginи , externalsпохоже, связаны с этим (так bundle!Загрузчик где - то) , но я не могу понять, когда использовать который.

благодаря

Генри
источник

Ответы:

153

Возможно и то, и другое: вы можете включить библиотеки с помощью <script>(т.е. использовать библиотеку из CDN) или включить их в сгенерированный пакет.

Если вы загружаете его через <script>тег, вы можете использовать externalsопцию, позволяющую писать require(...)в ваших модулях.

Пример с библиотекой из 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");

Пример с библиотекой, входящей в комплект:

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");

Модуль ProvidePluginможет отображать модули в (бесплатные) переменные. Таким образом , вы можете определить: «Каждый раз , когда я использую (бесплатно) переменный xyzвнутри модуля вы (WebPack) следует установить xyzв require("abc")

Пример без ProvidePlugin:

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

Пример с ProvidePlugin:

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

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

Резюме:

  • Библиотека из CDN: используйте <script>тег и externalsпараметр
  • Библиотека из файловой системы: Включите библиотеку в комплект. (Возможно, измените resolveпараметры, чтобы найти библиотеку)
  • externals: Сделать глобальные вары доступными как модуль
  • ProvidePlugin: Сделать модули доступными как свободные переменные внутри модулей
Тобиас К.
источник
Следует добавить newперед webpack.ProvidePlugin webpack.github.io/docs/list-of-plugins.html
MK Yung
Почему бы просто не использовать скрипт-загрузчик? Это намного проще, как объяснил
@dtothefp
Если мой файл webpack.config находится в папке с именем javascript, а внутри у меня есть папка с именем vendor с моим файлом jquery. если пути не будет. решить: {псевдоним: {jquery: "vendor / jquery-1.10.2.js"}}. У меня все еще не работает псевдоним
me-me
3
Просто передайте абсолютный путь к опции псевдонима. Если вы передаете относительный путь, он относительно местоположения require / import в webpack 1. В webpack 2 он относительно файла webpack.config.js соответственно. параметр контекста.
Тобиас К.
@TobiasK. Абсолютный путь не работает с экспортом по умолчанию. Я получаю объект {__esModule: true, default: MY_DEFAULT_EXPORT}вместо MY_DEFAULT_EXPORTфайлов.
mgol
26

Стоит отметить, что если вы используете свойство ProvidePluginв сочетании со externalsсвойством, это позволит вам перейти jQueryв закрытие модуля webpack без необходимости явно указывать requireэто. Это может быть полезно для рефакторинга устаревшего кода со ссылками на множество различных файлов $.

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

теперь в index.js

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

будет скомпилированный вывод с чем-то вроде ниже, переданным в 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;

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

Следовательно, вы можете видеть, что $ссылка на global / window jQueryиз CDN, но передается в закрытие. Я не уверен, предназначена ли это функциональность или удачный взлом, но, похоже, он хорошо работает для моего варианта использования.

dtothefp
источник
вам не нужен ни один плагин, если вы не собирались использовать require/importего. $просто будет работать, потому что он достигнет глобального масштаба, несмотря ни на что. ProviderPluginТребует разбора AST , так это дорогой плагин и добавить в свое время сборки заметно. Так что это в основном пустая трата.
faceyspacey.com 06
@dtohefp, этот ответ - находка. Можете ли вы объяснить, почему ProvidePluginвернули такой объект, myModule.defaultесли я не добавил модуль во внешние? Я никогда не знал, что будут прямые отношения.
Slbox
11

Я знаю, что это старый пост, но подумал, что было бы полезно упомянуть, что загрузчик скриптов webpack может быть полезен и в этом случае. Из документов webpack:

«скрипт: однократно выполняет файл JavaScript в глобальном контексте (например, в теге скрипта), требует не анализировать».

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

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

Я нашел это особенно полезным при миграции старых процессов сборки, которые объединяют файлы поставщиков JS и файлы приложений. Предупреждение: похоже, что загрузчик скриптов работает только через перегрузку require()и не работает, насколько я могу судить, указав его в файле webpack.config. Хотя многие утверждают, что перегрузка require- плохая практика, она может быть весьма полезной для объединения скрипта поставщика и приложения в один пакет и в то же время раскрытия глобальных объектов JS, которые не нужно включать в дополнительные пакеты веб-пакетов. Например:

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

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

Это сделает $ .cookie, History и moment глобально доступными внутри и вне этого пакета и объединит эти библиотеки поставщиков со скриптом main.js и всеми его required-файлами.

Кроме того, с помощью этой техники полезно:

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

который использует Bower, будет просматривать mainфайл в каждой requireбиблиотеке d package.json. В приведенном выше примере для History.js не mainуказан файл, поэтому путь к файлу необходим.

dtothefp
источник