Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How inject css in shadowDom with vite?

I have vite config and React app.


import react from '@vitejs/plugin-react';
import * as path from 'path';
import { defineConfig, splitVendorChunkPlugin } from 'vite';
import htmlPlugin from 'vite-plugin-html-config';
import { dependencies } from './package.json';

const exclVendors = ['react', 'react-router-dom', 'react-dom'];
function renderChunks(deps: Record<string, string>) {
  let chunks = {};
  Object.keys(deps).forEach((key) => {
    if (exclVendors.includes(key)) return;
    chunks[key] = [key];
  });
  return chunks;
}

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    port: 8082
  },
  envPrefix: 'APP_',
  resolve: {
    alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
  },
  plugins: [
    react(),
    htmlPlugin({ favicon: './src/assets/logo.svg' }),
    splitVendorChunkPlugin(),
  ],
  build: {
    sourcemap: false,
    rollupOptions: {
      output: {
        manualChunks: {
          ...renderChunks(dependencies),
        },
      },
    },
  },
});

I want create app in shadow Dom.

The application is built in the shadow Dom but the css is added to the head.

How to add all css to shadow Dom ?

I tried installing the vite-plugin-css-injected-by-js plugin but it did not move the css from the head css

In esbuild this is done by esbuild-css-modules-plugin, but I haven’t found how to do the same in vite.

====

Alternative solution with esbuild.

The config is very simple, but it does what I need. Very fast build and all css is added to the specified tag without making changes to the code.

   const buildParams = {
        entryPoints: entryPoints,
        bundle: true,
        metafile: true,
        outfile: outfile,
        format: "esm",
        loader: { ".js": "jsx", ".json": "json", ".png": "file", ".jpeg": "file", ".jpg": "dataurl", ".svg": "dataurl", ".woff": "file" },
        color: true,
        minify: true,
        sourcemap: true,
        mainFields : [ 'module' , 'main' ],
        define: define,
        plugins: [
            glsl({
                minify: true
            }),
            aliasPlugin([{ find: '@', replacement: path.resolve(__dirname, 'src') }]),
            polyfillNode({
                process: true,
                buffer: true,
            }),
            cssModulesPlugin({
                inject: 'body',
                force: true,
                dashedIndents: true,
                emitDeclarationFile: false,
                localsConvention: 'camelCase',
                pattern: '[name]-[hash]-[local]'
            }),
            copy({
                resolveFrom: 'cwd',
                assets: {
                    from: ['./index.esbuild.html'],
                    to: ['./dist/index.html']
                },
                watch: false,
            })
        ]
    }

    let result = await esbuild.build(buildParams)

like image 412
Sergey Avatar asked Oct 21 '25 06:10

Sergey


1 Answers

I am unsure if you have a solution already, but I can share one that works for me now within the shadow dom.

First, use the ?inline option to generate a styles export within the following CSS file.

import styles from "./App.css?inline"
function App() {
  // ... other code
  return (
    <>
      <style>{styles}</style>
      <div className="chrome-extension-boilerplate">
        {/* ...other components*/}
      </div>
    </>
  )
}

Alternatively, you can directly add styles within the shadow dom element. It will look similar, but you must inject the styles directly into the shadow doom root.

function attachStyleToShadowDom(shadowWrapper: ShadowRoot, cssContent: string) {
    // create a variable to attach the tailwind stylesheet
    const style = document.createElement("style")

    //Attach the stylesheet as text
    style.textContent = cssContent

    // apply the style
    shadowWrapper.appendChild(style)
}

export function createShadowRoot(root: Element, styles: string) {
    // Set shadow root inside of root element
    const shadowRoot = root.attachShadow({ mode: "open" })
    root.appendChild(shadowRoot)
    // Add React App root node and styles
    const rootIntoShadow = document.createElement("div")
    rootIntoShadow.id = appRootId
    shadowRoot.appendChild(rootIntoShadow)
    attachStyleToShadowDom(shadowRoot, styles)
    return rootIntoShadow
}

Here is a link to the Chrome extension boilerplate I am building: https://github.com/EduardoAC/browser-extension-boilerplate. I hope that helps to solve your issues.

like image 150
Eduardo AC Avatar answered Oct 22 '25 19:10

Eduardo AC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!