Spec-Zone.ru › webpack 4

Методы модулей

В этом разделе описаны все методы, доступные в коде, скомпилированном с помощью webpack. При использовании webpack для сборки вашего приложения, вы можете выбрать различные стили синтаксиса модулей, включая ES6, CommonJS и AMD.

Хотя webpack поддерживает несколько синтаксических стилей модулей, мы рекомендуем придерживаться одного синтаксиса для обеспечения согласованности и избежания странного поведения/ошибок. Вот пример смешивания ES6 и CommonJS, но, безусловно, существуют и другие.

ES6 (Рекомендуется)

Версия 2 webpack поддерживает синтаксис модулей ES6 напрямую, что означает, что вы можете использовать import и export без инструмента, такого как babel, для обработки этого за вас. Имейте в виду, что вам все равно, вероятно, понадобится babel для других функций ES6+. Следующие методы поддерживаются webpack:

import

Статически import экспорты другого модуля.

import MyModule from './my-module.js';
import { NamedExport } from './other-module.js';

Ключевое слово здесь — статически. Обычное import выражение не может использоваться динамически в других логических операциях или содержать переменные. См. спецификацию для получения дополнительной информации и import() ниже для динамического использования.

export

Экспортируйте всё как default или именованный экспорт.

// Named exports
export var Count = 5;
export function Multiply(a, b) {
  return a * b;
}

// Default export
export default {
  // Some data...
};

import()

function(string path):Promise

Динамическая загрузка модулей. Вызовы import() обрабатываются как точки разделения, что означает, что запрашиваемый модуль и его дочерние элементы разделены в отдельный фрагмент.

Спецификация загрузчика ES2015 ES2015 Loader spec определяет import() как метод динамической загрузки модулей ES2015 во время выполнения.

if ( module.hot ) {
  import('lodash').then(_ => {
    // Do something with lodash (a.k.a '_')...
  });
}

Эта функция опирается на Promise внутри. Если вы используете import() со старыми браузерами, помните о необходимости подмены Promise с помощью полифилла, такого как es6-promise или promise-polyfill.

Динамические выражения в import()

Невозможно использовать полностью динамическое выражение import, например import(foo). Поскольку foo может потенциально представлять любой путь к любому файлу в вашей системе или проекте.

Выражение import() должно содержать хотя бы некоторую информацию о том, где находится модуль. Сборка может быть ограничена определённой директорией или набором файлов, чтобы при использовании динамического выражения — каждый модуль, который может быть запрошен в вызове import(), был включён. Например, import(`./locale/${language}.json`) приведет к тому, что каждый .json файл в директории ./locale будет включён в новый фрагмент. Во время выполнения, когда переменная language была вычислена, любые файлы, такие как english.json или german.json будут доступны для использования.

// imagine we had a method to get language from cookies or other storage
const language = detectVisitorLanguage();
import(`./locale/${language}.json`).then(module => {
  // do something with the translations
});

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

Магические комментарии

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

// Single target
import(
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  'module'
);

// Multiple possible targets
import(
  /* webpackInclude: /\.json$/ */
  /* webpackExclude: /\.noimport\.json$/ */
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  /* webpackPrefetch: true */
  /* webpackPreload: true */
  `./locale/${language}`
);
import(/* webpackIgnore: true */ 'ignored-module.js');

webpackIgnore: Отключает разбор динамического импорта, когда установлено значение true.

Обратите внимание, что установка webpackIgnore в true отключает разделение кода.

webpackChunkName: Имя для нового фрагмента. С webpack 2.6.0 поддерживаются замены [index] и [request] в строке для увеличения номера или фактического решённого имени файла соответственно. Добавление этого комментария вызовет присвоение отдельному фрагменту имени [my-chunk-name].js вместо [id].js.

webpackMode: С webpack 2.6.0 можно указать различные режимы для разрешения динамических импортов. Поддерживаются следующие опции:

  • "lazy" (по умолчанию): Создаёт загружаемый по запросу фрагмент для каждого import() модуля.
  • "lazy-once": Создаёт единственный загружаемый по запросу фрагмент, который может удовлетворить все вызовы import(). Фрагмент будет загружен при первом вызове import(), а последующие вызовы import() будут использовать тот же ответ от сети. Обратите внимание, что это имеет смысл только в случае частично динамического выражения, например import(`./locales/${language}.json`), где может быть запрошено несколько путей к модулям.
  • "eager": Не создаёт дополнительных фрагментов. Все модули включаются в текущий фрагмент, и дополнительные запросы к сети не производятся. Возвращается Promise, но он уже разрешен. В отличие от статического импорта, модуль не выполняется до вызова import().
  • "weak": Пытается загрузить модуль, если функция модуля уже загружена каким-то другим способом (например, другой фрагмент импортировал его или скрипт, содержащий модуль, был загружен). Возвращается Promise, но успешно разрешается только если фрагменты уже на клиенте. Если модуль недоступен, Promise отклоняется. Запрос к сети никогда не будет выполнен. Это полезно для универсальной отрисовки, когда необходимые фрагменты всегда вручную предоставляются в начальных запросах (встроены в страницу), но не в случаях, когда навигация по приложению вызовет импорт, который изначально не был предоставлен.

