output.library: name, type, export

Параметр output.library используется для экспорта собранного бандла как библиотеки. Вместо обычного приложения, которое просто выполняется в браузере, Webpack может сформировать модуль, доступный внешнему коду через глобальную переменную, CommonJS, AMD, UMD или современные ES-модули.

Такой режим применяется при разработке:

  • UI-библиотек;
  • SDK;
  • npm-пакетов;
  • универсальных модулей;
  • микрофронтендов;
  • библиотек компонентов;
  • плагинов;
  • внутренних корпоративных фреймворков.

Webpack позволяет контролировать:

  • имя экспортируемой библиотеки;
  • формат экспорта;
  • экспортируемые сущности;
  • совместимость с различными окружениями.

Базовая структура

Минимальная конфигурация библиотеки:

// webpack.config.js

module.exports = {
    entry: './src/index.js',

    output: {
        filename: 'my-lib.js',

        library: {
            name: 'MyLibrary',
            type: 'umd'
        }
    }
};

После сборки библиотека становится доступной:

<script src="my-lib.js"></script>

<script>
    MyLibrary.someMethod();
</script>

Структура library

В современных версиях Webpack параметр имеет объектную форму:

output: {
    library: {
        name: 'MyLibrary',
        type: 'umd',
        export: 'default'
    }
}

Поддерживаются свойства:

Свойство Назначение
name Имя библиотеки
type Тип экспорта
export Что именно экспортировать

library.name

Назначение

Определяет имя библиотеки в целевом окружении.

Пример:

output: {
    library: {
        name: 'Utils',
        type: 'window'
    }
}

Результат:

window.Utils = ...

Использование:

<script src="bundle.js"></script>

<script>
    Utils.formatDate();
</script>

Формы library.name

Строка

Наиболее распространённый вариант:

name: 'MyLibrary'

Массив

Создание вложенных пространств имён:

name: ['App', 'Utils']

Результат:

window.App = window.App || {};
window.App.Utils = ...

Использование:

App.Utils.method();

Объект

Позволяет задавать разные имена для разных типов библиотек.

library: {
    name: {
        root: 'MyLibrary',
        amd: 'my-library',
        commonjs: 'my-common-library'
    },
    type: 'umd'
}

Это особенно важно при публикации универсальных npm-пакетов.


library.type

Назначение

Определяет способ экспорта библиотеки.

От этого зависит:

  • где будет доступен модуль;
  • как он подключается;
  • какая система модулей используется;
  • как выглядит итоговый bundle.

type: 'var'

Экспорт в переменную

output: {
    library: {
        name: 'MyLibrary',
        type: 'var'
    }
}

Результат:

var MyLibrary = ...

Особенности:

  • простой формат;
  • работает в браузере;
  • создаёт переменную в текущем scope;
  • не подходит для изоляции.

type: 'assign'

Присваивание значения существующей переменной.

library: {
    name: 'MyLibrary',
    type: 'assign'
}

Результат:

MyLibrary = ...

Webpack не создаёт переменную самостоятельно.


type: 'this'

Экспорт в this.

library: {
    name: 'MyLibrary',
    type: 'this'
}

Результат:

this.MyLibrary = ...

Поведение зависит от контекста выполнения.

В браузере:

window.MyLibrary

В strict mode значение this может быть undefined.


type: 'window'

Экспорт в объект window.

library: {
    name: 'MyLibrary',
    type: 'window'
}

Результат:

window.MyLibrary = ...

Используется только в браузере.


type: 'global'

Экспорт в глобальный объект.

library: {
    name: 'MyLibrary',
    type: 'global'
}

Webpack использует globalThis.

Подходит для:

  • браузеров;
  • Node.js;
  • Web Workers.

type: 'commonjs'

Экспорт через CommonJS.

library: {
    type: 'commonjs'
}

Результат:

exports = ...

Чаще используется в Node.js.


type: 'commonjs2'

Наиболее распространённый CommonJS-формат.

library: {
    type: 'commonjs2'
}

Результат:

module.exports = ...

Используется большинством npm-пакетов.


type: 'amd'

Экспорт через AMD.

library: {
    name: 'my-library',
    type: 'amd'
}

Результат:

define('my-library', [], factory);

Подходит для:

  • RequireJS;
  • старых браузерных проектов.

type: 'umd'

Универсальный формат

Самый популярный режим для библиотек.

library: {
    name: 'MyLibrary',
    type: 'umd'
}

UMD автоматически определяет среду:

  • CommonJS;
  • AMD;
  • browser globals.

Webpack генерирует универсальную обёртку:

(function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if(typeof define === 'function' && define.amd)
        define([], factory);
    else
        root["MyLibrary"] = factory();
})(self, () => {});

Преимущества UMD

Кроссплатформенность

Один bundle работает:

  • в браузере;
  • в Node.js;
  • в AMD-loader;
  • в legacy-средах.

Поддержка CDN

Библиотека может подключаться через <script>:

<script src="my-lib.js"></script>

Совместимость с npm

Модуль можно импортировать:

const lib = require('my-lib');

Недостатки UMD

UMD создаёт:

  • более крупный bundle;
  • дополнительную обёртку;
  • legacy-код.

Для современных приложений чаще используют ES Modules.


type: 'module'

Современный формат ES Modules

output: {
    module: true,

    library: {
        type: 'module'
    }
}

Использование:

import { sum } from './my-lib.js';

Особенности ES Modules

Строгие ограничения

Нельзя использовать некоторые legacy-возможности Webpack.


Поддержка tree shaking

ESM позволяет:

  • удалять неиспользуемый код;
  • уменьшать размер bundle;
  • улучшать оптимизацию.

