使用webpack输出ES模块

Mic*_*ski 40 javascript ecmascript-6 webpack webpack-2 es6-modules

使用Rollup,只需将format选项设置为,即可输出ES模块'es'.我怎么能用webpack做同样的事情?如果现在不可能,webpack是否有计划添加它?

我在文档中output.libraryTarget找到的唯一提到ES模块的是:

libraryTarget: "commonjs-module"- 使用module.exports对象(output.library被忽略)公开它,__esModule被定义(它在互操作模式下作为ES2015模块线程化)

但是,这对我来说还不太清楚.是否libraryTarget: "commonjs2"__esModule定义的唯一差异相同?什么是"互操作模式"?

Pri*_*dya 20

首先,我想说明commonJS和之间的区别commonJS2

CommonJS不支持使用module.exports = function() {}node.js和许多其他commonJS实现.

Webpack2采用捆绑库代码的概念并广泛使用它,并使其兼容在不同环境中工作,我们使用 - libraryTarget选项

现在这里的部分将回答你的两个问题

支持的可能库选项webpack2

  • libraryTarget: "umd", // enum
  • libraryTarget: "umd-module", // ES2015 module wrapped in UMD
  • libraryTarget: "commonjs-module", // ES2015 module wrapped in CommonJS
  • libraryTarget: "commonjs2", // exported with module.exports
  • libraryTarget: "commonjs", // exported as properties to exports
  • libraryTarget: "amd", // defined with AMD defined method
  • libraryTarget: "this", // property set on this
  • libraryTarget: "var", // variable defined in root scope

Interlop具有以下含义

为了鼓励使用CommonJSES6模块,除了如下例所示,在设置时不会设置default export其他模块exports module.exportsexports["default"]

export default test;
exports["default"] = test;
module.exports = exports["default"];
Run Code Online (Sandbox Code Playgroud)

所以基本上它意味着commonJS-module可以通过使用包含在commonJS中的with ES2015模块暴露来使用它module.exportsinterloping

有关这方面的更多信息interloping可以在这篇博文中找到,也可以在stackoverflow 链接中找到.

其基本思想是在ES6 运行时导出和导入属性不能改变,但commonJS 能正常工作要求改变在运行时发生,因此它具有ES2015interlopedCommonJS的.

更新

Webpack 2 提供了创建可捆绑和包含的库的选项.

如果希望模块在不同的环境中使用,则可以通过添加库选项将其捆绑为库,并将其输出到特定环境.文档中提到的过程.

关于如何使用commonjs-module的另一个简单示例

这里要注意的重点是babel添加exports.__esModule = true到每个es6 module并在导入它时_interopRequire要检查该属性.

__esModule = true需要仅在库导出时设置.它需要exports入口模块上设置.内部模块不需要__esModule,它只是一个babel hack.

如文档中所述

__esModule已定义(在互操作模式下为ES2015模块)

测试用例中提到的用法

export * from "./a";
export default "default-value";
export var b = "b";

