在webpack/babel构建中如何使用CustomElement v1 polyfill?

4
我遇到了一些问题,无法通过webpack在所有设备上正确使用this WebComponents polyfill + native-shim
关于我的设置的一些背景: * Webpack2 + babel-6 * 应用程序是用ES6编写的,转换为ES5 * 导入一个由ES6编写的node_module包,在应用程序中定义/注册了一个CustomElement 因此,相关的webpack dev配置看起来像这样:
const config = webpackMerge(baseConfig, {
  entry: [
    'webpack/hot/only-dev-server',
    '@webcomponents/custom-elements/src/native-shim',
    '@webcomponents/custom-elements',
    '<module that uses CustomElements>/dist/src/main',
    './src/client',
  ],
  output: {
    path: path.resolve(__dirname, './../dist/assets/'),
    filename: 'app.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        options: {
          cacheDirectory: true,
        },
        include: [
          path.join(NODE_MODULES_DIR, '<module that uses CustomElements>'),
          path.join(__dirname, '../src'),
        ],
      },
    ],
  },
...

关键要点: * 我需要在加载使用自定义元素的模块之前加载CustomElement poly * 我需要在我的应用程序源代码之前加载使用自定义元素的模块 * 使用自定义元素的模块是ES6,因此我们正在进行转译(这就是在babel-loader中包含它的原因)。

在现代的ES6浏览器中(如IE桌面版Chrome),以上内容按预期工作,但是

在旧版浏览器中无法正常工作。例如,在iOS 8中,我会遇到以下错误:

SyntaxError: Unexpected token ')'

指向原生shim pollyfill中的匿名函数开头:
(() => {
  'use strict';

  // Do nothing if `customElements` does not exist.
  if (!window.customElements) return;

  const NativeHTMLElement = window.HTMLElement;
  const nativeDefine = window.customElements.define;
  const nativeGet = window.customElements.get;

所以在我看来,native-shim需要被转译成ES5:

        include: [
+         path.join(NODE_MODULES_DIR, '@webcomponents/custom-elements/src/native-shim'),
          path.join(NODE_MODULES_DIR, '<module that uses CustomElements>'),
          path.join(__dirname, '../src'),
        ],

但是现在这样做会导致Chrome和iOS 8出现以下错误:

app.js:1 Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
    at new StandInElement (native-shim.js:122)
    at HTMLDocument.createElement (<anonymous>:1:1545)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:504)
    at Object.mountComponent (ReactReconciler.js:46)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
    at Object.mountComponent (ReactReconciler.js:46)
    at Object.updateChildren (ReactChildReconciler.js:121)
    at ReactDOMComponent._reconcilerUpdateChildren (ReactMultiChild.js:208)
    at ReactDOMComponent._updateChildren (ReactMultiChild.js:312)

这导致我转到原生shim中的constructor()行:

  window.customElements.define = (tagname, elementClass) => {
    const elementProto = elementClass.prototype;
    const StandInElement = class extends NativeHTMLElement {
      constructor() {

哎呀,我真的不太清楚我们如何在基于webpack的构建中包含这个依赖项,因为使用CustomElements的依赖项是ES6的(需要转译)。

  • 将原生的shim转译成es5并不起作用
  • 将原生的shim直接放在捆绑入口处对于iOS8不起作用,但对Chrome起作用
  • 不包括原生的shim会破坏Chrome和iOS的兼容性

我真的对Web组件感到非常沮丧。我只想使用这一个依赖项,它恰好是使用Web组件构建的。如何在webpack构建中使其正常工作,并在所有设备上正常工作?我是否遗漏了什么显而易见的东西?

我的.babelrc配置供后人参考(最相关的是dev配置):

{
  "presets": [
    ["es2015", { "modules": false }],
    "react"
  ],
  "plugins": [
    "transform-custom-element-classes",
    "transform-object-rest-spread",
    "transform-object-assign",
    "transform-exponentiation-operator"
  ],
  "env": {
    "test": {
      "plugins": [
        [ "babel-plugin-webpack-alias", { "config": "./cfg/test.js" } ]
      ]
    },
    "dev": {
      "plugins": [
        "react-hot-loader/babel",
        [ "babel-plugin-webpack-alias", { "config": "./cfg/dev.js" } ]
      ]
    },
    "dist": {
      "plugins": [
        [ "babel-plugin-webpack-alias", { "config": "./cfg/dist.js" } ],
        "transform-react-constant-elements",
        "transform-react-remove-prop-types",
        "minify-dead-code-elimination",
        "minify-constant-folding"
      ]
    },
    "production": {
      "plugins": [
        [ "babel-plugin-webpack-alias", { "config": "./cfg/server.js" } ],
        "transform-react-constant-elements",
        "transform-react-remove-prop-types",
        "minify-dead-code-elimination",
        "minify-constant-folding"
      ]
    }
  }
}

也许这可以帮助:https://dev59.com/N6Dha4cB1Zd3GeqP9hPM#43007474 - Supersharp
@Supersharp 感谢您的评论。看了一下 es5-adapter,它似乎与 custom-elements 存储库中的 native-shim(https://github.com/webcomponents/custom-elements/blob/master/src/native-shim.js)完全相同,这是我在 OP 中提到的。这解决了 ES6 兼容浏览器的问题,但对于旧版 iOS 并不适用。:( - tdc
我不知道它们是否相同,但适配器不应该被转译。 - Supersharp
1个回答

1
我使用以下.babelrc插件管道实现了类似的功能。它看起来唯一的区别是https://babeljs.io/docs/plugins/transform-es2015-classes/https://babeljs.io/docs/plugins/transform-es2015-classes/,但是我真的记不清那些问题具体解决了什么:
{
  "plugins": [
    "transform-runtime",
    ["babel-plugin-transform-builtin-extend", {
      "globals": ["Error", "Array"]
    }],
    "syntax-async-functions",
    "transform-async-to-generator",
    "transform-custom-element-classes",
    "transform-es2015-classes"
  ]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接