wxt-dev / wxt-dev/wxt

Static CSS option for defineContentScript, CSS scoping for content scripts

Open
#2,395 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
10.5k
Forks
564
PR merge metrics
No merged PRs in 30d

Description

Feature Request

CSS scoping between global and shadow DOM UIs can be a bit of an headache currently. As quick solution to at least allow defining CSS for both of these scopes I have the following feature request:

When using content scripts with cssInjectionMode: 'ui' injecting additional global CSS currently requires dynamic addition for example via:

const exampleCssUrl = browser.runtime.getURL('/example.css');
document.head.insertAdjacentHTML('beforeend', `<link rel="stylesheet" href="${exampleCssUrl}">`);

This works, but could be solved more cleanly by directly inserting paths to required CSS into the generated manifest via an option to defineContentScript, for example like this:

export default defineContentScript({
    matches: ['<all_urls>'],
    cssInjectionMode: 'ui',
    cssStatic: ['example.css'],

    async main(ctx) {
        const exampleCssUrl = browser.runtime.getURL('/example.css');
        document.head.insertAdjacentHTML('beforeend', `<link rel="stylesheet" href="${exampleCssUrl}">`);

        const ui = await createShadowRootUi(ctx, {
            name: '<name>',
            position: 'inline',
            anchor: 'body',
            onMount(container) {
                // Create UI with scoped CSS
            },
        });
        ui.mount();
});

Hooking build:manifestGenerated to add CSS paths to content scripts works for production builds, but this sadly does not work for development as content scripts do not use the manifest data there.

This could also be implemented for scripts, but this would not allow any new use-cases.


In general it would be nice if there was a system to scope CSS in content scripts. Vite sadly doesn't provide a system we could (ab)use for this as far as I can tell. My only idea would be something along the lines of inserting markers into the built CSS to allow build-time separation into different scopes.

Basically something like the following:

import 'wxt/scoped-css/reset';          // generates following CSS into /content-scripts/<name>/content.css
import 'wxt/scoped-css/<scope>';         // generates into /content-scripts/<name>/<scope>.css
import 'wxt/scoped-css/all';            // generates into /content-scripts/<name>/*.css

import 'wxt/scoped-css/push/<scope>';   // switch to pushed scope
import 'wxt/scoped-css/pop';            // pop scope

A custom vite plugin would then intercept those imports and replace them with CSS markers we can use for separation of the built CSS. This could work similarly to how the separation of font-family CSS from shadow DOM CSS is done (but at build time I guess).

Thoughts?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the defineContentScript entry point and the build:manifestGenerated hook mentioned in the issue, then trace how content scripts are handled during development versus production. Define the scope of the static CSS option before considering the broader scoped-CSS proposal. Done should include a documented option whose CSS paths work in both development and production, with tests covering the generated manifest and development behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript, vite
Domain
build-system, frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.