Современный стандарт

Поддерживается:

  • современными браузерами;
  • Vite;
  • Rollup;
  • ESBuild;
  • современным Node.js.

type: 'jsonp'

Редко используемый формат.

library: {
    name: 'MyLibrary',
    type: 'jsonp'
}

Использует JSONP-обёртку.

Практически не применяется в современных проектах.


type: 'system'

Экспорт для SystemJS.

library: {
    type: 'system'
}

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


Сравнение типов библиотек

Тип Браузер Node.js AMD ESM
var Да Нет Нет Нет
window Да Нет Нет Нет
global Да Да Нет Нет
commonjs Нет Да Нет Нет
commonjs2 Нет Да Нет Нет
amd Да Нет Да Нет
umd Да Да Да Нет
module Да Да Нет Да

library.export

Назначение

Позволяет экспортировать конкретную часть модуля.


Экспорт default

Исходный код:

export default {
    sum,
    sub
};

Конфигурация:

library: {
    name: 'MathLib',
    type: 'umd',
    export: 'default'
}

Внешний код получит:

MathLib.sum();

Без export

Если параметр не указан:

library: {
    name: 'MathLib',
    type: 'umd'
}

Экспортируется весь namespace модуля.

Результат:

MathLib.default.sum();

или

MathLib.sum();

в зависимости от конфигурации transpiler.


Экспорт named export

Исходный модуль:

export const utils = {
    format() {}
};

export const api = {};

Конфигурация:

library: {
    name: 'MyLibrary',
    type: 'umd',
    export: 'utils'
}

Результат:

MyLibrary.format();

Экспорт вложенного свойства

Поддерживается массив:

export const tools = {
    math: {
        sum() {}
    }
};
library: {
    export: ['tools', 'math']
}

Результат:

MyLibrary.sum();

Полный пример библиотеки

Исходный код

// src/index.js

export function sum(a, b) {
    return a + b;
}

export function sub(a, b) {
    return a - b;
}

Конфигурация

const path = require('path');

module.exports = {
    mode: 'production',

    entry: './src/index.js',

    output: {
        path: path.resolve(__dirname, 'dist'),

        filename: 'math-lib.js',

        library: {
            name: 'MathLib',
            type: 'umd'
        },

        clean: true
    }
};

Использование через script

<script src="math-lib.js"></script>

<script>
    console.log(MathLib.sum(2, 3));
</script>

Использование через CommonJS

const MathLib = require('./math-lib');

MathLib.sum(2, 3);

Использование через ESM

import * as MathLib from './math-lib.js';

MathLib.sum(2, 3);

Библиотека с default export

Исходный код

function sum(a, b) {
    return a + b;
}

function sub(a, b) {
    return a - b;
}

export default {
    sum,
    sub
};

Конфигурация

library: {
    name: 'MathLib',
    type: 'umd',
    export: 'default'
}

Множественные форматы библиотек

Иногда создают несколько сборок:

module.exports = [
    {
        output: {
            filename: 'lib.umd.js',
            library: {
                name: 'MyLib',
                type: 'umd'
            }
        }
    },

    {
        output: {
            filename: 'lib.esm.js',
            module: true,
            library: {
                type: 'module'
            }
        }
    }
];

Использование с npm-пакетами

Типичная структура:

{
    "main": "dist/lib.cjs.js",
    "module": "dist/lib.esm.js",
    "browser": "dist/lib.umd.js"
}

output.module

Для library.type = 'module' требуется:

output: {
    module: true
}

И дополнительно:

experiments: {
    outputModule: true
}

Полный пример:

module.exports = {
    experiments: {
        outputModule: true
    },

    output: {
        module: true,

        library: {
            type: 'module'
        }
    }
};

Особенности tree shaking библиотек

Webpack может удалять неиспользуемые части библиотеки.

Важно:

{
    "sideEffects": false
}

Совместимость Babel и library export

Babel может изменять структуру export/import.

Например:

exports.default = ...

В результате приходится использовать:

MyLib.default.method();

Для исправления используют:

library: {
    export: 'default'
}

Частые ошибки

Отсутствует library.name

Ошибка:

library: {
    type: 'window'
}

Webpack не знает имя глобальной переменной.

Правильно:

library: {
    name: 'MyLib',
    type: 'window'
}

Использование window в Node.js

Ошибка:

type: 'window'

в серверной среде.

Следствие:

ReferenceError: window is not defined

Неправильный формат для npm

Проблема:

type: 'var'

npm-пакет не работает через require().

Для npm лучше:

type: 'commonjs2'

или:

type: 'umd'

Конфликт глобальных имён

Проблема:

name: 'Utils'

Глобальная переменная уже существует.

Следствие:

  • перезапись данных;
  • конфликты библиотек;
  • трудноуловимые баги.

Лучшие практики

Для npm-библиотек

Рекомендуется:

type: 'umd'

или:

type: 'module'

Для современных библиотек

Предпочтителен ESM:

type: 'module'

Для CDN

Подходит:

type: 'umd'

Для Node.js

Лучший вариант:

type: 'commonjs2'

Практическая схема выбора

Сценарий Рекомендуемый тип
npm package umd / module
Browser CDN umd
Node.js commonjs2
Modern frontend module
Legacy browser umd
RequireJS amd
Global utility window

Современный подход к публикации библиотек

Большинство современных библиотек публикуют:

  • ESM-сборку;
  • CommonJS-сборку;
  • UMD-сборку.

Пример:

dist/
├── library.esm.js
├── library.cjs.js
└── library.umd.js

Это обеспечивает:

  • совместимость;
  • оптимизацию;
  • поддержку старых проектов;
  • поддержку современных bundler-систем.