Webpack и External Libs: ProvidePlugin vs entry vs global import?

1. ProvidePlugin()

Похож на широко используемый подход. Об этом gist, демонстрируя, как включить whatwg-fetch polyfill в сборку Webpack. Многие ответы на StackOverflow используют здесь и здесь.

new webpack.ProvidePlugin({
  '$': 'jquery',
  'jQuery': 'jquery',
  'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
})

👍 Плюсы

  • Это работает. (пожалуйста, обновите этот список, если мне что-то не хватает)

👎 Минусы

  • Необходимо отслеживать глобальные библиотеки в конфигурации Webpack.

2. entry: [...]

Я был немного удивлен этим подходом, когда обнаружил его в этот смысл, но он работает так же хорошо.

entry: [
    'babel-polyfill',
    'whatwg-fetch',
    'jquery',
    'webpack-hot-middleware/client',
    path.join(process.cwd(), 'app/app.js')
],

👍 Плюсы

  • Он работает.
  • Я могу полностью удалить ProvidePlugin().

👎 Минусы

  • Необходимо отслеживать глобальные библиотеки в конфигурации Webpack.

3. Верхний уровень import

Это очень просто, см. пример app.js. Этот файл является точкой входа в приложение React.

/**
 * app.js
 */

import 'whatwg-fetch';
import 'babel-polyfill';
import 'jquery';

👍 Плюсы

  • Он работает так же хорошо.
  • Простое добавление/удаление. Не нужно касаться конфигурации Webpack.

👎 Минусы

  • Не похоже, что этот подход будет работать с плагинами jQuery, например. bootstrap.js.

Наблюдение. Между всеми тремя подходами я не заметил никаких изменений в размере пакета.

Есть ли один рекомендованный способ обработки глобальных библиотек с помощью Webpack (и React)? Может ли какое-либо из этих решений вызвать проблему с помощью рендеринга на стороне сервера?

Спасибо!

Ответ 1

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

// app.js
import $ from 'jquery';
$.ajax(...);

Если вам абсолютно необходимо jQuery на глобальном уровне, потому что третья сторона script требует его на вашей странице или, возможно, для отладки в консоли, а затем немного информации о подходе, которые вы указали:

ProvidePlugin

ProvidePlugin не будет раскрывать jQuery в глобальной сети и действительно предназначен для исправления сторонних модулей, которые неправильно полагаются на наличие глобального модуля, поэтому я бы не рекомендовал это, например.

// app.js
$.ajax(...);

Эффективно передается в:

// app.js
require('jquery').ajax(...);

Ввод и импорт верхнего уровня

Эти подходы не будут работать для обычного модуля UMD, такого как jQuery, поскольку jQuery достаточно умен, чтобы не подвергать себя глобальному при загрузке загрузчиком commonjs/amd/es6.

Однако эти два подхода идеально подходят для модулей с побочными эффектами, таких как babel-polyfill/whatwg-fetch, потому что они ничего не экспортируют, они по сути мутируют глобальную среду.


Моя рекомендация для jQuery заключается в том, чтобы использовать expose-loader, который предназначен для экспорта экспорта модулей во всем мире, например.

// webpack.config.js
{
    module: {
        loaders: [
            test: require.resolve('jquery'),
            loader: 'expose-loader?jQuery!expose-loader?$'
        ]
    }
}

Затем вам нужно будет импортировать его в код приложения:

// app.js
import $ from 'jquery';
$.ajax(...)

Но он доступен в глобальном режиме для других скриптов на странице для доступа, если это абсолютно необходимо:

// console
window.$
window.jQuery

ПРИМЕЧАНИЕ. Технически вы могли бы просто import 'jquery' раз в вашей точке входа при использовании выгружающего загрузчика, а затем полагаться на глобальный в других модулях.

Как я уже сказал, на самом деле не рекомендуется размещать модуль, если вам это не нужно, даже если вы в настоящее время используете его в каждом другом модуле.

Ответ 2

Просто узнайте, что предоставляемая библиотека будет перезаписана, если вы используете несколько пакетов (точек входа) на одной странице при использовании ProvidePlugin. Примеры для RoR и Webpacker, но я предполагаю, что это не имеет значения.

Например, у вас есть в вашем макете:

  javascript_pack_tag 'application',
                      'metronic'

А в конфигах у вас есть:

  environment.plugins.append('Provide', new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      "window.jQuery": "jquery",
      "window.$": "jquery",
      _: 'underscore',
      Handlebars: 'handlebars'
  }));

Если в application.js вам требуются библиотеки, которые мутируют JQuery, вы потеряете всю эту мутацию в metronic.js и в браузере, даже если вы предоставите JQuery с помощью expose-loader.

Поправьте меня, если я ошибаюсь, вероятно, ProvidePlugin просто импортирует библиотеки в каждую точку входа.