import d from "library";
import { a, b } from "library";
Run Code Online (Sandbox Code Playgroud)

  • 您能否回答我的主要问题:是否可以使用webpack输出ES模块?另外,`commonjs-module`如何与命名导出一起使用? (2认同)
  • `commonjs-module` 和 `commonjs2` [此时显然是等效的](https://github.com/webpack/webpack/issues/3559#issuecomment-268965473),前者可能已被弃用。 (2认同)

Max*_*jev 14

Webpack2还没有相关的libraryTarget,它不输出ES6包.从另一方面如果您在CommonJS捆绑包中捆绑您的库将无法运行Tree Shaking,无法消除未使用的模块.这是由于ES模块仍在开发中,因此没有人将ES捆绑包发布到浏览器,而webpack主要用于创建支持浏览器的捆绑包.

另一方面,如果您要发布库,则可以提供CommonJS(umd)和ES目标,这要归功于包中的"module"键.杰森.实际上你不需要webpack来发布ES目标,所有你需要做的就是在每个文件上运行babel以使其达到es2015标准,例如,如果你使用的是反应,你可以用"反应"预设运行babel.如果你的源代码已经是没有额外功能的ES 2015,你可以直接将模块指向你的src/index.js:

//package.json
...
  "module": "src/index.js"
  "main": "dist/your/library/bundle.js
...
Run Code Online (Sandbox Code Playgroud)

我发现使用babel来处理export v from 'mod'我的主index.js中的指令很方便,所以我有1个模块文件导出我的所有模块.这是通过babel-plugin-transform-export-extensions实现的(也包含在stage-1预设中).

我从react-bootstrap库中发现了这种方法,你可以在他们的github中看到脚本(它们是webpack1).我已经在react-sigma repo中改进了一些脚本,随意复制以下文件,这些文件可以满足您的需求:

config/babel.config.js
scripts/buildBabel.js
scripts/es/build.js
scripts/build.js // this is command line controller, if you need just ES you don't need it
Run Code Online (Sandbox Code Playgroud)

另外看一下lib目标(scripts/lib/build.js和.babelrc),我提供了lib转换模块,因此即使没有ES明确指定require("react-sigma/lib/Sigma /"),库用户也只能包含他们需要的模块. ,如果你的lib很重且模块化,特别有用!

  • node_modules 从 babel-loader 中排除,因为库已经转译了,我们不需要 babel 那里。如果源需要导入图像或其他资产配置,则应使用适当的加载器扩展,例如 file-loader 或 sass-loader ,如果需要,设置为包含 node_modules。参考图像或 css 的好做法是将所有静态内容复制到您的应用程序静态文件夹中。 (2认同)
  • 这样做的缺点是,如果您正在构建一个组件库或导入其他资产的类似类型的模块,则每个使用您的模块的应用程序都必须配置所有适当的加载器。它给应用程序的 Webpack 配置增加了很多麻烦,而且它很脆弱,因为该库可能只与特定版本的插件/加载器兼容。最好使用 webpack 而无需捆绑/转换为 CJS,同时在构建库时仍将非 JS 模块转换为可导入的等效模块 (2认同)

Bil*_*ese 14

使用最新的 Webpack V5(截至 2022 年 9 月),您可以执行以下操作:

module.exports = {
  entry: ["./src/index.ts"],


  experiments: {
    outputModule: true,
  },

  output: {
    path: `${__dirname}/dist/myOutputFile.mjs`,
    library: {
      type: "module",
    },
  },
};
Run Code Online (Sandbox Code Playgroud)

我还设置devtool: false并用于externals将 React 之类的东西排除在捆绑包之外。

有关更多详细信息,请参阅https://github.com/webpack/webpack/issues/2933https://webpack.js.org/configuration/output/#outputlibrarytype 。


col*_*lxi 8

如果你不介意在你的包中添加一个额外的文件,你可以使用这个解决方法作为一个解决方案,允许你将 Webpack 包作为 ES6 模块分发/导入

配置

webpack.config.js

output: {
    path: path.resolve('./dist'),
    filename: 'bundle.js',
    library: '__MODULE_DEFAULT_EXPORT__',
    libraryTarget: 'window',
    libraryExport: 'default'
  },
Run Code Online (Sandbox Code Playgroud)

./dist/index.js(我们需要创建这个文件)

import './bundle.js'
const __MODULE_DEFAULT_EXPORT__ = window.__MODULE_DEFAULT_EXPORT__
delete window.__MODULE_DEFAULT_EXPORT__
export default __MODULE_DEFAULT_EXPORT__
Run Code Online (Sandbox Code Playgroud)

package.json(如果你要分发你的模块很重要)

  "main": "dist/index.js",
Run Code Online (Sandbox Code Playgroud)

这个怎么运作 :

  • Webpack/dist/bundle.js使用windowaslibraryTarget方法将包输出到。根据我的配置,这使得包默认导出window.__MODULE_DEFAULT_EXPORT__在导入后立即可用。
  • 我们创建了一个自定义的“loader” : ./dist/index.js,它导入/dist/bundle.js、选择window.__MODULE_DEFAULT_EXPORT__、从window对象中删除它(清理),将它分配给一个局部变量,然后将它作为 ES6 导出导出。
  • 我们配置我们package.json的指向我们的“加载器”:./dist/index.js
  • 我们现在可以执行常规 import MyDefaultExportName from './dist/index.js'

注意:这个解决方案 - 因为它在这里公开 - 远非完美,并且有一些缺点和局限性。虽然有改进的空间:)

  • 这非常有用。令人难以置信的是,webpack 仍然没有打包为模块的选项。 (2认同)

Nat*_*vin 7

什么是最好的非 hacky 解决方案?

显然,此功能将在 Webpack 5 中出现

更新:Webpack 5 已发布,但仍不支持此行为

更新 2:看到这条评论,它看起来很快就会到来。

现在,我们可以使用这篇博文中描述的步骤来使用允许输出 ES 模块的插件。

当使用上面的博客文章时(文章的示例代码有点偏离)我们首先运行

npm i -D @purtuga/esm-webpack-plugin
Run Code Online (Sandbox Code Playgroud)

然后我们可以设置webpack.config.js如下:

npm i -D @purtuga/esm-webpack-plugin
Run Code Online (Sandbox Code Playgroud)

然后我们就可以正常使用该文件了。

const EsmWebpackPlugin = require("@purtuga/esm-webpack-plugin");
module.exports = {
    mode: "development",
    entry: "index.js",
    output: {
        filename: "consoleUtils.js",
        library: "LIB",
        libraryTarget: "var"
    },
    //...
    plugins: [
        new EsmWebpackPlugin()
    ]
}
Run Code Online (Sandbox Code Playgroud)

另请参阅跟踪此功能的此问题

  • 考虑到 Webpack 目前不支持此功能,所有解决方案都将始终是 hacky 的。与您的提案的唯一区别是插件采用了 hacky 方法,而不是您直接采用的方法。 (3认同)
  • @colxi 当然,该插件的真正解决方案是很hacky的,但是**我们不必处理任何hacky**。这对于初学者来说特别容易,因为这是一个非常小的修改。 (2认同)