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

Bundle css on server and return to client #128

Open
TimoRuetten opened this issue Mar 2, 2019 · 11 comments
Open

Bundle css on server and return to client #128

TimoRuetten opened this issue Mar 2, 2019 · 11 comments

Comments

@TimoRuetten
Copy link

We are using Serverside rendering so we would like to send the generated css classes from the server to the client. Is there any way to solve this with your package?

If we do not send the css directly to the client from server the first render - which the user sees - does not have the styles. A second later the styles get appended to the elements which is a bit ugly on the first render.

@akanix42
Copy link
Owner

akanix42 commented Mar 4, 2019

Currently this is not a feature of my package, but it may be possible to add it. How are you performing SSR and how do you envision sending the CSS?
For example, we could add an additional export that allows you to access the CSS directly from your code: import styles, { css } from './foo.css';

@TimoRuetten
Copy link
Author

There could be 2 ways in my opinion.

1 All css files which are imported could be bundled when the Meteor Server restarts and put all together in one file which can be added to the

2 Like in your example it could be possible to extract the css of the file and add it to a self written CSS which has the context of all CSS code on Serverside and can append a <style /> tag to the head - then only the needed CSS for the SSR will be returned to client.

I dont know which one would be the best and how to implement this because I have not rly a clue how css-modules works and how I am able to extract the generated css.

@akanix42
Copy link
Owner

akanix42 commented Mar 4, 2019

The way Meteor handles CSS, we have a few options:

  1. Tell Meteor to only include the CSS file if it is imported somewhere. This plugin won't know if it's actually imported somewhere - Meteor handles that behind the scenes. When done this way, the CSS is not bundled into a single file and is instead only added to the page when it is imported. This is the behavior you are experiencing.
  2. Tell Meteor to always bundle the CSS file. When done this way, the CSS will be bundled into a single .css file and loaded by Meteor via <link rel="stylesheet"> in the <head>, so the styles will be loaded before your application is displayed. When done this way, all of the CSS in your application (regardless of whether or not you import it) will be included. This already automatically happens in Meteor <= 1.6 when not using the imports directory. We'd probably have to add a flag to allow you to force this behavior for use with the mainModule property introduced in Meteor 1.7.
  3. Modify the plugin to export the css so you can include it in the rendered content by manually adding a <style> tag.

There may be another way to do this by building a custom minifier plugin, but I'm not sure what all that would entail.

@TimoRuetten
Copy link
Author

But is there a way to export the generated CSS when importing the file? If so it would be easy to append the exported css to the head on server side. I do not know much about css-modules so I am not sure how this could be solved.

Tomorrow I will do a little research

@TimoRuetten
Copy link
Author

Could you give me a hint how we could do this? Of course I would help when its possible for me to solve this case :)

@akanix42
Copy link
Owner

akanix42 commented Mar 6, 2019

For option 3 (the export), I think it should be fairly straightforward (spoken as someone who is intimately familiar with the package, so our perspectives on straightforward may differ 🙂 ):
The CSS is accessible as inputFile.contents and is added to the output here: https://github.com/nathantreid/meteor-css-modules/blob/master/css-modules-build-plugin.js#L239

If when shouldAddStylesheet is false we were to assign that to a variable in the output file and then export the variable, I think it would do the trick.

An example of exporting is here, where we do the export for the class names: https://github.com/nathantreid/meteor-css-modules/blob/master/css-modules-build-plugin.js#L247

@TimoRuetten
Copy link
Author

Thanks for your input. Not 100% sure if I understand you correct that I should now change the plugin custom for my own case or if you are interested to implement something to solve it in general?

I think the best solution would be something like this:

  • control in the package.json settings if a server output should be generated
  • if so: when on serverside the classnames are generated I think the output css is also available - then we could maybe add the output css to the sink of meteor so you would be able to access the css right in your render method on serverside.

Would be this something which could be possible? If so and you are not interested in doing it I would try it by myself. Would need some time to understand your plugin in full but I would give it a try.

@akanix42
Copy link
Owner

akanix42 commented Mar 7, 2019

I'm interested in doing it, but it may take me a little while to get around to doing so. If you'd like to, feel free to look into it.
Currently server output is controlled in package.json via the specificArchitecture option: https://github.com/nathantreid/meteor-css-modules/wiki/Package-Options. I'm not sure we'd need anything more than that, as bundle sizes are less of a concern on the server, but we could add an exportCssOnServer option if necessary.
I'm not quite sure what you mean by

the sink of meteor

but with the export change you'd be able to do something like the following:

import { css } from './foo.css';
import React from 'react';

export default class HelloWorld extends React.Component {
  render() {
    return (
      <style>{css}</style>
    );
  }
}

Is that what you had in mind?

@TimoRuetten
Copy link
Author

Your example would be an option but then you need to add your css on any file you are including it. The only reason to do what I want is because of SSR. If you are using SSR with Meteor you are working with sink from meteor.

https://docs.meteor.com/packages/server-render.html

The sink object comes with the onPageLoad callback and holds some information of the request the user has made. So my idea would be to append the css information to the sink because this object is unique for every request. If it is possible to access the sink object on your package it would be easy to append the bundled css to the sink and then I can append it to the HTML on Server.

The other option would be to use it like in your comment. Then it would be more handy to create a React Provider which gets all the bundled css and outputting it. Maybe it could also be possible to "auto-fetch" on any file which is including a css file? But I dont think so.

I am not 100% sure which would be the best solution to solve this but in my case I would think that the sink method would be the easiest because then I am not in the duty to handle outputing the bunbled css on every file which is including style files.

@TimoRuetten
Copy link
Author

Hey @nathantreid - I just got your package wrong. I thought that on every request only the needed css will get generated on server - but thats not true. The css which is needed will be generated on the server start (which makes sense - of course).

I was able to clone your package to my local packages directory and will try to do a update which would be make it able to return the needed css on server. My goal would to be to make it possible to export the css like in your example but also to add the generated css to the sink on every request, so it would be possible to send only the needed css of every request back to the client.

Will let you know when I had success to do so.

@arggh
Copy link

arggh commented May 31, 2019

Probably related, as I was just on my way to ask @nathantreid if it's possible with the current implementation to merge these multiple stylesheets into one (?):

css-modules-issue

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

No branches or pull requests

3 participants