Replies: 2 comments 3 replies
-
I think this is similar to #11855. About the suggested solution, I'm not sure how to make it work with multiple shadow roots. // element.js
import './foo.css' // where will this CSS be registered, both custom elements? or the global window?
import './common.js'
export function customElement1() {
//
}
export function customElement2() {
//
}
// common.js
import './common.css' // also this CSS |
Beta Was this translation helpful? Give feedback.
-
I think the only way to handle this feature effectively is through a combination of a Vite configuration option and a code design guideline. The listener for handling the preloading process (in this case, something like Example Project Setup
In this setup, we separate the Web Component wrapper (responsible for registering the preloading listener) from the actual widget logic (which contains dynamic imports). This ensures that styles for dynamically imported components are properly loaded into the correct shadow root.
import { customElement } from "solid-element";
// Widgets will have dynamic imports
import Widget1 from "./widgets/Widget1";
import Widget2 from "./widgets/Widget2";
// Create Web Component with Shadow DOM and use `StylesLoader` to load styles into the shadow root.
customElement("my-widget-1", (props) => {
return (
<StylesLoader>
<Widget1 />
</StylesLoader>
);
});
// Create Web Component with Shadow DOM and use `StylesLoader` to load styles into the shadow root.
customElement("my-widget-2", (props) => {
return (
<StylesLoader>
<Widget2 />
</StylesLoader>
);
});
function StylesLoader(props) {
let stylesContainer: HTMLDivElement;
// Register a listener for preloading dependencies
import.meta.registerPreloadDependency(preloadDependency);
function preloadDependency(dep: string): Promise<void> | undefined {
const isCss = dep.endsWith(".css");
const link = document.createElement("link");
link.rel = isCss ? "stylesheet" : "modulepreload";
link.href = dep;
stylesContainer.appendChild(link);
if (isCss) {
return new Promise((res, rej) => {
link.addEventListener("load", res);
link.addEventListener("error", () =>
rej(new Error(`Unable to preload CSS for ${dep}`))
);
});
}
}
return (
<>
<div ref={(el) => (stylesContainer = el)} />
{props.children}
</>
);
}
The actual widget components ( // DynamicComponent will have CSS dependencies
// The `import` and `__vitePreload` will only run when rendering.
const DynamicComponent = lazy(() => import("./views/DynamicComponent"));
export default function Widget1(props) {
return (
<div>
{/* Now __vitePreload will run */}
<DynamicComponent />
</div>
);
} Why This Separation MattersThe important point here is the separation of the Web Component wrapper and the actual Widget component implementation. By ensuring that This separation ensures that the CSS from dynamically imported components is correctly scoped to the shadow DOM of each Web Component. How It WorksFor all widgets, the listener is registered before any dynamic imports are triggered. This means that each Web Component wrapper (like The challenge is how
Additionally, Summary
In either case, the |
Beta Was this translation helpful? Give feedback.
-
Description:
As a developer using Vite to build Web Components with Shadow DOM, I need to control where dynamically imported CSS is injected. Currently, CSS from dynamic imports is always injected into
document.head
by the__vitePreload
function, but in cases like Web Components using Shadow DOM, the CSS needs to be injected into the shadow root.When dynamically importing modules, such as:
The generated code includes a
__vitePreload
function that loads all the associated dependencies, including CSS. However, the CSS is injected intodocument.head
, as seen in the following part of the code:This behavior is problematic for Web Components using Shadow DOM, where styles need to be scoped within the shadow root and not globalized by being inserted into the document’s head.
Suggested solution:
To solve this issue, I suggest adding an option or a hook to control where the CSS
<link>
elements created by__vitePreload
are appended. Ideally, this should allow the developer to register some kind of listener to receive the dependency URL and perform the preload.For example,
import.meta.registerPreloadDependency
could be used to allow developers to register a listener for handling the preloading process:Alternative:
Without this feature, developers like myself must manually move the
<link>
elements fromdocument.head
to the shadow root, which is neither scalable nor clean.Additional context:
This feature would be especially useful for developers building Web Components using Shadow DOM, where encapsulated styles are critical for maintaining the integrity of component styling. It would also benefit other use cases where developers need to scope styles to a specific part of the DOM, rather than having them applied globally via
document.head
.Beta Was this translation helpful? Give feedback.
All reactions