webpack-contrib / style-loader

Style Loader
MIT License
1.65k stars 471 forks source link

Add shadow-DOM option type for injectType #536

Closed Justinidlerz closed 3 years ago

Justinidlerz commented 3 years ago

This PR contains a:

Motivation / Use-Case

Extract styles and put into a container, then can injected into the shadow-DOM conainer


import component from 'component';
import getCss from 'style-loader/dist/runtime/injectStyleInScript';

class MyElement extends Element {
    constructor() {
        super();
        const shadowContent = this.attachShadow({ mode: 'open' });  
        const style = document.createElement('style');
        style.innerHTML = getCss();
        shadowContent.appendChild(style);
    }
}
linux-foundation-easycla[bot] commented 3 years ago

CLA Signed

The committers are authorized under a signed CLA.

Justinidlerz commented 3 years ago

@alexander-akait Thanks for reviewing the PR. css-loader can not combine all styles into one container. Such as a react App has many components and I want to mount that into a shadow-DOM root. But I don't want to import CSS files from each component.

So the full case see like: /a/component.tsx

import css from './style.css'

// ...
export component;

/b/component.tsx

import css from './style.css'

// ...
export component;

There have many components...

main.tsx

import Main from 'components';
import {render} from 'react-dom'
import getCss from 'style-loader/dist/runtime/injectStyleInScript';

class MyElement extends Element {
    constructor() {
        super();
        const shadowContent = this.attachShadow({ mode: 'open' });  
        const style = document.createElement('style');
        style.innerHTML = getCss();
        shadowContent.appendChild(style);
        const root = document.createElement('div');
        shadowContent.appendChild(root);

        render(<Main />, root);
    }
}
alexander-akait commented 3 years ago

run css.toString()

alexander-akait commented 3 years ago

https://github.com/webpack-contrib/css-loader/blob/master/src/runtime/api.js#L11

Justinidlerz commented 3 years ago

@alexander-akait So you mean I can use that see like:

import Main from 'components';
import {render} from 'react-dom'
import allCss from 'css-loader/dist/runtime/api';

class MyElement extends Element {
    constructor() {
        super();
        const shadowContent = this.attachShadow({ mode: 'open' });  
        const style = document.createElement('style');
        style.innerHTML = allCss.toString(); // This one?
        shadowContent.appendChild(style);
        const root = document.createElement('div');
        shadowContent.appendChild(root);

        render(<Main />, root);
    }
}
alexander-akait commented 3 years ago

No, just use:

import Main from 'components';
import {render} from 'react-dom'
import styles from './style.css';

class MyElement extends Element {
    constructor() {
        super();
        const shadowContent = this.attachShadow({ mode: 'open' });  
        const style = document.createElement('style');
        style.innerHTML = styles.toString();
        shadowContent.appendChild(style);
        const root = document.createElement('div');
        shadowContent.appendChild(root);

        render(<Main />, root);
    }
}
Justinidlerz commented 3 years ago

@alexander-akait Sorry, I don't quite understand the method of use you proposed Could you please give me an example of how to use the css-loader to getting the combined styles?

alexander-akait commented 3 years ago

Example above

alexander-akait commented 3 years ago

Just remove style-loader, you don't need this

Justinidlerz commented 3 years ago

No, just use:

import Main from 'components';
import {render} from 'react-dom'
import styles from './style.css';

class MyElement extends Element {
    constructor() {
        super();
        const shadowContent = this.attachShadow({ mode: 'open' });  
        const style = document.createElement('style');
        style.innerHTML = styles.toString();
        shadowContent.appendChild(style);
        const root = document.createElement('div');
        shadowContent.appendChild(root);

        render(<Main />, root);
    }
}

I can import the root CSS file see like your provided case. But how to apply nested component styles?

alexander-akait commented 3 years ago

Sorry, it is not QA services, please use stackoverflow for questions and personal help, we don't need this API, because css-loader provide your ability to use toString and return string of CSS, it is enough for your case

Justinidlerz commented 3 years ago

/a/component.tsx

import css from './style.css'

const A = () => {
   return <div />
}

export default A;

/b/component.tsx

import css from './style.css'
import A from '../a/component'

const B = () => {
   return <div>
       <A />
   </div>
}
export component;

There have many components...

main.tsx

import B from 'b/component';
import {render} from 'react-dom'
import getCss from 'style-loader/dist/runtime/injectStyleInScript';

class MyElement extends Element {
    constructor() {
        super();
        const shadowContent = this.attachShadow({ mode: 'open' });  
        const style = document.createElement('style');
        style.innerHTML = getCss();
        shadowContent.appendChild(style);
        const root = document.createElement('div');
        shadowContent.appendChild(root);

        render(<Main />, root);
    }
}
alexander-akait commented 3 years ago

You don't need this API, what is not clear from my answer? Remove style-loader and don't use this, you don't need this for custom components.

alexander-akait commented 3 years ago

You mix multiple react component with the one custom component, this is the wrong approach to what you are trying to achieve

alexander-akait commented 3 years ago

You should not have import css from './style.css' for react components, styles only inside custom component