【问题标题】:Make webpack's library output compatible with babel6使 webpack 的库输出兼容 babel6
【发布时间】:2016-02-14 05:10:40
【问题描述】:

Babel 的第 6 版更改了 export default 的功能,尤其是它与 commonjs require 的关系。

总结一下,直到 babel5,require('module') 给出模块的默认导出,它现在总是返回包含模块所有导出的模块对象。 如果只想要默认值,他/她必须使用require('module').defaultAs explained here, there is very good reasons behind this,这个问题的目的不是破坏或破解这种行为。

但是,如果一个人正在构建一个库,他/她通常不想分发一个模块,而是他的库的导出值(例如,一个函数,无论内部使用什么模块系统)。 当使用commonjsAMD 时,webpackoutput.library 配置可以很好地解决这个问题。因为之前的 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;

但是我发现这个解决方案很差。应该能够在编译级别解决它,而无需更改源代码。 有什么想法吗?

【问题讨论】:

  • “应该能够解决它有一个编译选项,而无需更新源代码。有什么想法吗?” 不太确定您期望什么样的答案。如果您认为这应该是一个编译选项,那么您应该向开发人员推荐它。
  • Webpack 配置非常强大。所有加载器都有许多不同的插件和许多不同的参数。
  • 例如,如果一个人只使用默认导出,他可以使用babel-plugin-transform-es2015-modules-commonjs并将他所有的es6包转换为commonjs。
  • 您将以错误的方式进行操作。 Babel 改变了它的行为以更符合规范,你想再次打破它。现在你可以在 ES6 和 CommonJS 之间建立一个隐式的桥梁。那件事module.exports = require('./main').default,导致更少的错误和WTF,而不是以前偷偷摸摸的module.exports = exports.default
  • @vvo 不幸的是还没有......所以我不得不使用导出解决方案来给 webpack 一个 commonjs 模块。

标签: javascript ecmascript-6 webpack babeljs


【解决方案1】:

Webpack 2 现在支持 es6 模块,这部分解决了这个问题。 Migrating from webpack 1 to webpack 2 相对无痛。只需记住disable babel's es6 module to commonjs conversion 即可完成这项工作:

.babelrc

{
  "presets": [
    ["es2015", {"modules": false}]
  ]
}

但是,不幸的是,它在导出默认值下无法正常工作(但an issue is opened,希望最终会发布解决方案)。

编辑

好消息! 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 中引用的插件https://stackoverflow.com/a/34778391/1592572

    示例配置

    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';
            }
        }
    };
    

    【讨论】:

    • 对不起,它不起作用。这会改变模块的加载方式,而不是导出方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多