Сделать вывод библиотеки webpack совместимым с babel6
Babel 6-я версия изменяет работу export default
и, в частности, ее связь с commonjs require
.
Подводя итог, пока до babel5, require('module')
, где предоставляется экспорт по умолчанию модуля, он теперь всегда возвращает объект модуля, содержащий все экспортные данные модуля.
Если требуется только по умолчанию, он должен использовать require('module').default
.
Как объясняется здесь, для этого есть очень веские причины, и цель этого вопроса заключается не в том, чтобы сломать или взломать это поведение.
Однако, если вы создаете библиотеку, он обычно не хочет распространять модуль, а значение экспорта его библиотеки (например, функция, независимо от того, какая система модулей используется внутри).
Это хорошо рассмотрено webpack и конфигурацией output.library
при использовании commonjs или AMD. Поскольку предыдущие версии babel разрешали экспорт по умолчанию с помощью commonjs, babel также был совместим с этим механизмом. Однако это уже не так: теперь библиотека всегда предоставляет объект модуля es6.
Вот пример.
SRC/main.js
export default "my lib content";
webpack.config.js
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
lib: [ path.resolve(__dirname, "src/main.js") ],
},
output: {
path: path.join(__dirname, "dist"),
filename: "mylib-build.js",
library: 'myLib'
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel",
include: path.join(__dirname, "src"),
query: { presets: ['es2015'] }
}
]
}
};
test.html
<html>
<head></head>
<body>
<script src="dist/mylib-build.js"></script>
<!-- `myLib` will be attached to `window` -->
<script>
console.log(JSON.stringify(myLib)); // { default: "my lib content" }
</script>
</body>
</html>
Это очень простой пример, но я, очевидно, хочу, чтобы экспорт mylib был строкой "my lib content"
вместо { default: "my lib content" }
.
Одним из решений может быть создание исходного файла экспорта в commonjs для выполнения преобразования:
module.exports = require('./main').default;
Однако я нахожу это решение довольно плохим. Нужно уметь решать его на уровне компиляции без изменения исходного кода.
Любая идея?
Ответы
Ответ 1
Webpack 2 теперь поддерживает модули es6, которые частично решают эту проблему. Миграция из webpack 1 в webpack 2 относительно безболезненна. Нужно просто запомнить отключить модуль babel es6 для преобразования commonjs, чтобы сделать эту работу:
.babelrc
{
"presets": [
["es2015", {"modules": false}]
]
}
Однако, к сожалению, он не работает должным образом с экспортом по умолчанию (но проблема открыта, надеюсь, что решение будет выпущено в конце концов).
ИЗМЕНИТЬ
Хорошие новости! Webpack 3 поддерживает параметр output.libraryExport
, который может использоваться для прямого экспорта экспорта по умолчанию:
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
lib: [ path.resolve(__dirname, "src/main.js") ],
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "mylib-build.js",
library: "myLib",
// Expose the default export.
libraryExport: "default"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel",
include: path.resolve(__dirname, "src")
}
]
}
};
Ответ 2
Я просто занимался этим. Можно ли назвать это обходным решением или решением, похоже, есть плагин Babel, который "решает его".
Используя плагин babel-plugin-add-module-exports, как указано в fooobar.com/questions/357721/...
Пример конфигурации
var webpackOptions = {
entry: {
Lib1: './src/Lib1.js',
Lib2: './src/Lib2.js'
},
output: {
filename: "Master.[name].js",
library: ["Master","[name]"],
libraryTarget: "var"
},
module: {
loaders: [
{
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ["add-module-exports"]
}
}
]
}
};
Это дает Master.Lib1
как lib1 вместо Master.Lib1.default
.
Ответ 3
Вы можете использовать это решение (это больше похоже на обходной путь, но это позволяет вам не изменять ваши источники):
Существует загрузчик callback-loader. Это позволяет вам изменять источники в течение времени сборки, вызывая обратный вызов и вместо этого ставьте результат. Другими словами, вы можете превратить все require('module')
в require('module').default
автоматически во время сборки.
Вот ваш конфиг для этого:
var webpackConfig = {
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'callback' },
...
]
},
...
callbackLoader: {
require: function() {
return 'require("' + Array.prototype.join.call(arguments, ',') + '").default';
}
}
};