fix(core): make scoped-elements ssr-compatible
fix(core): ssr-support scopedElements
This commit is contained in:
parent
fb3bdd6a17
commit
2c38a919bc
8 changed files with 502 additions and 40 deletions
5
.changeset/clean-chicken-retire.md
Normal file
5
.changeset/clean-chicken-retire.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@lion/ui': patch
|
||||
---
|
||||
|
||||
[core] make scoped-elements ssr-compatible
|
||||
305
package-lock.json
generated
305
package-lock.json
generated
|
|
@ -17,6 +17,7 @@
|
|||
"@changesets/cli": "^2.27.9",
|
||||
"@custom-elements-manifest/analyzer": "^0.10.3",
|
||||
"@custom-elements-manifest/to-markdown": "^0.1.0",
|
||||
"@lit-labs/testing": "^0.2.5",
|
||||
"@open-wc/building-rollup": "^2.2.3",
|
||||
"@open-wc/eslint-config": "^12.0.3",
|
||||
"@open-wc/scoped-elements": "^3.0.5",
|
||||
|
|
@ -3399,12 +3400,271 @@
|
|||
"resolved": "packages/ui",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@lit-labs/ssr": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-3.2.2.tgz",
|
||||
"integrity": "sha512-He5TzeNPM9ECmVpgXRYmVlz0UA5YnzHlT43kyLi2Lu6mUidskqJVonk9W5K699+2DKhoXp8Ra4EJmHR6KrcW1Q==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit-labs/ssr-client": "^1.1.7",
|
||||
"@lit-labs/ssr-dom-shim": "^1.2.0",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@parse5/tools": "^0.3.0",
|
||||
"@types/node": "^16.0.0",
|
||||
"enhanced-resolve": "^5.10.0",
|
||||
"lit": "^3.1.2",
|
||||
"lit-element": "^4.0.4",
|
||||
"lit-html": "^3.1.2",
|
||||
"node-fetch": "^3.2.8",
|
||||
"parse5": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=13.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/ssr-client": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-client/-/ssr-client-1.1.7.tgz",
|
||||
"integrity": "sha512-VvqhY/iif3FHrlhkzEPsuX/7h/NqnfxLwVf0p8ghNIlKegRyRqgeaJevZ57s/u/LiFyKgqksRP5n+LmNvpxN+A==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"lit": "^3.1.2",
|
||||
"lit-html": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/ssr-dom-shim": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz",
|
||||
"integrity": "sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@lit-labs/ssr/node_modules/@types/node": {
|
||||
"version": "16.18.116",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.116.tgz",
|
||||
"integrity": "sha512-mLigUvhoaADRewggiby+XfAAFOUOMCm/SwL5DAJ+CMUGjSLIGMsJVN7BOKftuQSHGjUmS/W7hVht8fcNbi/MRA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lit-labs/ssr/node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/ssr/node_modules/node-fetch": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@lit-labs/testing/-/testing-0.2.5.tgz",
|
||||
"integrity": "sha512-VVYPhnpYhTgmZ3pWGQV8ZN/c81/aUlxSya+G94pNhlAiKUqsAwJZAkQCEZLncF8WHWg9jhas3eswxe9G3oQr1Q==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@lit-labs/ssr": "^3.1.8",
|
||||
"@lit-labs/ssr-client": "^1.1.4",
|
||||
"@web/test-runner-commands": "^0.6.1",
|
||||
"@webcomponents/template-shadowroot": "^0.1.0",
|
||||
"lit": "^2.0.0 || ^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/@web/browser-logs": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@web/browser-logs/-/browser-logs-0.2.6.tgz",
|
||||
"integrity": "sha512-CNjNVhd4FplRY8PPWIAt02vAowJAVcOoTNrR/NNb/o9pka7yI9qdjpWrWhEbPr2pOXonWb52AeAgdK66B8ZH7w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"errorstacks": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/@web/dev-server-core": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.4.1.tgz",
|
||||
"integrity": "sha512-KdYwejXZwIZvb6tYMCqU7yBiEOPfKLQ3V9ezqqEz8DA9V9R3oQWaowckvCpFB9IxxPfS/P8/59OkdzGKQjcIUw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/koa": "^2.11.6",
|
||||
"@types/ws": "^7.4.0",
|
||||
"@web/parse5-utils": "^1.3.1",
|
||||
"chokidar": "^3.4.3",
|
||||
"clone": "^2.1.2",
|
||||
"es-module-lexer": "^1.0.0",
|
||||
"get-stream": "^6.0.0",
|
||||
"is-stream": "^2.0.0",
|
||||
"isbinaryfile": "^5.0.0",
|
||||
"koa": "^2.13.0",
|
||||
"koa-etag": "^4.0.0",
|
||||
"koa-send": "^5.0.1",
|
||||
"koa-static": "^5.0.0",
|
||||
"lru-cache": "^6.0.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"parse5": "^6.0.1",
|
||||
"picomatch": "^2.2.2",
|
||||
"ws": "^7.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/@web/parse5-utils": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-1.3.1.tgz",
|
||||
"integrity": "sha512-haCgDchZrAOB9EhBJ5XqiIjBMsS/exsM5Ru7sCSyNkXVEJWskyyKuKMFk66BonnIGMPpDtqDrTUfYEis5Zi3XA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/parse5": "^6.0.1",
|
||||
"parse5": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/@web/test-runner-commands": {
|
||||
"version": "0.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-commands/-/test-runner-commands-0.6.6.tgz",
|
||||
"integrity": "sha512-2DcK/+7f8QTicQpGFq/TmvKHDK/6Zald6rn1zqRlmj3pcH8fX6KHNVMU60Za9QgAKdorMBPfd8dJwWba5otzdw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@web/test-runner-core": "^0.10.29",
|
||||
"mkdirp": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/@web/test-runner-core": {
|
||||
"version": "0.10.29",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-core/-/test-runner-core-0.10.29.tgz",
|
||||
"integrity": "sha512-0/ZALYaycEWswHhpyvl5yqo0uIfCmZe8q14nGPi1dMmNiqLcHjyFGnuIiLexI224AW74ljHcHllmDlXK9FUKGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.2.6",
|
||||
"@web/dev-server-core": "^0.4.1",
|
||||
"chokidar": "^3.4.3",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"ip": "^1.1.5",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.0",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/dependency-graph": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
|
||||
"integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/es-module-lexer": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/globby": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.2.9",
|
||||
"ignore": "^5.2.0",
|
||||
"merge2": "^1.4.1",
|
||||
"slash": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/parse5": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lit-labs/testing/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@lit/reactive-element": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz",
|
||||
|
|
@ -4134,6 +4394,16 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@parse5/tools": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@parse5/tools/-/tools-0.3.0.tgz",
|
||||
"integrity": "sha512-zxRyTHkqb7WQMV8kTNBKWb1BeOFUKXBXTBWuxg9H9hfvQB3IwP6Iw2U75Ia5eyRxPNltmY7E8YAlz6zWwUnjKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parse5": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
|
|
@ -7896,6 +8166,13 @@
|
|||
"dev": true,
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@webcomponents/template-shadowroot": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@webcomponents/template-shadowroot/-/template-shadowroot-0.1.0.tgz",
|
||||
"integrity": "sha512-ry84Vft6xtRBbd4M/ptRodbOLodV5AD15TYhyRghCRgIcJJKmYmJ2v2BaaWxygENwh6Uq3zTfGPmlckKT/GXsQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@webcomponents/webcomponentsjs": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.8.0.tgz",
|
||||
|
|
@ -11741,6 +12018,20 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/enquirer": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
||||
|
|
@ -25400,6 +25691,16 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz",
|
||||
|
|
@ -28036,7 +28337,7 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"packages-node/providence-analytics": {
|
||||
"version": "0.16.8",
|
||||
"version": "0.17.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/traverse": "^7.25.7",
|
||||
|
|
@ -28295,7 +28596,7 @@
|
|||
},
|
||||
"packages/ui": {
|
||||
"name": "@lion/ui",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bundled-es-modules/message-format": "^6.2.4",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"@changesets/cli": "^2.27.9",
|
||||
"@custom-elements-manifest/analyzer": "^0.10.3",
|
||||
"@custom-elements-manifest/to-markdown": "^0.1.0",
|
||||
"@lit-labs/testing": "^0.2.5",
|
||||
"@open-wc/building-rollup": "^2.2.3",
|
||||
"@open-wc/eslint-config": "^12.0.3",
|
||||
"@open-wc/scoped-elements": "^3.0.5",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,31 @@
|
|||
/*
|
||||
import { dedupeMixin } from '@open-wc/dedupe-mixin';
|
||||
import { adoptStyles, isServer } from 'lit';
|
||||
import { ScopedElementsMixin as OpenWcLitScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../../form-core/types/validate/ValidateMixinTypes.js').ScopedElementsMap} ScopedElementsMap
|
||||
* @typedef {import('@open-wc/dedupe-mixin').Constructor<ScopedElementsHost>} ScopedElementsHostConstructor
|
||||
* @typedef {import('@open-wc/scoped-elements/lit-element.js').ScopedElementsHost} ScopedElementsHost
|
||||
* @typedef {import('./types.js').ScopedElementsHostV2Constructor} ScopedElementsHostV2Constructor
|
||||
* @typedef {import('@open-wc/dedupe-mixin').Constructor<LitElement>} LitElementConstructor
|
||||
* @typedef {import('lit').CSSResultOrNative} CSSResultOrNative
|
||||
* @typedef {typeof import('lit').LitElement} TypeofLitElement
|
||||
* @typedef {import('lit').LitElement} LitElement
|
||||
*/
|
||||
|
||||
export function supportsScopedRegistry() {
|
||||
return Boolean(
|
||||
// @ts-expect-error
|
||||
globalThis.ShadowRoot?.prototype.createElement && globalThis.ShadowRoot?.prototype.importNode,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This file is combination of '@open-wc/scoped-elements@v3/lit-element.js' and '@open-wc/scoped-elements@v3/html-element.js'.
|
||||
* Then on top of those, some code from '@open-wc/scoped-elements@v2' is brought to to make polyfill not mandatory.
|
||||
* This can be a great help for ssr scenarios, allowing elements to be consumed without needing knowledge about internall
|
||||
* consumption.
|
||||
* (N.B. at this point in time, this is limited to the scenario where there's one version of lion on the page).
|
||||
*
|
||||
* ## Considerations
|
||||
* In its current state, the [scoped-custom-element-registry](https://github.com/webcomponents/polyfills/tree/master/packages/scoped-custom-element-registry) draft spec has uncertainties:
|
||||
|
|
@ -21,29 +46,7 @@
|
|||
* This can be beneficial for performance, bundle size, ease of use and SSR capabilities.
|
||||
*
|
||||
* We will keep a close eye on developments in spec and polyfill, and will re-evaluate the scoped-elements approach when the time is right.
|
||||
*/
|
||||
|
||||
import { dedupeMixin } from '@open-wc/dedupe-mixin';
|
||||
import { adoptStyles } from 'lit';
|
||||
import { ScopedElementsMixin as OpenWcLitScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('@open-wc/scoped-elements/lit-element.js').ScopedElementsHost} ScopedElementsHost
|
||||
* @typedef {import('../../form-core/types/validate/ValidateMixinTypes.js').ScopedElementsMap} ScopedElementsMap
|
||||
* @typedef {import('lit').CSSResultOrNative} CSSResultOrNative
|
||||
* @typedef {import('lit').LitElement} LitElement
|
||||
* @typedef {typeof import('lit').LitElement} TypeofLitElement
|
||||
* @typedef {import('@open-wc/dedupe-mixin').Constructor<LitElement>} LitElementConstructor
|
||||
* @typedef {import('@open-wc/dedupe-mixin').Constructor<ScopedElementsHost>} ScopedElementsHostConstructor
|
||||
* @typedef {import('./types.js').ScopedElementsHostV2Constructor} ScopedElementsHostV2Constructor
|
||||
*/
|
||||
|
||||
const supportsScopedRegistry = Boolean(
|
||||
// @ts-expect-error
|
||||
ShadowRoot.prototype.createElement && ShadowRoot.prototype.importNode,
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @template {LitElementConstructor} T
|
||||
* @param {T} superclass
|
||||
* @return {T & ScopedElementsHostConstructor & ScopedElementsHostV2Constructor}
|
||||
|
|
@ -51,8 +54,29 @@ const supportsScopedRegistry = Boolean(
|
|||
const ScopedElementsMixinImplementation = superclass =>
|
||||
/** @type {ScopedElementsHost} */
|
||||
class ScopedElementsHost extends OpenWcLitScopedElementsMixin(superclass) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (isServer) {
|
||||
// We are on the server: this means we can't support scoped registries...
|
||||
// So we must treat it like the "no-polyfill scenario", that registers scoped
|
||||
// elements used for internal composition on the global registry.
|
||||
// On the client that would happen in connectedCallback, so we do it here...
|
||||
// N.B. keep in mind that this does not work when we have multiple element (versions)
|
||||
// with the same name. (like multiple versions of lion extension layers).
|
||||
// If we want to support this, we must re-introduce the shim-behavior of ScopedElementsMixin v1
|
||||
// to make this work with ssr as well.
|
||||
// @ts-expect-error
|
||||
this.registry = customElements;
|
||||
// @ts-expect-error
|
||||
for (const [name, klass] of Object.entries(this.constructor.scopedElements || {})) {
|
||||
this.defineScopedElement(name, klass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createScopedElement(/** @type {string} */ tagName) {
|
||||
const root = supportsScopedRegistry ? this.shadowRoot : document;
|
||||
const root = supportsScopedRegistry() ? this.shadowRoot : document;
|
||||
// @ts-expect-error polyfill to support createElement on shadowRoot is loaded
|
||||
return root.createElement(tagName);
|
||||
}
|
||||
|
|
@ -61,12 +85,12 @@ const ScopedElementsMixinImplementation = superclass =>
|
|||
* Defines a scoped element.
|
||||
*
|
||||
* @param {string} tagName
|
||||
* @param {typeof HTMLElement} klass
|
||||
* @param {typeof HTMLElement} classToBeRegistered
|
||||
*/
|
||||
defineScopedElement(tagName, klass) {
|
||||
// @ts-ignore
|
||||
defineScopedElement(tagName, classToBeRegistered) {
|
||||
const registeredClass = this.registry.get(tagName);
|
||||
if (registeredClass && supportsScopedRegistry === false && registeredClass !== klass) {
|
||||
const isAlreadyRegistered = registeredClass && registeredClass === classToBeRegistered;
|
||||
if (isAlreadyRegistered && !supportsScopedRegistry()) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
[
|
||||
|
|
@ -80,10 +104,8 @@ const ScopedElementsMixinImplementation = superclass =>
|
|||
);
|
||||
}
|
||||
if (!registeredClass) {
|
||||
// @ts-ignore
|
||||
return this.registry.define(tagName, klass);
|
||||
return this.registry.define(tagName, classToBeRegistered);
|
||||
}
|
||||
// @ts-ignore
|
||||
return this.registry.get(tagName);
|
||||
}
|
||||
|
||||
|
|
@ -92,12 +114,12 @@ const ScopedElementsMixinImplementation = superclass =>
|
|||
* @returns {ShadowRoot}
|
||||
*/
|
||||
attachShadow(options) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const { scopedElements } = /** @type {typeof ScopedElementsHost} */ (this.constructor);
|
||||
|
||||
const shouldCreateRegistry =
|
||||
!this.registry ||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
(this.registry === this.constructor.__registry &&
|
||||
!Object.prototype.hasOwnProperty.call(this.constructor, '__registry'));
|
||||
|
||||
|
|
@ -108,8 +130,7 @@ const ScopedElementsMixinImplementation = superclass =>
|
|||
* This is important specifically for superclasses/inheritance
|
||||
*/
|
||||
if (shouldCreateRegistry) {
|
||||
// @ts-ignore
|
||||
this.registry = supportsScopedRegistry ? new CustomElementRegistry() : customElements;
|
||||
this.registry = supportsScopedRegistry() ? new CustomElementRegistry() : customElements;
|
||||
for (const [tagName, klass] of Object.entries(scopedElements ?? {})) {
|
||||
this.defineScopedElement(tagName, klass);
|
||||
}
|
||||
|
|
@ -131,7 +152,7 @@ const ScopedElementsMixinImplementation = superclass =>
|
|||
);
|
||||
|
||||
const createdRoot = this.attachShadow(shadowRootOptions);
|
||||
if (supportsScopedRegistry) {
|
||||
if (supportsScopedRegistry()) {
|
||||
// @ts-expect-error
|
||||
this.renderOptions.creationScope = createdRoot;
|
||||
}
|
||||
|
|
|
|||
131
packages/ui/components/core/test/ScopedElementsMixin.test.js
Normal file
131
packages/ui/components/core/test/ScopedElementsMixin.test.js
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
import { expect, fixture } from '@open-wc/testing';
|
||||
import {
|
||||
ssrNonHydratedFixture,
|
||||
ssrHydratedFixture,
|
||||
csrFixture,
|
||||
} from '@lit-labs/testing/fixtures.js';
|
||||
import { LitElement, html } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import { browserDetection } from '../src/browserDetection.js';
|
||||
|
||||
import { ScopedElementsMixin, supportsScopedRegistry } from '../src/ScopedElementsMixin.js';
|
||||
|
||||
const hasRealScopedRegistrySupport = supportsScopedRegistry();
|
||||
const originalShadowRootProps = {
|
||||
// @ts-expect-error
|
||||
createElement: globalThis.ShadowRoot?.prototype.createElement,
|
||||
// @ts-expect-error
|
||||
importNode: globalThis.ShadowRoot?.prototype.importNode,
|
||||
};
|
||||
|
||||
// Even though the polyfill might be loaded in this test or we run it in a browser supporting these features,
|
||||
// we mock "no support", so that `supportsScopedRegistry()` returns false inside ScopedElementsMixin..
|
||||
function mockNoRegistrySupport() {
|
||||
// Are we on a server or do we have no polyfill? Nothing to be done here...
|
||||
if (!hasRealScopedRegistrySupport) return;
|
||||
|
||||
// This will be enough to make the `supportsScopedRegistry()` check fail inside ScopedElementsMixin and bypass scoped registries
|
||||
globalThis.ShadowRoot = globalThis.ShadowRoot || { prototype: {} };
|
||||
// @ts-expect-error
|
||||
globalThis.ShadowRoot.prototype.createElement = null;
|
||||
}
|
||||
|
||||
mockNoRegistrySupport.restore = () => {
|
||||
// Are we on a server or do we have no polyfill? Nothing to be done here...
|
||||
if (!hasRealScopedRegistrySupport) return;
|
||||
|
||||
// @ts-expect-error
|
||||
globalThis.ShadowRoot.prototype.createElement = originalShadowRootProps.createElement;
|
||||
// @ts-expect-error
|
||||
globalThis.ShadowRoot.prototype.importNode = originalShadowRootProps.importNode;
|
||||
};
|
||||
|
||||
class ScopedElementsChild extends LitElement {
|
||||
render() {
|
||||
return html`<span>I'm a child</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
class ScopedElementsHost extends ScopedElementsMixin(LitElement) {
|
||||
static scopedElements = { 'scoped-elements-child': ScopedElementsChild };
|
||||
|
||||
render() {
|
||||
return html`<scoped-elements-child></scoped-elements-child>`;
|
||||
}
|
||||
}
|
||||
customElements.define('scoped-elements-host', ScopedElementsHost);
|
||||
|
||||
describe('ScopedElementsMixin', () => {
|
||||
it('renders child elements correctly (that were not registered yet on global registry)', async () => {
|
||||
// customElements.define('scoped-elements-child', ScopedElementsChild);
|
||||
for (const _fixture of [csrFixture, ssrNonHydratedFixture, ssrHydratedFixture]) {
|
||||
const el = await _fixture(html`<scoped-elements-host></scoped-elements-host>`, {
|
||||
// we must provide modules atm
|
||||
modules: ['./ssr-definitions/ScopedElementsHost.define.js'],
|
||||
});
|
||||
|
||||
// Wait for FF support
|
||||
if (!browserDetection.isFirefox) {
|
||||
expect(
|
||||
el.shadowRoot?.querySelector('scoped-elements-child')?.shadowRoot?.innerHTML,
|
||||
).to.contain("<span>I'm a child</span>");
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
expect(el.registry.get('scoped-elements-child')).to.not.be.undefined;
|
||||
}
|
||||
});
|
||||
|
||||
describe('When scoped registries are supported', () => {
|
||||
it('registers elements on local registry', async () => {
|
||||
const ceDefineSpy = sinon.spy(customElements, 'define');
|
||||
|
||||
const el = /** @type {ScopedElementsHost} */ (
|
||||
await fixture(html`<scoped-elements-host></scoped-elements-host>`)
|
||||
);
|
||||
|
||||
// @ts-expect-error
|
||||
expect(el.registry.get('scoped-elements-child')).to.equal(ScopedElementsChild);
|
||||
expect(el.registry).to.not.equal(customElements);
|
||||
expect(ceDefineSpy.calledWith('scoped-elements-child')).to.be.false;
|
||||
|
||||
ceDefineSpy.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('When scoped registries are not supported', () => {
|
||||
class ScopedElementsChildNoReg extends LitElement {
|
||||
render() {
|
||||
return html`<span>I'm a child</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
class ScopedElementsHostNoReg extends ScopedElementsMixin(LitElement) {
|
||||
static scopedElements = { 'scoped-elements-child-no-reg': ScopedElementsChildNoReg };
|
||||
|
||||
render() {
|
||||
return html`<scoped-elements-child-no-reg></scoped-elements-child-no-reg>`;
|
||||
}
|
||||
}
|
||||
before(() => {
|
||||
mockNoRegistrySupport();
|
||||
customElements.define('scoped-elements-host-no-reg', ScopedElementsHostNoReg);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
mockNoRegistrySupport.restore();
|
||||
});
|
||||
|
||||
it('registers elements', async () => {
|
||||
const ceDefineSpy = sinon.spy(customElements, 'define');
|
||||
|
||||
const el = /** @type {ScopedElementsHostNoReg} */ (
|
||||
await fixture(html`<scoped-elements-host-no-reg></scoped-elements-host-no-reg>`)
|
||||
);
|
||||
|
||||
expect(el.registry).to.equal(customElements);
|
||||
expect(ceDefineSpy.calledWith('scoped-elements-child-no-reg')).to.be.true;
|
||||
ceDefineSpy.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
// ... empty file needed for '@lit-labs/testing/fixtures.js'
|
||||
|
|
@ -13,7 +13,7 @@ import isLocalizeESModule from './isLocalizeESModule.js';
|
|||
/**
|
||||
* We can't access `window.document.documentElement` on the server,
|
||||
* so we write to and read from this object on the server.
|
||||
* N.B.: for now, the goal is to make LocalizeManager not crash on the server, and localizaion happens on the client.
|
||||
* N.B.: for now, the goal is to make LocalizeManager not crash on the server, and let localization happen on the client.
|
||||
* In the future, we might want to look into more advanced SSR of localized messages
|
||||
*/
|
||||
const documentElement = isServer
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import fs from 'fs';
|
||||
import { playwrightLauncher } from '@web/test-runner-playwright';
|
||||
import { litSsrPlugin } from '@lit-labs/testing/web-test-runner-ssr-plugin.js';
|
||||
|
||||
const devMode = process.argv.includes('--dev-mode');
|
||||
|
||||
|
|
@ -60,4 +61,5 @@ export default {
|
|||
name: pkg.name,
|
||||
files: `${pkg.path}/**/*.test.js`,
|
||||
})),
|
||||
plugins: [litSsrPlugin()],
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue