-
-
Notifications
You must be signed in to change notification settings - Fork 470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for using lazyStyleTag use() from a JavaScript module (injecting into multiple shadow DOMs) #565
Comments
It it possible to create memory leaking and it will have very bad perf... |
HI @alexander-akait, can you elaborate on bad performance? I'm open to other suggestions. What about passing a key in options that can be used to associate the instance? |
@mikeaustin Getting DOM nodes using As I undestand you want to reuse some styles in multiple shadow doms, right? If you provide a problem which you try to solve we can try to find better solution |
Hi @alexander-akait, thank you for the reply. The original message covers the issue – loading a JS module dynamically, multiple times, only the first call to use() injects the style element. Since JS module instances are shared (loading a second time returns the original instance), only one style element is ever injected. Thank you. Would another option to be to create a new instance manually? So instead of styles.use(), styles.create(). |
@mikeaustin Can you create small example? I want to look how you use it to provide better solution |
I'm having the same issue. It can be reproduced easily with the example from the docs: https://webpack.js.org/loaders/style-loader/#custom-elements-shadow-dom Just import the resulting js to some html file and create several instances of the custom element, like so: <custom-square></custom-square>
<custom-square></custom-square> You'll notice that only the first element is styled. Would appreciate any advice on how to work around this properly. So far I'm thinking of some sort of MiniCssExtractPlugin + AssetsPlugin combination, but don't really like that option. Ideally, there should be a |
@andriichumak Do you keep styles in JS file or extract them for production? |
I would prefer to have styles extracted, but it's not a hard requirement for my project. If we would be able to inject Another option I can think of is to make the loader return the actual path to the generated css file instead of an empty object when using regular import pathToFile from 'my.css';
// pathToFile = e.g. /assets/my.css |
@andriichumak Can you create small reproducible example to show usage? |
Had exactly the same issue today. It's a pity that in webpack there's no easy way to export a CSS module URL(s) to extracted files. I'm considering reverting back and use just css-loader, exporting styles as CSSStyleSheet items. But the issue with these interfaces, is that they're not supported from Safari (and polyfill does not work great) |
@mikeaustin Can you prodvide example of the problem (small repo), so I provide configuration solutions how I will solve the same problems |
Hello @alexander-akait I did a small example of the issue: https://github.com/mditullio/demo-webpack-style-loader. The need behind would be to share the same CSS from multiple web component instances that use shadow DOM. Ideally, this could be, as suggested by @andriichumak a module which exports the URL / path to the extracted CSS. Thanks in advance for the attention |
@mikeaustin Tha main problem style-loader is not extract CSS, it is for CSS in runtime code, anyway if you can use |
Thanks for the suggestion about dynamic import, I will look onto it. For the polyfill of adoptedStyleSheets, I tried this lib: https://github.com/calebdwilliams/construct-style-sheets So, for now, I decided to use Shadow DOM for intranet-only needs (just supporting Edge / Chrome), waiting for Apple updating its browsers... Safari is the new IE11 🐢 |
Feel free to feedback and ask questions |
Just came across this issue as I'm having an issue with the same thing currently (I posted it on StackOverflow also). Reading through this I'm a little confused if someone found an appropriate workaround to this issue as I've been stuck on this for a few days now and I feel like I've tried a few different approaches. Edit // webpack.config.js:
{ loader: "style-loader", options: { attributes: { id: "my-styles" } } }
// component.tsx
connectedCallback() {
// Inject Styles
const css = new CSSStyleSheet();
css.replace(document.querySelector("#my-styles").innerHTML);
this.shadowRoot.adoptedStyleSheets = [css];
// Inject Component into ShadowRoot
createRoot(this.shadowRoot).render(this.render());
} Also, going this approach creates complications for my extension popup as I'm unable to access the styles there as they are injected into the page instead. |
Hello @aw1875 What you could do, if you can use CSSStyleSheet class (remark it's not available on every browser, Safari does not support it) is to directly export your stylesheet files in the form of CSSStyleSheet using the css-loader - look at https://webpack.js.org/loaders/css-loader/#exporttype. The problem in my case, is that I needed to support also Safari browsers, so I ended up just by not using ShadowRoot, injecting them global styles using SASS with a root selector |
@mditullio appreciate the response! I looked through the docs and gave it a try based on them. It didn't seem to work, giving me the error "TypeError: Failed to set the 'adoptedStyleSheets' property on 'ShadowRoot': Failed to convert value to 'CSSStyleSheet'." I'm not sure if this is because I'm using tailwind and postcss but the documentation seemed pretty straight forward. Also, I should mention that this is specifically for a chrome extension so I'm not super concerned with browser support. Quick edit: |
Yes, style-loader should be removed if you use injectType = css-style-sheet. |
Just responded on StackOverflow but thank you it works perfectly now! |
Perfect ! You're welcome ;) |
Remove 'style-loader' because of the issued mentioned here, webpack-contrib/style-loader#565, and only use 'css-loader'.
Feature Proposal
When using
lazyStyleTag
anduse({ target: shadowRoot })
inside a shared JavaScript module, only the first call to use injects astyle
element. The other shadow elements that calluse()
have no styles. I've duplicated the module and loaded each and the problem does not exist. There may be other options such somehow forcing separate module instances, but I'm not sure.In index.js, I believe the following condition prevents use() from injecting duplicate styles:
https://github.com/webpack-contrib/style-loader/blob/master/src/index.js#L131
One possible solution is to give an id to each injected
style
element, instead of having a globalrefs
value.Feature Use Case
loading JS modules injected into shadow elements, so modules can be loaded dynamically.
Please paste the results of
npx webpack-cli info
here, and mention other relevant informationSystem:
OS: macOS 12.1
CPU: (4) x64 Intel(R) Core(TM) i5-8210Y CPU @ 1.60GHz
Memory: 122.11 MB / 16.00 GB
Binaries:
Node: 14.18.1 - /usr/local/bin/node
npm: 6.14.15 - /usr/local/bin/npm
Browsers:
Chrome: 101.0.4951.64
Chrome Canary: 104.0.5071.0
Firefox: 98.0.1
Safari: 15.2
Safari Technology Preview: 15.4
Packages:
css-loader: ^6.7.1 => 6.7.1
css-modules-typescript-loader: ^4.0.1 => 4.0.1
styles-loader: ^4.0.1 => 4.0.1
ts-loader: ^9.3.0 => 9.3.0
webpack-cli: ^4.9.2 => 4.9.2
The text was updated successfully, but these errors were encountered: