我遇到了一些问题,无法通过webpack在所有设备上正确使用this WebComponents polyfill + native-shim。
关于我的设置的一些背景: * Webpack2 + babel-6 * 应用程序是用ES6编写的,转换为ES5 * 导入一个由ES6编写的
指向原生shim pollyfill中的匿名函数开头:
关于我的设置的一些背景: * 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"
]
}
}
}