webpackPrefetch: Сообщает браузеру, что ресурс, вероятно, потребуется для какой-то навигации в будущем. Для получения дополнительной информации см. руководство по работе webpackPrefetch.

webpackPreload: Сообщает браузеру, что ресурс может потребоваться во время текущей навигации. Для получения дополнительной информации см. руководство по работе webpackPreload.

Обратите внимание, что все опции могут быть объединены, например /* webpackMode: "lazy-once", webpackChunkName: "all-i18n-data" */. Это заключено в объект JavaScript и выполняется с использованием node VM. Вам не нужно добавлять фигурные скобки.

webpackInclude: Регулярное выражение, которое будет проверяться при разрешении импорта. Только модули, которые соответствуют шаблону, будут включены в сборку.

webpackExclude: Регулярное выражение, которое будет проверяться при разрешении импорта. Любые модули, которые соответствуют шаблону, не будут включены в сборку.

Обратите внимание, что опции webpackInclude и webpackExclude не влияют на префикс. Например: ./locale.

Использование System.import в webpack не соответствовало предлагаемой спецификации, поэтому оно было устаревшим в webpack 2.1.0-beta.28 в пользу import().

CommonJS

Целью CommonJS является определение экосистемы для JavaScript вне браузера. Следующие методы CommonJS поддерживаются webpack:

require

require(dependency: String);

Синхронно извлекает экспорты из другого модуля. Компилятор обеспечит наличие зависимости в выходном пакете.

var $ = require('jquery');
var myModule = require('my-module');

Использование его асинхронно может не иметь ожидаемого эффекта.

require.resolve

require.resolve(dependency: String);

Синхронно извлекает идентификатор модуля. Компилятор обеспечит наличие зависимости в выходном пакете. См. module.id для получения дополнительной информации.

Идентификатор модуля — это число в webpack (в отличие от NodeJS, где это строка — имя файла).

require.cache

Несколько запросов к одному и тому же модулю приводят к выполнению только одного модуля и только одному экспорту. Поэтому в runtime существует кэш. Удаление значений из этого кэша вызывает новое выполнение модуля и новый экспорт.

Это необходимо только в редких случаях для совместимости!

var d1 = require('dependency');
require('dependency') === d1;
delete require.cache[require.resolve('dependency')];
require('dependency') !== d1;
// in file.js
require.cache[module.id] === module;
require('./file.js') === module.exports;
delete require.cache[module.id];
require.cache[module.id] === undefined;
require('./file.js') !== module.exports; // in theory; in praxis this causes a stack overflow
require.cache[module.id] !== module;

require.ensure

require.ensure() специфично для webpack и заменено на import().

require.ensure(
  dependencies: String[],
  callback: function(require),
  errorCallback: function(error),
  chunkName: String
)

Выделяет указанный dependencies в отдельный пакет, который будет загружен асинхронно. При использовании синтаксиса модулей CommonJS это единственный способ динамической загрузки зависимостей. Это означает, что этот код может быть запущен в процессе выполнения, загружая dependencies только при определённых условиях.

Эта функция опирается на Promise внутри. Если вы используете require.ensure со старыми браузерами, помните о необходимости подмены Promise с помощью полифилла, такого как es6-promise или promise-polyfill.

var a = require('normal-dep');

if ( module.hot ) {
  require.ensure(['b'], function(require) {
    var c = require('c');

    // Do something special...
  });
}

В следующих параметрах поддерживается указанный выше порядок:

  • dependencies: Массив строк, объявляющий все модули, необходимые для выполнения кода в callback.
  • callback: Функция, которую webpack выполнит после загрузки зависимостей. Реализация функции require передаётся как параметр этой функции. Функция может использовать это для дальнейшей require() необходимых ей модулей для выполнения.
  • errorCallback: Функция, выполняемая, когда webpack не может загрузить зависимости.
  • chunkName: Имя созданного этим вызовом require.ensure() фрагмента. Передавая одно и то же chunkName в различные вызовы require.ensure(), мы можем объединить их код в один фрагмент, что приводит к одной сборке, которую браузер должен загрузить.

Хотя реализация require передаётся в качестве аргумента функции callback, использование произвольного имени, например, require.ensure([], function(request) { request('someModule'); }), не обрабатывается статическим анализатором webpack. Используйте require вместо этого, например require.ensure([], function(require) { require('someModule'); }).

AMD

Asynchronous Module Definition (AMD) — это спецификация JavaScript, определяющая интерфейс для написания и загрузки модулей. Следующие методы AMD поддерживаются webpack:

