Формат var — один из самых старых способов экспорта
библиотеки в Webpack. Он создаёт глобальную переменную, доступную после
подключения бандла в браузере.
module.exports = {
output: {
filename: 'library.js',
library: 'MyLibrary',
libraryTarget: 'var',
},
};
После подключения файла:
<script src="library.js"></script>
в глобальной области появится переменная:
MyLibrary
Webpack создаёт обычную переменную:
var MyLibrary = ...
Если библиотека экспортирует объект:
export default {
sum(a, b) {
return a + b;
},
};
то использование выглядит так:
MyLibrary.sum(1, 2);
var не изолирует библиотеку. Если переменная уже
существует:
var MyLibrary = {};
то новое определение может её перезаписать.
Также формат не поддерживает модульные системы:
thisФормат this экспортирует библиотеку как свойство объекта
this.
module.exports = {
output: {
filename: 'library.js',
library: 'MyLibrary',
libraryTarget: 'this',
},
};
this["MyLibrary"] = ...
Значение this зависит от среды выполнения.
В браузере вне strict mode:
this === window;
Поэтому библиотека становится доступной как:
window.MyLibrary
В strict mode:
"use strict";
значение this может быть undefined.
В ES-модулях верхнеуровневый this также равен
undefined.
Из-за этого формат считается ненадёжным для универсальных библиотек.
Иногда применяется:
windowФормат window экспортирует библиотеку напрямую в объект
window.
module.exports = {
output: {
filename: 'library.js',
library: 'MyLibrary',
libraryTarget: 'window',
},
};
Webpack генерирует:
window["MyLibrary"] = ...
<script src="library.js"></script>
window.MyLibrary
или:
MyLibrary
varvar:
var MyLibrary = ...
window:
window.MyLibrary = ...
Главное отличие связано с поведением глобальных переменных.
window.Test = 123;
console.log(Test);
в браузере работает, потому что свойства window
становятся глобальными переменными.
Но:
delete window.Test;
может удалить свойство, тогда как var ведёт себя
иначе.
Формат работает только в браузере.
В Node.js объект window отсутствует:
ReferenceError: window is not defined
globalХотя формат global используется реже, он важен для
серверной среды.
module.exports = {
output: {
library: 'MyLibrary',
libraryTarget: 'global',
},
};
Webpack создаёт:
global["MyLibrary"] = ...
Подходит для:
Не работает в браузере без полифиллов.
commonjscommonjs предназначен для CommonJS-модулей.
module.exports = {
output: {
libraryTarget: 'commonjs',
},
};
exports["default"] = ...
или:
module.exports = ...
в зависимости от структуры экспорта.
const lib = require('./library');
CommonJS использует:
require;module.exports;exports.export function sum(a, b) {
return a + b;
}
После сборки:
const lib = require('./library');
lib.sum(1, 2);
Формат долгое время был стандартом Node.js.
Подходит для:
CommonJS плохо сочетается с tree shaking.
Причина — динамический механизм импорта:
require(variable);
Webpack не всегда может статически определить зависимости.
commonjs2commonjs2 — наиболее распространённый формат для
Node.js-библиотек.
module.exports = {
output: {
libraryTarget: 'commonjs2',
},
};
module.exports = ...
commonjscommonjs:
exports["name"] = value;
commonjs2:
module.exports = value;
При commonjs2 импорт обычно проще:
const lib = require('./library');
без необходимости обращаться к .default.
Исходный код:
export default function () {
return 'hello';
}
Использование:
const hello = require('./library');
hello();
Почти все старые Node.js-библиотеки используют:
commonjs2;amdAMD — Asynchronous Module Definition.
Формат создавался для браузеров до появления ES Modules.
module.exports = {
output: {
library: 'MyLibrary',
libraryTarget: 'amd',
},
};
define("MyLibrary", [], function () {
return ...
});
Требуется AMD-загрузчик:
Пример:
require(['MyLibrary'], function (lib) {
lib.sum(1, 2);
});
AMD поддерживает:
Система стала устаревшей после появления:
Сегодня AMD встречается в legacy-проектах.
umdUMD — Universal Module Definition.
Один из самых важных форматов библиотек.
UMD пытается работать одновременно:
module.exports = {
output: {
filename: 'library.js',
library: 'MyLibrary',
libraryTarget: 'umd',
},
};
Webpack генерирует сложную обёртку:
(function (root, factory) {
if (typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if (typeof define === 'function' && define.amd)
define([], factory);
else if (typeof exports === 'object')
exports["MyLibrary"] = factory();
else
root["MyLibrary"] = factory();
})(self, function () {
return ...
});
UMD поддерживает почти все среды:
| Среда | Поддержка |
|---|---|
| Browser globals | Да |
| CommonJS | Да |
| AMD | Да |
| Node.js | Да |
В браузере:
<script src="library.js"></script>
В Node.js:
const lib = require('./library');
В AMD:
require(['MyLibrary'], function (lib) {
});
umdNamedDefineДополнительная настройка:
output: {
library: 'MyLibrary',
libraryTarget: 'umd',
umdNamedDefine: true,
}
Позволяет задавать имя AMD-модуля:
define('MyLibrary', [], factory);
Без неё модуль может быть анонимным.
UMD создаёт:
В современных проектах всё чаще заменяется ES Modules.
moduleФормат module генерирует настоящий ES Module.
module.exports = {
experiments: {
outputModule: true,
},
output: {
libraryTarget: 'module',
},
};
Без:
experiments.outputModule = true
Webpack выдаст ошибку.
Webpack создаёт:
export
import
вместо:
module.exports
import lib from './library.js';
Webpack может удалять неиспользуемый код:
import { sum } from 'lib';
если:
multiply()
не используется, функция может быть исключена из бандла.
ESM имеет фиксированную структуру:
import ...
export ...
Это улучшает:
Поддержка:
<script type="module">
<script>Требуется:
<script type="module" src="library.js"></script>
Например:
Node.js требует:
.mjs;"type": "module" в package.json.assignassign экспортирует библиотеку присваиванием.
output: {
library: 'MyLibrary',
libraryTarget: 'assign',
}
MyLibrary = ...
Webpack не использует:
var;window;this.Просто выполняется присваивание.
Если переменная не существует:
ReferenceError
или создание неявной глобальной переменной в нестрогом режиме.
| Формат | Browser | Node.js | AMD | ESM | Глобальная переменная |
|---|---|---|---|---|---|
| var | Да | Нет | Нет | Нет | Да |
| this | Да | Частично | Нет | Нет | Да |
| window | Да | Нет | Нет | Нет | Да |
| global | Нет | Да | Нет | Нет | Да |
| commonjs | Нет | Да | Нет | Нет | Нет |
| commonjs2 | Нет | Да | Нет | Нет | Нет |
| amd | Да | Нет | Да | Нет | Нет |
| umd | Да | Да | Да | Нет | Да |
| module | Да | Да | Нет | Да | Нет |
output.libraryПараметр library задаёт имя экспортируемой
библиотеки.
output: {
library: 'Utils',
libraryTarget: 'window',
}
Результат:
window.Utils
libraryНекоторые форматы могут работать без имени:
libraryTarget: 'commonjs2'
потому что экспорт идёт через:
module.exports
output.library.typeНачиная с Webpack 5 рекомендуется использовать новый формат.
output: {
library: 'MyLibrary',
libraryTarget: 'umd',
}
output: {
library: {
name: 'MyLibrary',
type: 'umd',
},
}
Новый API:
Современные библиотеки часто публикуют несколько сборок одновременно.
{
"main": "./dist/index.cjs.js",
"module": "./dist/index.esm.js",
"browser": "./dist/index.browser.js"
}
| Поле | Формат |
|---|---|
| main | CommonJS |
| module | ES Modules |
| browser | Browser build |
Webpack позволяет экспортировать массив конфигураций.
module.exports = [
{
output: {
filename: 'library.umd.js',
library: {
name: 'MyLibrary',
type: 'umd',
},
},
},
{
experiments: {
outputModule: true,
},
output: {
filename: 'library.esm.js',
library: {
type: 'module',
},
},
},
];
Получаются:
Именно такой подход используется во многих крупных библиотеках.