Safari中CSSStyleSheet非法构造函数错误及Webpack适配方案咨询
我正在使用NodeJS开发一款JS应用,通过Webpack构建,核心用Web Components实现。组件代码示例如下:
import style from "./inboxScreen.css" assert { type: "css" }; export class InboxScreen extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }) this.shadowRoot.adoptedStyleSheets.push(style); this.shadowRoot.innerHTML = ` `; } } customElements.define("inbox-screen", InboxScreen);
应用在Chrome、Firefox和Edge中运行正常,但在Safari里抛出TypeError: Illegal constructor错误,报错的压缩后代码行指向:
r.push([e.id, ":host { width: 100%; font-size: 14px; color: grey; } .pending { color: orange; } .total { color: green; } .normal-state { display: none; } .normal-state.active { display: block; } .retrieval-state { display: none; } .retrieval-state.active { display: block; animation: flash 2s infinite alternate; } @keyframes flash { 0% { color: grey; } 50% { color: white; } 100% { color: grey; } } .polling-state { display: none; } .polling-state.active { display: flex; } ", ""]); var o = new CSSStyleSheet; o.replaceSync(r.toString()); // illegal constructor
当前Webpack配置规则:
rules: [ { assert: { type: "css" }, loader: "css-loader", options: { exportType: "css-style-sheet", }, }, ],
已知Safari不支持assert { type: "css" }语法,请问能否通过调整Webpack配置解决该问题?
可以通过调整Webpack配置解决,核心思路是避开Safari不支持的assert { type: "css" }语法,同时保留adoptedStyleSheets的使用,具体调整如下:
移除import语句中的assert断言
把组件里的import style from "./inboxScreen.css" assert { type: "css" };改成普通的CSS导入:import style from "./inboxScreen.css";修改Webpack的css-loader配置
去掉assert规则,同时保留exportType: "css-style-sheet",让css-loader直接导出CSSStyleSheet实例,无需依赖原生的assert语法:rules: [ { test: /\.css$/i, loader: "css-loader", options: { exportType: "css-style-sheet", }, }, ],兼容Safari的CSSStyleSheet构造
如果调整后仍有new CSSStyleSheet的兼容性问题,可以添加一个简单的兼容逻辑(直接写在组件或入口文件中):if (!window.CSSStyleSheet || typeof CSSStyleSheet !== 'function') { window.CSSStyleSheet = class CSSStyleSheet { constructor() { this.adoptedStyleSheet = document.createElement('style'); document.head.appendChild(this.adoptedStyleSheet); this.cssRules = this.adoptedStyleSheet.sheet.cssRules; } replaceSync(cssText) { this.adoptedStyleSheet.textContent = cssText; } }; }
这样调整后,Webpack会通过css-loader直接处理CSS并生成兼容的CSSStyleSheet实例,无需依赖Safari不支持的assert语法,同时保持Web Components的样式隔离逻辑不变。
内容的提问来源于stack exchange,提问作者20MillionMax

