Недавно я обновился до Webpack 5, и у меня возникли проблемы с импортом модулей UMD.
В частности, я пытаюсь импортировать Leaflet. Leaflet, кажется, экспортирует модуль UMD, созданный rollup.js, который выглядит так:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.L = {})));
}(this, (function (exports) { 'use strict';
[...]
})));
Как видите, он сначала пытается использовать CommonJS (если определены exports
и module
), затем пытается использовать AMD (если определено define
), а в противном случае пытается поместить себя в глобальную область видимости, ссылаясь на this
из модуля. контекст.
Webpack (без всяких загрузчиков) компилирует вот так:
(function (global, factory) {
typeof exports === 'object' && "object" !== 'undefined' ? factory(exports) :
typeof define === 'function' && __webpack_require__.amdO ? define(['exports'], factory) :
(factory((global.L = {})));
}(undefined, (function (exports) { 'use strict';
[...]
})));
Конкретно, что было сделано:
typeof module
на "object"
define.amd
на __webpack_require__.amd0
this
на undefined
Во время сборки webpack выдает мне предупреждение: export 'default' (imported as 'L') was not found in 'leaflet' (possible exports: )
. Когда я открываю скомпилированный пакет в браузере, я получаю сообщение об ошибке Uncaught TypeError: Cannot set property 'L' of undefined
.
Что происходит, так это то, что CommonJS терпит неудачу (потому что exports
не определен), AMD терпит неудачу (потому что define
не определен) и, наконец, установка глобального значения также не выполняется, потому что this
заменяется на undefined
.
Согласно документации Webpack, Webpack должен повсеместно поддерживать импорт модулей CommonJS и AMD, но, похоже, в данном случае ни один из них не работает.
Что я могу сделать, чтобы исправить это?
Я сузил проблему и обнаружил, что проблема была вызвана тем, что я использовал imports-loader
определенным образом.
Перед обновлением я использовал imports-loader
, чтобы добавить все необходимые транзитивные зависимости, которые мои зависимости не импортировали, в частности файлы CSS. Конфигурация выглядела примерно так:
{ module: { rules: [ {
test: //node_modules/leaflet/.*\.js$/,
loader: "imports-loader?asdf=leaflet/dist/leaflet.css"
} ] } }
После обновления webpack больше не принимал строковый синтаксис для загрузчиков, и imports-loader также изменил свой синтаксис, поэтому я изменил его на:
{ module: { rules: [ {
test: //node_modules/leaflet/.*\.js$/,
loader: "imports-loader",
options: {
imports: "default leaflet/dist/leaflet.css asdf"
}
} ] } }
Это, казалось, сделало работу и правильно включило необходимый файл CSS. Однако, когда я обнаружил, что эта часть конфига является причиной проблемы, я углубился в документацию imports-loader. Оказывается, конфигурация, которую я использовал, теперь генерировала следующую строку кода:
import asdf from "leaflet/dist/leaflet.css";
(и я мог бы использовать "side-effects leaflet/dist/leaflet.css"
, чтобы получить тот же результат, не используя asdf
в качестве фиктивного имени импорта). Хотя это правильно импортировало файл CSS, это, вероятно, заставило веб-пакет думать, что этот файл является правильным модулем ES, отключив поддержку модулей CommonJS/AMD/UMD. Я изменил конфигурацию imports-loader на следующее:
{ module: { rules: [ {
test: //node_modules/leaflet/.*\.js$/,
loader: "imports-loader",
options: {
imports: "pure leaflet/dist/leaflet.css",
type: "commonjs"
}
} ] } }
Согласно документам, это создает следующую строку кода:
require("leaflet/dist/leaflet.css");
После внесения этого изменения, кажется, работает без проблем.
Интересно, что кажется, что webpack фактически обнаруживает весь блок UMD, а не просто предоставляет переменные exports
и define
, поэтому теперь он компилирует код Leaflet в это:
(function (global, factory) {
true ? factory(exports) :
0;
}(this, (function (exports) { 'use strict';
[...]
})));