Как связать сценарии поставщиков отдельно и потребовать их по мере необходимости с помощью Webpack?

Я пытаюсь сделать что-то, что, по моему мнению, должно быть возможным, но я действительно не могу понять, как это сделать, только из документации по webpack (что, на мой взгляд, является адским, чтобы расшифровать и понять).

Я пишу библиотеку JavaScript с несколькими модулями, которые могут или не зависят друг от друга. Кроме того, jQuery используется всеми модулями, и некоторым из них могут понадобиться плагины jQuery. Эта библиотека будет использоваться на нескольких разных сайтах, для которых могут потребоваться некоторые или все модули.

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

Что я хотел бы достичь: для каждого веб-сайта я хочу иметь два пакета файлов с необходимыми сторонними зависимостями и другими с необходимыми модулями из моей библиотеки.

Пример: Представьте, что моя библиотека имеет следующие модули:

  • a (требуется: jquery, jquery.plugin1)
  • b (требуется: jquery, a)
  • c (требуется: jquery, jquery.ui, a, b)
  • d (требуется: jquery, jquery.plugin2, a)

И у меня есть веб-сайт (см. его как уникальный файл записи), который требует модулей a, b и c. Webpack для этого случая должен генерировать следующие файлы:

  • пакет поставщиков: с jquery, jquery.plugin1 и jquery.ui;
  • веб-узел: с модулями a, b и c;

В конце концов, я бы предпочел, чтобы jQuery был глобальным, поэтому мне не нужно требовать его на каждом отдельном файле (я мог бы потребовать его только в основном файле, например). Плагины jQuery просто расширят $global, если они потребуются (это не проблема, если они доступны для других модулей, которые им не нужны).

Предполагая, что это возможно, что будет примером файла конфигурации webpack для этого случая? Я попробовал несколько комбинаций загрузчиков, внешних и плагинов в моем файле конфигурации, но я действительно не понимаю, что они делают, и какие из них я должен использовать. Спасибо!

Ответ 1

в моем файле webpack.config.js, у меня есть

function isExternal(module) {
  var context = module.context;

  if (typeof context !== 'string') {
    return false;
  }

  return context.indexOf('node_modules') !== -1;
}

в моем массиве плагинов

plugins: [
  new CommonsChunkPlugin({
    name: 'vendors',
    minChunks: function(module) {
      return isExternal(module);
    }
  }),
  // Other plugins
]

Теперь у меня есть файл, который только добавляет сторонние библиотеки в один файл по мере необходимости.

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

plugins: [
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: function(module, count) {
      return !isExternal(module) && count >= 2; // adjustable
    }
  }),
  new CommonsChunkPlugin({
    name: 'vendors',
    chunks: ['common'],
    // or if you have an key value object for your entries
    // chunks: Object.keys(entry).concat('common')
    minChunks: function(module) {
      return isExternal(module);
    }
  })
]

Обратите внимание, что порядок плагинов имеет большое значение.

Обновление: изменение индекса indexOf для пользователей Windows

Ответ 2

Я не уверен, что полностью понимаю вашу проблему, но так как в последнее время у меня была аналогичная проблема, я попытаюсь помочь вам.

Ассортимент поставщика.

Для этого вам следует использовать CommonsChunkPlugin. в конфигурации вы указываете имя фрагмента (например, vendor) и имя файла, которое будет сгенерировано (vendor.js).

new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),

Теперь важная часть, теперь вы должны указать, что означает библиотека vendor, и вы делаете это в разделе ввода. Один еще один элемент для списка ввода с тем же именем, что и имя вновь объявленного фрагмента (т.е. "Поставщик" в этом случае). Значение этой записи должно быть списком всех модулей, которые вы хотите переместить в пакет vendor. в вашем случае это должно выглядеть примерно так:

entry: {
    app: 'entry.js',
    vendor: ['jquery', 'jquery.plugin1']
}

JQuery как глобальный

Имел ту же проблему и решил ее с помощью ProvidePlugin. здесь вы не определяете глобальный объект, а как тип щипцов для модулей. т.е. вы можете настроить его следующим образом:

new webpack.ProvidePlugin({
    $: "jquery"
})

И теперь вы можете просто использовать $ в любом месте вашего кода - webpack автоматически преобразует его в

require('jquery')

Надеюсь, это помогло. вы также можете посмотреть мой конфигурационный файл webpack, который здесь

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


Edit:

Чтобы узлы поставщика, зависящие от точки входа, просто использовали CommonsChunkPlugins несколько раз:

new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),

а затем объявить разные extenral библиотеки для разных файлов:

entry: {
    page1: ['entry.js'],
    page2: ['entry2.js'],
    "vendor-page1": [
        'lodash'
    ],
    "vendor-page2": [
        'jquery'
    ]
},

Если некоторые библиотеки перекрываются (и для большинства из них) между точками входа, вы можете извлечь их в общий файл, используя тот же плагин, что и с другой конфигурацией. См. этот пример.

Ответ 3

Если вы заинтересованы в том, чтобы автоматически связывать ваши сценарии отдельно от поставщиков:

var webpack = require('webpack'),
    pkg     = require('./package.json'),  //loads npm config file
    html    = require('html-webpack-plugin');

module.exports = {
  context : __dirname + '/app',
  entry   : {
    app     : __dirname + '/app/index.js',
    vendor  : Object.keys(pkg.dependencies) //get npm vendors deps from config
  },
  output  : {
    path      : __dirname + '/dist',
    filename  : 'app.min-[hash:6].js'
  },
  plugins: [
    //Finally add this line to bundle the vendor code separately
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.min-[hash:6].js'),
    new html({template : __dirname + '/app/index.html'})
  ]
};

Подробнее об этой функции можно узнать в официальной документации .

Ответ 4

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

entry: {
  bundle1: './build/bundles/bundle1.js',
  bundle2: './build/bundles/bundle2.js',
  'vendor-bundle1': [
    'react',
    'react-router'
  ],
  'vendor-bundle2': [
    'react',
    'react-router',
    'flummox',
    'immutable'
  ]
},

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle1',
    chunks: ['bundle1'],
    filename: 'vendor-bundle1.js',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle2',
    chunks: ['bundle2'],
    filename: 'vendor-bundle2-whatever.js',
    minChunks: Infinity
  }),
]

И ссылку на CommonsChunkPlugin docs: http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin