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

Option to inject CSS #4

Open
benmccann opened this issue Sep 7, 2020 · 7 comments · May be fixed by #8
Open

Option to inject CSS #4

benmccann opened this issue Sep 7, 2020 · 7 comments · May be fixed by #8

Comments

@benmccann
Copy link
Contributor

Right now it's a little tricky to get started using this plugin because you need to write code that loads the css. One thing I would really love is an option to update the JS so that it injects the CSS for you, which would make it so that you don't have to update your app in order to use this plugin besides installing the plugin itself.

This is how webpack's style-loader works. It has a few different options such as injecting either code to write a style tag with the CSS inlined or code to write a link tag linking the the .css file.

@domingues
Copy link
Owner

I like the idea, but we need to take in account the target of the compilation: browser/server side.
In the browser side we can assume that de DOM is available and inject something like this:

{
	const link = document.createElement("link");
	link.rel = "stylesheet";
	link.href = "${pluginOptions.publicPath}/${css_file_name}";
	document.getElementsByTagName("head")[0].appendChild(link);
}

but I don't know if in the SSR we can do a generic thing or if we need to inject code specific for each framework.

@benmccann
Copy link
Contributor Author

I've been really thinking through how to do this for SSR. I think I've come to the conclusion that your existing bundle approach is probably the best approach. I still think that there's substantial value in injecting a link tag in the client side bundle though. It makes a lot of client side logic much easier to implement

@benmccann
Copy link
Contributor Author

benmccann commented Sep 14, 2020

I've got a version of this working here: https://github.com/sveltejs/sapper/blob/ead10eebb7416971a390a0190f1df7c1f3327791/src/core/create_compilers/RollupCompiler.ts#L155

It runs your plugin and then another one I wrote to inject the link afterwards.

Please feel free to steal!

@benmccann benmccann linked a pull request Oct 6, 2020 that will close this issue
@domingues
Copy link
Owner

I'm been thinking about this, and I still don't know if this is the place to do this.

Another approach that I tried was to export the public URL of the CSS files (here) and then use it.
For example with a (dumb) Svelte preprocessor we could load the stylesheet even when doing SSR:

const hash = content => crypto.createHmac('sha256', content).digest('hex').substr(0, 8);
const css_file_name = filename => path.resolve(filename.replace(new RegExp(`\\${path.extname(filename)}$`), '.css'));
const preprocessor = {
    markup: ({content, filename}) => {
        return {code: content + `<svelte:head><link rel='stylesheet' href='{css_${hash(css_file_name(filename))}}'></svelte:head>`}
    },
    script: ({content, attributes, filename}) => {
        if (!attributes.context) {
            const fname = css_file_name(filename)
            content += `\nimport css_${hash(fname)} from '${fname}';\n`;
        }
        return {code: content};
    },
}

@benmccann
Copy link
Contributor Author

What happens if you have multiple instances of the same Svelte component? Will Svelte be smart enough not to duplicate the <link> elements in <svelte:head>?

@domingues
Copy link
Owner

domingues commented Dec 3, 2020

In the DOM I think that there is no problem, but in SSR we will have duplicate <link>s with the same data-svelte, probably a Svelte bug/limitation: $$result.head += .

const Src = create_ssr_component(($$result, $$props, $$bindings, slots) => {
	$$result.css.add(css);
	return `${($$result.head += `<link rel="${"stylesheet"}"${add_attribute("href", css_03132a47, 0)} data-svelte="svelte-aw03p5">`, "")}`;
});

But even if the later is fixed, my dumb preprocessor still have a problem: each component of the same chunk will load the same CSS one time each.

Maybe with a special component <LoadCSS href={} /> we can track which files have already been loaded.

@benmccann
Copy link
Contributor Author

That's basically what I do as well: https://github.com/domingues/rollup-plugin-css-chunks/pull/8/files#diff-dcdc3e0b3362edb8fec2a51d3fa51f8fb8af8f70247e06d9887fa934834c9122R63

I think the trade-off between the approaches:

  • Add ability to inject link tags #8 - easier for the user to setup. no pre-processor required. works for non-svelte css
  • export_url - easier for the app framework developer. don't need to integrate reading of manifest

I personally think I still prefer #8 given those trade-offs because we can hide more setup from the user and we might get a larger user base since it'd be easier to use with non-svelte components. Not sure if I'm missing any other considerations though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants