(Webpack) Как разбить зависимости динамических модулей

Я только что понял, что если вы загружаете модули динамически с помощью require.ensure(), webpack не будет анализировать и разбивать зависимости вместе. В некотором смысле это имеет смысл, что можно утверждать, что webpack не может знать, передаются ли такие модули когда-либо, но можем ли мы заставить webpack выполнять эту работу в любом случае?

Пример:

app.js:

require.ensure([ 'module1.js' ], ( require ) => {
    // at some point
    require( 'module1.js' );
}, 'Module1');

require.ensure([ 'module2.js' ], ( require ) => {
    // at some point
    require( 'module2.js' );
}, 'Module2');

module1.js

let io = require( 'socket.io-client' );

module2.js

let io = require( 'socket.io-client' );

Результатом этой компиляции является то, что оба этих модуля получают всю библиотеку socket-io, «связанную» с их частями. Я изначально ожидал, что CommonsChunkPlugin перехватит эти requires и поместит эту большую библиотеку в общий блок.

new webpack.optimize.CommonsChunkPlugin( 'common' ),

Однако не работает. Конечно, я всегда мог «разрешить» эту зависимость вручную, но я надеялся, что webpack каким-то образом поможет?


person jAndy    schedule 01.09.2016    source источник
comment
Доу устанавливает minChunks на 2 в CommonsChunkPlugin options ситуации изменения?   -  person Everettss    schedule 02.09.2016
comment
К сожалению нет.   -  person jAndy    schedule 02.09.2016


Ответы (2)


Ответ скрыт в конфигурации CommonsChunkPlugin

new webpack.optimize.CommonsChunkPlugin({
  name: 'main', // Important to use 'main' or not specify, since 'main' is default
  children: true, // Look for common dependencies in all children,
  minChunks: 2, // How many times a dependency must come up before being extracted
});

children: true - основная часть этой конфигурации. Из документов:

Если true, выбираются все дочерние элементы общего чанка.


Изменить для общего асинхронного фрагмента

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

new webpack.optimize.CommonsChunkPlugin({
  name: 'main',
  children: true, 
  minChunks: 2, 
  async: true, // modification
});

Из документов о async:

Если true, новый асинхронный блок общего доступа создается как дочерний элемент для options.name и родственник options.chunks. Он загружается параллельно с options.chunks. Можно изменить имя выходного файла, указав желаемую строку вместо true.

Теперь создается дополнительный чанк, содержащий только socket.io-client из вашего примера. Это близко к исходному примеру в документах веб-пакетов.

person Everettss    schedule 06.09.2016
comment
Ах, я очень надеялся, что это все, но, как оказалось, в этом сценарии это не поможет. Все, что происходит, если я включаю children: true, - это то, что мой общий блок теперь связан с main-bundle. Но это не повлияет на динамически загружаемые пакеты. Оба по-прежнему получают эту общую библиотеку / требование, связанное с их блоком. - person jAndy; 06.09.2016
comment
async: true выполняет свою работу? - person Everettss; 06.09.2016
comment
Нет разницы. Оба динамических модуля по-прежнему связываются с одной и той же библиотекой socket-io. Я тестирую все на webpack 2.1.0-beta.20, так что почти последняя версия. - person jAndy; 06.09.2016
comment
О, я показал ответ для новейшей стабильной версии v1.13.2 - person Everettss; 06.09.2016
comment
Я не должен иметь никакого значения, но, конечно ... может быть. Вот моя конфигурация веб-пакета вместе с кодом модуля для этого небольшого тестового примера: jsbin.com/lekulanuqa/edit?js Вы пробовали себя? Работает ли у вас так, как ожидалось? - person jAndy; 06.09.2016
comment
Используйте эту часть: name: 'main' - person Everettss; 06.09.2016
comment
Это действительно помогло. Наряду с children: true он создает ожидаемое поведение (связывание socket-io lib с основным блоком). Я думал, что свойство name там просто какой-то случайный идентификатор, соответственно устанавливает имя выходного файла ... Спасибо, что тоже может выстрелить в награду. - person jAndy; 06.09.2016
comment
Я тоже был удивлен. Вы можете опустить параметр конфигурации имени, поскольку значение по умолчанию - 'main'. Если вы хотите указать имя файла общего кода, вы должны использовать filename: 'shared.js'. - person Everettss; 06.09.2016
comment
Я тоже этого не понимаю. Если я просто настрою CommonChunksPlugin на minChunks: 2 и скажем name: shared, он создаст дополнительный пакет с именем shared-bundle.js, в который включен только скрипт jsonPloader для веб-пакетов. Если я настрою его, как вы предложили, с name: main и children: true, он создаст только 3 блока (основной пакет и по одному для каждого динамического модуля). Скрипт jsonpLoader также входит в основной пакет. - person jAndy; 06.09.2016
comment
Единственное, что меня немного беспокоит, это то, что библиотека socket-io (или любой модуль, который используется динамическими модулями) связывается с main-bundle. Было бы намного проще и удобнее, если бы общий материал был разделен на отдельный пакет. Таким образом, вам не нужно передавать общий код (вероятно, динамические модули никогда не загрузятся). Только если потребуется один из динамических модулей, он должен передать общий пакет в первый раз. Есть идеи по этому поводу? - person jAndy; 08.09.2016
comment
async: true создает отдельный фрагмент с общим содержимым, который требуется jsonpLoader только для фрагмента, который будет использовать этот общий код. - person Everettss; 08.09.2016

Пока что нашел одно возможное решение. Если вы используете метод webpack require.include(), чтобы просто включить (не оценить) «разделяемую библиотеку, здесь socket.io-client» также в родительском модуль, здесь app.js, CommonChunkPlugin теперь сможет правильно разобраться.

require.include( 'socket.io-client' ); // import io from 'socket.io-client'; also works
require.ensure([ 'module1.js' ], ( require ) => {
    // at some point
    require( 'module1.js' );
}, 'Module1');

require.ensure([ 'module2.js' ], ( require ) => {
    // at some point
    require( 'module2.js' );
}, 'Module2');

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

person jAndy    schedule 06.09.2016