define (с фабрикой)

define([name: String], [dependencies: String[]], factoryMethod: function(...))

Если dependencies предоставлены, factoryMethod будет вызван с экспортом каждой зависимости (в том же порядке). Если dependencies не предоставлены, factoryMethod вызывается с require, exports и module (для совместимости!). Если эта функция возвращает значение, это значение экспортируется модулем. Компилятор гарантирует, что каждая зависимость доступна.

Обратите внимание, что webpack игнорирует аргумент name.

define(['jquery', 'my-module'], function($, myModule) {
  // Do something with $ and myModule...

  // Export a function
  return function doSomething() {
    // ...
  };
});

Это НЕ может использоваться в асинхронной функции.

define (со значением)

define(value: !Function)

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

define({
  answer: 42
});

Это НЕ может использоваться в асинхронной функции.

require (amd-version)

require(dependencies: String[], [callback: function(...)])

Подобно require.ensure, это разделит предоставленный dependencies в отдельный пакет, который будет загружен асинхронно. callback будет вызван с экспортом каждой зависимости в массиве dependencies.

Эта функция использует Promise в качестве внутренней реализации. Если вы используете AMD в старых браузерах (например, Internet Explorer 11), помните о необходимости подмены Promise с помощью полифилла, такого как es6-promise или promise-polyfill.

require(['b'], function(b) {
  var c = require('c');
});

Нет возможности указать имя пакета.

Именованные модули

Внутренняя LabeledModulesPlugin позволяет использовать следующие методы для экспорта и импорта внутри ваших модулей:

export метки

Экспортировать данную value. Метка может стоять перед объявлением функции или переменной. Имя функции или переменной — это идентификатор, под которым экспортируется значение.

export: var answer = 42;
export: function method(value) {
  // Do something...
};

Использование в асинхронных функциях может привести к непредсказуемым результатам.

require метки

Сделать все экспорты из зависимости доступными в текущей области видимости. Метка require может стоять перед строкой. Зависимость должна экспортировать значения с меткой export. Модули CommonJS или AMD использовать нельзя.

some-dependency.js

export: var answer = 42;
export: function method(value) {
  // Do something...
};
require: 'some-dependency';
console.log(answer);
method(...);

Webpack

Помимо синтаксисов модулей, описанных выше, webpack также позволяет использовать несколько пользовательских методов, специфичных для webpack:

require.context

require.context(
  directory: String,
  includeSubdirs: Boolean /* optional, default true */,
  filter: RegExp /* optional, default /^\.\/.*$/, any file */,
  mode: String  /* optional, 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once', default 'sync' */
)

Указать целую группу зависимостей, используя путь к directory, опцию для includeSubdirs, filter для более тонкого управления включаемыми модулями и mode для определения способа работы загрузки. Подлежащие модули затем можно легко разрешить позже:

var context = require.context('components', true, /\.html$/);
var componentA = context.resolve('componentA');

Если mode указано как "lazy", подлежащие модули будут загружаться асинхронно:

var context = require.context('locales', true, /\.json$/, 'lazy');
context('localeA').then(locale => {
  // do something with locale
});

Полный список доступных режимов и их поведение описан в документации import().

require.include

require.include(dependency: String)

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

require.include('a');
require.ensure(['a', 'b'], function(require) { /* ... */ });
require.ensure(['a', 'c'], function(require) { /* ... */ });

Это приведёт к следующему выводу:

  • пакет входа: file.js и a
  • анонимный пакет: b
  • анонимный пакет: c

Без require.include('a') он был бы дублирован в обоих анонимных пакетах.

require.resolveWeak

Аналогично require.resolve, но это не включит module в пакет. Это считается "слабой" зависимостью.

if(__webpack_modules__[require.resolveWeak('module')]) {
  // Do something when module is available...
}
if(require.cache[require.resolveWeak('module')]) {
  // Do something when module was loaded before...
}

// You can perform dynamic resolves ("context")
// just as with other require/import methods.
const page = 'Foo';
__webpack_modules__[require.resolveWeak(`./page/${page}`)];

require.resolveWeak — основа универсального рендеринга (SSR + разделение кода), используемого в таких пакетах, как react-universal-component. Это позволяет коду рендерить синхронно как на сервере, так и при начальной загрузке на клиенте. Требует, чтобы пакеты вручную обслуживались или каким-то образом были доступны. Способен требовать модули, не указывая, что они должны быть объединены в пакет. Используется совместно с import(), который подхватывает ситуацию, когда навигация пользователя запускает дополнительные импорты.

Дополнительные материалы

  • CommonJS Википедия
  • Asynchronous Module Definition

© JS Foundation and other contributors
Licensed under the Creative Commons Attribution License 4.0.
https://v4.webpack.js.org/api/module-methods

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API