Webpack 2 - Кодирование отношений верхнего уровня

Финальное редактирование

Разрешение tl; dr заключается в том, что это невозможно. Хотя верхний ответ ниже содержит некоторую хорошую информацию.


Рассмотрим приведенный ниже код, от contacts.js. Это динамически загруженный модуль, загружаемый по требованию с помощью System.import в другом месте кода.

Если SharedUtil1 также используется в других модулях, которые также динамически загружаются с помощью System.import, как бы я хотел иметь SharedUtility1 исключенный из all эти модули и загружались только по требованию в первый раз?

Верхний уровень System.import SharedUtil1 не будет работать, так как мой экспорт зависит от него: экспорт может быть размещен только на верхнем уровне кода модуля, а не на любом обратном вызове.

Возможно ли это с помощью Webpack? Я на бета-версии 2.0.7.

import SharedUtil1 from '../../SharedUtilities/SharedUtility1';

class Contacts{
    constructor(data){
        this.data = data;
        this.sharedUtil1 = new SharedUtil1();
    }
}

export default Contacts;

ОБНОВЛЕНИЕ 1

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

Нет ли способа в Webpack указать, что зависимость X должна быть загружена по требованию, если это необходимо, и иметь какие-либо импортированные модули, которые импортируют ее для прозрачного ожидания процесса импорта? Я бы подумал, что этот случай использования будет синусоидальным для любого удаленного приложения, поэтому я должен думать, что я просто что-то пропустил.

ОБНОВЛЕНИЕ 2

В ответ на Питер я попытался получить работу по дедупликации, поскольку плагин commonChunk относится к коду обмена между конечными точками, как он упоминал, а так как require.ensure помещает загруженный код в обратный вызов, тем самым предотвращая вас от ES6 export с любым кодом, который зависит от него.

Что касается дедупликации, contacts.js и tasks.js загружают один и тот же sharedUtil, как, например,

import SharedUtil1 from '../../sharedUtilities/sharedUtility1';

Я попробовал запустить webpack как

webpack --optimize-dedupe

а также добавив

plugins: [
    new webpack.optimize.DedupePlugin()
]

в webpack.config. В обоих случаях, хотя код sharedUtil по-прежнему помещается как в пакеты контактов, так и в задачи.

Ответы

Ответ 1

Прочитав сообщение в блоге, я наконец понял, что вы намеревались. Я немного смутился словом "зависимости верхнего уровня".

У вас есть два модуля (async-a и async-b), которые загружаются по требованию из любого места (здесь модуль main), и оба имеют ссылку на общий модуль (shared).

- - -> on-demand-loading (i. e. System.import)
---> sync loading (i. e. import)

main - - -> async-a ---> shared
main - - -> async-b ---> shared

По умолчанию webpack создает дерево фрагментов следующим образом:

---> chunk uses other chunk (child-parent-relationship)

entry chunk [main] ---> on-demand chunk 1 [async-a, shared]
entry chunk [main] ---> on-demand chunk 2 [async-b, shared]

Это нормально, если shared < async-a/b или вероятность того, что async-a и async-b используются как одним и тем же пользователем, являются низкими. Это по умолчанию, потому что это простейшее поведение и, вероятно, то, что вы ожидаете: один System.import = > один кусок. По-моему, это также самый распространенный случай.

Но если shared >= async-a/b и вероятность того, что пользователь async-a и async-b загружен пользователем, высока, существует более эффективная опция chunking: (немного трудно визуализировать):

entry chunk [main] ---> on-demand chunk 1 [async-a]
entry chunk [main] ---> on-demand chunk 2 [async-b]
entry chunk [main] ---> on-demand chunk 3 [shared]

When main requests async-a: chunk 1 and 3 is loaded in parallel
When main requests async-b: chunk 2 and 3 is loaded in parallel
(chunks are only loaded if not already loaded)

Это не поведение по умолчанию, но есть плагин для его архивации: CommonChunkPlugin в асинхронном режиме. Он находит общие/разделяемые модули в кучу кусков и создает новые куски, которые включают совместно используемые модули. В асинхронном режиме он загружает новый фрагмент параллельно исходным (но теперь меньшим) фрагментам.

