Разделение кода
Для больших веб-приложений неэффективно размещать весь код в одном файле, особенно если некоторые блоки кода требуются только в определенных условиях. Webpack имеет функцию разделения вашего кода на «блоки», которые загружаются по требованию. Другие сборщики могут называть их «слоями», «свертками» или «фрагментами». Эта функция называется «разделение кода».
Это функция по выбору. Вы можете определить точки разделения в своей кодовой базе. Webpack позаботится о зависимостях, выходных файлах и других аспектах выполнения.
Чтобы развеять распространенное недопонимание: Разделение кода — это не только извлечение общего кода в общий блок. Более важная функция заключается в том, что Разделение кода может использоваться для разделения кода на блок, загружаемый по требованию. Это позволяет уменьшить начальный объем загрузки и загружать код по требованию, когда он запрошен приложением.
Определение точки разделения
AMD и CommonJs определяют различные методы для загрузки кода по требованию. Оба поддерживаются и действуют как точки разделения:
CommonJs: require.ensure
require.ensure(dependencies, callback)
Метод require.ensure гарантирует, что каждая зависимость в dependencies может быть синхронно запрошена при вызове callback. callback не имеет параметров.
Пример:
require.ensure(["module-a", "module-b"], function() {
var a = require("module-a");
// ...
});
Примечание: require.ensure загружает только модули, но не выполняет их.
AMD: require
Спецификация AMD определяет асинхронный метод require с этим определением:
require(dependencies, callback)
При вызове все dependencies загружаются, и callback вызывается с экспортом загруженных dependencies.
Пример:
require(["module-a", "module-b"], function(a, b) {
// ...
});
Примечание: AMD require загружает и выполняет модули. В webpack модули выполняются слева направо.
Примечание: можно опустить обратный вызов.
ES6 Модули
tl;dr: Webpack не поддерживает ES6 модули; используйте require.ensure или require напрямую, в зависимости от того, какой формат модулей создает ваш транспайлер.
Webpack 1.x.x (в релизе 2.0.0!) не поддерживает и не понимает ES6 модули напрямую. Однако вы можете обойти это, используя транспайлер, такой как Babel, для преобразования ES6 синтаксиса import в модули CommonJs или AMD. Этот подход эффективен, но имеет важное ограничение для динамической загрузки.
Добавление синтаксиса модуля (import x from 'foo') намеренно разработано для статической анализируемости, что означает, что динамические импорты недоступны.
// INVALID!!!!!!!!! ['lodash', 'backbone'].forEach(name => import name )
К счастью, существует спецификация JavaScript API «загрузчик», предназначенная для обработки динамического случая: System.load (или System.import). Этот API станет прямым аналогом приведенных выше вариантов require . Однако большинство транспайлеров не поддерживают преобразование вызовов System.load в require.ensure, поэтому вам нужно сделать это непосредственно, если вы хотите использовать динамическое разделение кода.
//static imports
import _ from 'lodash'
// dynamic imports
require.ensure([], function() {
let contacts = require('./contacts')
})
Содержание блоков
Все зависимости в точке разделения попадают в новый блок. Зависимости также добавляются рекурсивно.
Если вы передаете выражение функции (или связанное выражение функции) в качестве обратного вызова в точку разделения, webpack автоматически помещает все необходимые зависимости в этом выражении функции в блок тоже.
Оптимизация блоков
Если два блока содержат одинаковые модули, они объединяются в один. Это может привести к тому, что у блоков будет несколько родительских элементов.
Если модуль доступен во всех родительских элементах блока, он удаляется из этого блока.
Если блок содержит все модули другого блока, это сохраняется. Это удовлетворяет нескольким блокам.
Загрузка блоков
В зависимости от опции конфигурации target в пакет добавляется алгоритм загрузки блоков. Например, для целевой платформы web блоки загружаются через jsonp. Блок загружается только один раз, и параллельные запросы объединяются в один. Алгоритм проверяет загруженные блоки на предмет соответствия нескольким блокам.
Типы блоков
Блок входа
Блок входа содержит запуск плюс набор модулей. Если блок содержит модуль 0, запуск выполняет его. В противном случае он ожидает блоков, содержащих модуль 0, и выполняет его (каждый раз, когда есть блок с модулем 0).
Обычный блок
Обычный блок не содержит запуска. Он содержит только набор модулей. Структура зависит от алгоритма загрузки блоков. Например, для jsonp модули оборачиваются в функцию обратного вызова jsonp. Блок также содержит список идентификаторов блоков, которые он удовлетворяет.
Начальный блок (не входной)
Начальный блок — это обычный блок. Единственное отличие заключается в том, что оптимизация рассматривает его как более важный, так как он учитывается при расчете времени начальной загрузки (как блоки входа). Этот тип блока может встречаться в сочетании с CommonsChunkPlugin.
Разделение кода приложения и поставщиков
Чтобы разделить приложение на 2 файла, скажем app.js и vendor.js, вы можете поместить файлы поставщиков в vendor.js. Затем передайте это имя в CommonsChunkPlugin как показано ниже.
var webpack = require("webpack");
module.exports = {
entry: {
app: "./app.js",
vendor: ["jquery", "underscore", ...],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js")
]
};
Это удалит все модули в блоке vendor из блока app . Блок bundle.js теперь будет содержать только код вашего приложения без зависимостей. Они находятся в vendor.bundle.js.
В вашем HTML-файле загрузите vendor.bundle.js перед bundle.js.
<script src="vendor.bundle.js"></script> <script src="bundle.js"></script>
Несколько входных блоков
Можно настроить несколько точек входа, что приведет к нескольким входным блокам. Блок входа содержит запуск, и на странице должен быть только один запуск (есть исключения).
Запуск нескольких точек входа
С CommonsChunkPlugin запуск перемещается в общий блок. Точки входа теперь находятся в начальных блоках. Хотя может загружаться только один начальный блок, может загружаться несколько входных блоков. Это позволяет запускать несколько точек входа на одной странице.
Пример:
var webpack = require("webpack");
module.exports = {
entry: { a: "./a", b: "./b" },
output: { filename: "[name].js" },
plugins: [ new webpack.optimize.CommonsChunkPlugin("init.js") ]
}
<script src="init.js"></script> <script src="a.js"></script> <script src="b.js"></script>
Общий блок
CommonsChunkPlugin может перемещать модули, которые встречаются в нескольких входных блоках, в новый входной блок (общий блок). Запуск также перемещается в общий блок. Это означает, что старые входные блоки теперь являются начальными блоками. См. все параметры в списке плагинов.
Оптимизация
Существуют плагины оптимизации, которые могут объединять блоки в зависимости от определенных критериев. См. список плагинов.
LimitChunkCountPluginMinChunkSizePluginAggressiveMergingPlugin
Именованные блоки
Функция require.ensure принимает дополнительный 3-й параметр. Это должна быть строка. Если две точки разделения передают одну и ту же строку, они используют один и тот же блок.
require.include
require.include(request)
require.include — это функция, специфичная для webpack, которая добавляет модуль в текущий блок, но не выполняет его (выражение удаляется из пакета).
Пример:
require.ensure(["./file"], function() {
require("./file2");
});
// is equal to
require.ensure([], function() {
require.include("./file");
require("./file2");
});
require.include может быть полезно, если модуль находится в нескольких дочерних блоках. require.include в родительском блоке включит модуль, а экземпляры модулей в дочерних блоках исчезнут.
Примеры
- Простой
- с bundle-loader
- с контекстом
- с amd и контекстом
- именованные блоки
- несколько входных блоков
- несколько общих блоков
Для демонстрационной версии посетите example-app. Проверьте «Сеть» в DevTools.
© 2012–2015 Tobias Koppers
Licensed under the MIT License.
https://webpack.github.io/docs/code-splitting.html