【问题标题】:Transpiling es6 modules to run in the browser转译 es6 模块以在浏览器中运行
【发布时间】:2020-05-26 13:53:34
【问题描述】:

我有一个使用 es6 模块的应用程序的简单示例,我想将它们转换为 es5(我不想在浏览器中运行模块,尽管我知道它们的支持率为 90%+在此刻)。

我正在兜圈子,遇到同样的错误和问题。
这是我的设置和我想要实现的目标:

//add.js
export function add(x, y) {
  return x + y;
}

//multiply.js
export function multiply(x, y) {
  return x * y;
}

然后我运行 babel 以使用 @babel/preset-env 预设输出一个 bundle.js 文件。

// .babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ]
  ]
}

输出如下:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.add = add;

function add(x, y) {
  return x + y;
}
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.multiply = multiply;

function multiply(x, y) {
  return x * y;
}

当我在浏览器中运行 html 文件时,控制台会记录以下错误:
bundle.js:3 Uncaught ReferenceError: exports is not defined

我的问题是:
babel 输出的是什么?
它们是 commonjs 模块吗?
如何让 es6 模块在浏览器中运行?

【问题讨论】:

  • 1) 请包含您的 babel 配置。 2) 浏览器抛出错误是因为exports 从未被声明,这是"use strict"; 规则下的错误。
  • 几个月前我在你的鞋子里,然后我发现了汇总(允许我完全删除 webpack 和 Babel 直接依赖项)。它的功能较少,但非常轻巧,并提供了一堆插件。听起来你想要的是“umd”构建。
  • @TheJim01 - 我现在已经包含了我的.babelrc 配置文件。你是说 use strict 设置只对这个错误负责吗?我不确定这是否正确,当我手动删除 'use strict' 时,仍然存在相同的错误
  • 是的,那些看起来像 CommonJS 模块。
  • 与其手动删除"use strict";,不如尝试将var exports = {}; 添加为捆绑文件的第二行。 这不是一个解决方案,但该更改应该可以使其发挥作用。

标签: javascript webpack ecmascript-6 babeljs


【解决方案1】:

"esmodules": true" 错误。

当指定"esmodules": true" 时,浏览器目标将被忽略并且脚本不会被转译为 es5。输出取决于您的 target 值。现代浏览器原生处理 es6 模块,最好的方法是转译不同于旧版浏览器(ie11)的现代浏览器并加载特定的脚本,例如

// low transpiled (loads only in modern browser)
<script type="module" src="/assets/scripts/main.js"></script>

// full transpiled (loads only in legacy browser) --> polyfill this bundle
<script nomodule src="/assets/scripts/main.legacy.js" defer></script> 

// https://github.com/unic/darvin-webpack-boilerplate/blob/master/webpack/settings/javascript/babel-config.js
const modern = {
  presets: [
    ["@babel/preset-env", {
      // define transpile level
      targets: {
        browsers: [
          "> 1% in EU",
          "not ie 11",
          "not dead"
        ]
      },
      useBuiltIns: "usage",
      corejs: 3,
    }]
  ],
  plugins: [
    "@babel/plugin-syntax-dynamic-import",
    "transform-eval"
  ],
  comments: false,
  cacheDirectory: path.join(CACHE_PATH, 'babel-loader')
};

const legacy = {
  presets: [
    ["@babel/preset-env", {
      // define transpile level
      targets: {
        browsers: [
          "> 1% in CH",
          "ie >= 11",
          "not dead"
        ]
      },
      useBuiltIns: "usage",
      corejs: 3,
    }]
  ],
  plugins: [
    "@babel/plugin-syntax-dynamic-import",
    "transform-eval"
  ],
  comments: false,
  cacheDirectory: path.join(CACHE_PATH, 'babel-loader')
};

请查看babel documentation了解更多信息。

【讨论】:

  • 感谢您抽出宝贵时间回答@tfr。我知道您可以使用 nomodule 浏览器的回退,但我想总体问题是如何为旧浏览器填充 esmodules。如果我这样做了,我就不需要模块 nomodule 模式。另外,我在圈子里尝试不同的选择。 esmodules: false 似乎没有改变任何输出
  • esmodules: false 和 add target 是正确的答案。如何 polyfill 是另一个话题
猜你喜欢
  • 2017-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 2015-07-31
  • 2020-10-24
  • 2017-04-12
相关资源
最近更新 更多