new CommonsChunkPlugin({
    async: true
})

// This does: (pseudo code)
foreach chunk in application.chunks
  var shared = getSharedModules(chunks: chunk.children, options)
  if shared.length > 0
    var commonsChunk = new Chunk(modules: shared, parent: chunk)
    foreach child in chunk.children where child.containsAny(shared)
      child.removeAll(shared)
      foreach dependency in chunk.getAsyncDepenendenciesTo(child)
        dependeny.addChunk(commonsChunk)

Имейте в виду, что CommonsChunkPlugin имеет параметр minChunks для определения, когда модуль имеет резьбу в качестве shared (не стесняйтесь предоставлять настраиваемую функцию для выбора модулей).

Вот пример, который подробно объясняет настройку и вывод: https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk

И еще один вариант с большей конфигурацией: https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk-advanced

Ответ 2

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

Да, это возможно; как это сделать, зависит как от контекста в вашем приложении, так и от ES6 или ES5.

ECMA Script 5

Webpack 1 был построен в ECMA Script 5 и обычно использует синтаксис CommonJS или RequireJS для экспорта и импорта модулей. При использовании этого синтаксиса для предотвращения дублирования кода можно использовать следующие функции:

  • Дедупликация предотвращает включение дублированных файлов в скомпилированные кода путем создания копий дублирующих функций вместо переопределяя их.
  • Именованные фрагменты позволяют объявлять куски как зависимости, но не сразу оцениваются; все вхождения одного и того же фрагмента будут использовать один и тот же экземпляр.
  • CommonsChunkPlugin позволяет обменивать кусок в нескольких точках ввода (применяется только к нескольким страницам страниц).

дедупликации

Из документации веб-пакета:

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

акцент мой, а не источник

Как описано в документации, разделение кода остается неизменным; каждый модуль, которому требуется sharedUtil1, должен объявить require как обычно. Чтобы предотвратить загрузку одной и той же зависимости несколько раз, включен параметр веб-пакета, который заставляет webpack явно проверять файлы для дублирования, прежде чем включать их во время выполнения.

Этот параметр включен с помощью --optimize-dedupe соответственно. new webpack.optimize.DedupePlugin()

Именованные фрагменты

Из документации по веб-загрузке:

Функция require.ensure принимает дополнительный третий параметр. Эта должен быть строкой. Если две точки разделения проходят одну и ту же строку, они используют тот же кусок... require.include может быть полезна, если модуль находится в нескольких дочерних кусках. A require.include в родительском объекте будет включать модуль и экземпляры модулей в дочерних кусках исчезнут.

Короче говоря, загрузка модулей задерживается до конца при компиляции. Это позволяет удалять повторяющиеся определения до их включения. В документации приведены примеры.

Плагин Common Chunk

Из документации по веб-папке:

CommonsChunkPlugin может перемещать модули, которые встречаются в нескольких входах куски к новому блоку ввода (кусок общего пользования). Время выполнения перемещено к общему достоянию. Это означает, что старые входные фрагменты являются исходными теперь куски.

Это очень специфично для разделения кусков между несколькими страницами, это не имеет отношения к другим обстоятельствам.

ECMA Script 6

Поддержка расширенных функций импорта модулей - это... работа продолжается. Чтобы понять, где это происходит, см. Следующие ссылки:

Здесь хорошее резюме модулей ES6 и webpack: Модули ES6 с TypeScript и Webpack

Вышеуказанная информация, скорее всего, быстро устареет.

Предложение

Для вашего собственного здравомыслия я предлагаю:

Если оптимизация имеет значение: Вернитесь к синтаксису CommonJS/RequireJS и обновите его до ECMA Script 6, когда Webpack 2 стабилен и выпущен.

Если синтаксис ECMA Script 6: Используйте стандартный формат экспорта импорта ECMA Script 6 и добавьте функции оптимизации по мере их появления.

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

Ответ 3

Для создателя Webpack это невозможно. Легко и просто. См. Ответ Peter для получения дополнительной информации о Webpack и ES6.

Вставное изображение было результатом недоразумения. См. Тот же ответ пользователя выше.

введите описание изображения здесь