vanilla-extract-css / vanilla-extract

Zero-runtime Stylesheets-in-TypeScript
https://vanilla-extract.style
MIT License
9.6k stars 291 forks source link

Enable custom injection method for ShadowDom or WebComponents. #488

Open cpakken opened 2 years ago

cpakken commented 2 years ago

Create an option for user to turn off css injection.

plugins: [new VanillaExtractPlugin({inject: false})]

Use Case

I am writing a chrome extension and will be using the shadow dom in order to prevent style clashing when attaching elements. This will apply to WebComponents as well.

Example API

import {getCssText} from '@vanilla-extract/css'; 

// in class
constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        const { shadowRoot } = this;
        container = document.createElement('div');

        styleTag = document.createElement('style');

        //Inject here
        styleTag.innerHTML = getCssText();

        shadowRoot.appendChild(styleTag);            

        shadowRoot.appendChild(container);
        ReactDOM.render(<App />, container);

    }

Inspiration from: https://stackoverflow.com/a/63959654 (Inject CSS styles to shadow root via Webpack)

cpakken commented 2 years ago

It's been a couple of months and wondering if anyone has looked into this.

I've thought of another idea for injecting styles:

import { injectToStyleElement } from '@vanilla-extract/css'; 

// in class
constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        const { shadowRoot } = this;
        const container = document.createElement('div');

        const styleEl = document.createElement('style');

        //Inject here
        injectToStyleElement(styleEl)

        shadowRoot.appendChild(styleEl);            

        shadowRoot.appendChild(container);
        ReactDOM.render(<App />, container);

    }

In the plugin configuration object, we can make an option for manual injection:

{manualInjection: true}

and stop vanilla-extract from creating and inserting its own styleElement into <head />. Then, it will wait for injectToStyleElement(customStyleElement) to be called .

In 'dev/serve' vanilla-extract can update the styles via this function and during a build, we can link with the .css URI.

I'm looking at https://github.com/seek-oss/vanilla-extract/blob/master/packages/css/src/injectStyles.ts#L30-L31 to see where we might implement this feature but I'm not familiar enough with the source yet.

Any feedback regarding this feature or API implementation would be nice

joshuabaker commented 2 years ago

I ended up writing a build script to do this. Bit crummy, but works.

// This script inlines the generated style.css into web-components components

const fs = require("fs");
const path = require("path");

const dist = path.resolve(__dirname, "../dist");

const styles = fs.readFileSync(`${dist}/style.css`).toString().trim();

const scriptPath = `${dist}/index.js`;
const scriptContents = fs.readFileSync(scriptPath).toString();
fs.writeFileSync(scriptPath, scriptContents.replace("__styles__", styles));
pgonzalez-santiago commented 2 years ago

Any news in here? I have a similar problem and I was wondering if its possible to inject the vanilla-extract styles in shadow dom element instead of in the head of the app.

mwood23 commented 2 years ago

This feels like something that should be handled outside of Vanilla Extract and documented for each bundler. For example, in webpack you can use the style-loader to inject vanilla extract after all the styles have been extracted into a given shadow DOM. This probably isn't the use case everyone is looking for but this config uses a multi entry point build and webpack layers to build web component friendly islands. https://github.com/mwood23/preact-island-starter