Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug?]: Unexpected Link Element Generation for Stylesheet Imports in Production Environment #1585

Closed
2 tasks done
laujonat opened this issue Jul 21, 2024 · 1 comment
Closed
2 tasks done
Labels
bug Something isn't working

Comments

@laujonat
Copy link

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

Approach 1: Using onLoad prop

I tried using the onLoad prop to update the rel attribute when the stylesheet has finished loading:

import utilities from "~/styles/utilities.css?url";

<Link
  href={utilities}
  rel="preload"
  as="style"
  onLoad={(event) => {
    const target = event.target as HTMLLinkElement;
    target.onload = null;
    target.rel = 'stylesheet';
  }}
/>

However, this throws an error:

Cannot set properties of undefined (setting 'rel')

Approach 2: Using ref and onMount

I then tried using a ref and updating the rel attribute in the onMount function:

import utilities from "~/styles/utilities.css?url";

let linkRef: HTMLLinkElement;

onMount(() => {
  linkRef.rel = "stylesheet";
  linkRef.media = "all";
});

<Link ref={linkRef!} href={utilities} rel="preload" as="style" media="print"/>

I'm not completely certain whether doing the work insideonMount will replicate the same behavior as the HTML onload attribute would, but this works as expected in the development environment, but not in the production environment.

Approach 3: Using Signals as refs

I also tried using Signals as refs:

import blocks from "~/styles/blocks.css?url";

const [blocksStyle, setBlocksStyle] = createSignal();

createEffect(() => {
  if (blocksStyle()) {
    blocksStyle().rel = "stylesheet";
    blocksStyle().media = "all";
  }
});

<Link ref={setBlocksStyle} href={blocks} rel="preload" as="style" media="print"  />

Both Approach 2 and 3 work as expected in the development environment. The initial document shows the link with rel="preload", and the attributes are updated as expected when inspecting the rendered document.

However, in the production environment, Solid start will include a link tag with rel="stylesheet" for the Explicit Url Import, which negates the initial preload and blocks the rendering of the stylesheet, overriding the preload implementation.

<link href="/_build/assets/css/utilities-CRvljsYj.css" rel="stylesheet" fetchpriority="high">

Here is a screenshot of the initial document sent from the server in the production environment:

Screenshot 2024-07-21 at 01 22 04

Any guidance on how to correctly load a stylesheet asynchronously in Solid, particularly in a production environment, would be greatly appreciated.

Expected behavior 🤔

When importing stylesheets on the client side using standard imports like import "~/styles/base.css"; or import "~/styles/cursors.css";, Solid correctly compiles all imports together into a single client-*.css link element, such as <link href="/_build/assets/css/client-Bg1X780_.css" rel="stylesheet" fetchPriority="high"/>.

However, when the stylesheet is imported using ?url (explicit URL imports from Vite), the handling of the stylesheet should be deferred to the URL itself. This is because explicit URL imports are intended to return the URL of the imported asset as a string, and not to automatically include the asset in the markup.

In this case, Solid should not automatically generate a <link> element with rel="stylesheet" for the imported URL. Instead, it should be left to the developer to decide how to include the stylesheet in the markup, such as creating a <link> element with the desired attributes.

This would allow for more control over the loading and application of stylesheets, and would prevent issues like the one described, where the automatic generation of a <link> element with rel="stylesheet" negates the initial preload and blocks the rendering of the stylesheet, overriding the preload implementation.

Steps to reproduce 🕹

Steps:

  1. Create a new Solid project.
  2. Create two CSS files in the styles directory, for example base.css and cursors.css.
  3. In a Solid component, import the stylesheets using standard imports:
    import "~/styles/base.css";
    import "~/styles/cursors.css";
    At this point, Solid should correctly compile all imports together into a single client-*.css link element, such as <link href="/_build/assets/css/client-Bg1X780_.css" rel="stylesheet" fetchPriority="high"/>.
  4. Now, import a stylesheet using an explicit URL import:
    import utilities from "~/styles/utilities.css?url";
  5. In the same component, create a Link element from @solid/meta for the imported URL:
    <Link href={utilities} rel="preload" as="style" media="print"/>
  6. Run the project in development mode and inspect the initial document and the rendered document. The Link element should show rel="preload" in the initial document, and the attributes should be updated as expected in the rendered document.
  7. Now, build the project for production and run it in production mode. Inspect the initial document and the rendered document. Solid should not automatically generate a <link> element with rel="stylesheet" for the imported URL, but it does. This negates the initial preload and blocks the rendering of the stylesheet, overriding the preload implementation.

Context 🔦

I'm trying to load a stylesheet asynchronously using the Link component in Solid. I've tried several approaches, but all are producing unexpected behavior in the production environment.

Your environment 🌎

**Environment Details:**

- Operating System: macOS Sonoma 14.5 (Intel Mac)
- Package Manager: pnpm version 8.6.10
- Node.js version: 22.4.1

**Project Dependencies:**

- @solidjs/meta: version 0.29.3
- @solidjs/router: version 0.13.3
- @solidjs/start: version 1.0.5
- solid-js: version 1.8.17
- vinxi: version 0.4.0
- vite: version 5.3.4
@laujonat laujonat added the bug Something isn't working label Jul 21, 2024
@laujonat laujonat changed the title [Bug?]: [Bug?]: Unexpected Link Element Generation for Stylesheet Imports in Production Environment Jul 21, 2024
@laujonat
Copy link
Author

Ok so I was able to resolve the issue by delaying the creation of elements using Suspense. (I'm not sure if this is an unintended side effect of using Suspense this way though.)

This kept the files I wanted to preload from being included in the manifest assets:

// Used refs to update link rel onload
const PreloadMeta = lazy(() => import("~/components/ui/Meta/PreloadStyle"));
const Index = (props: RouteSectionProps) => {
  return (
    <Suspense>
      <PreloadMeta />
image

I can just close this out- looking forward to the continued growth and success of everything solid !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant