I'm currently working with webpack and style-loader to inject my styles into components that use shadow-dom. However, the issue happens when I try to use multiple instances of the element (the styles stop injecting). I was able to properly solve this issue with another component by adding the unuse
function to my disconnectCallback
for that component. Unfortunately, for this component below, I expect it to appear multiple times at once on a page. Am I doing something wrong?
Component.tsx:
import React from 'react';
import { createRoot } from 'react-dom/client';
// Styles
import styles from '../styles/contentScript.css';
// Images
const icon = chrome.runtime.getURL('assets/icon.png');
export default class CustomButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// Functions
this.handleShow = this.handleShow.bind(this);
}
handleShow = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
...
};
connectedCallback() {
// Inject Styles
styles.use({ target: this.shadowRoot });
// Inject Component into ShadowRoot
createRoot(this.shadowRoot).render(this.render());
}
render() {
return (
<div className='absolute inset-0'>
<button className='main-button group' onClick={this.handleShow}>
<img src={icon} className='w-7' />
<span className='main-button-tooltip group-hover:scale-100'>
Open Popup
</span>
</button>
</div>
);
}
disconnectedCallback() {
styles.unuse();
}
}
customElements.define('custom-button', CustomButton);
webpack.config.js
// Imports...
module.exports = {
entry: {
...
},
module: {
rules: [
{
use: 'ts-loader',
test: /\.tsx?$/,
exclude: /node_modules/,
},
{
use: [
{
loader: 'style-loader',
options: {
injectType: 'lazyStyleTag',
insert: function insertIntoTarget(element, options) {
var parent = options.target || document.head;
parent.appendChild(element);
},
},
},
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
indent: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
test: /\.css$/i,
},
{
type: 'asset/resource',
test: /\.(png|jpg|jpeg|gif)$/i,
},
]
},
resolve: {
...
},
plugins: [
...
],
output: {
filename: '[name].js',
clean: true,
},
optimization: {
...
},
}
I should also note (in case it's important) I am using tailwind for styling so I've included postcss and autoprefixer. This is also for a chrome extension so I'm creating this component in my contentScript. I have also tried it without the unuse
call in my disconnectCallback
and faced the same issue.
CodePudding user response:
to follow the discussion on github, if you're only browser target is Chrome, then I really suggest you to use the CSSStyleSheet
class.
In that case, you should drop from your webpack configuration the style-loader, as it's not needed anymore:
{
loader: 'style-loader',
options: {
injectType: 'lazyStyleTag',
insert: function insertIntoTarget(element, options) {
var parent = options.target || document.head;
parent.appendChild(element);
},
},
},
Then modify the configuration of the css-loader to have the option exportType = "css-style-sheet"
(https://webpack.js.org/loaders/css-loader/#exporttype).
In this way, the exported element is already an object of type CSSStyleSheet, and you can use it directly on your web component:
import sheet from "./styles.css" assert { type: "css" };
document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet];
Normally, the 'postcss' step should not pose problems.
No need anymore to use "use / unuse" then (because that's an API of style-loder that you should remove with this solution)