Jss: Option to pass an existing element to the DOM Renderer

Created on 6 May 2016  路  35Comments  路  Source: cssinjs/jss

Are you open to a PR that allows us to provide an element for the DOM Renderer to use instead of creating its own?

This would help me implement reconciliation with server side rendering output using the built-in renderer via jss.createStyleSheet().

Most helpful comment

added and published

All 35 comments

Can you explain the goal please?

@kof

I'm rendering <style> tags on the server in the document <head> so that there is no flash of unstyled content before the app is loaded.

Right now, when the client app loads up, jss is creating new stylesheets in addition to those rendered by the server.

On the client, I want to check if that stylesheet already exists in the DOM and recycle the element.

I'm rendering <style> tags on the server in the document <head> so that there is no flash of unstyled content before the app is loaded.

jss is also rendering style tags in the head. what is your server side environment, no DOM?

Right now, when the client app loads up, jss is creating new stylesheets in addition to those rendered by the server.

You mean for the same components?

On the client, I want to check if that stylesheet already exists in the DOM and recycle the element.

Please explain "recycle" ... just the style element or you want to recycle the rules from CSS?

What you do right now, is kinda half solved out of the box, we need to cover this anyways properly for jss users.

See #221

I think you are trying the second approach described in #221

@kof

Converting jss styles to regular css server-side, once js components, regenerate CSS from js styles. (possible now)

That's what I'm trying to do.

I will be using the contents of the style tag until the next change. I wasn't planning on trying to do any sort of hydration just yet.

Have you thought about trying the first approach?

But in any case I would like to support the second approach too. So in other words you need to give jss renderer the style element which is already created on the server to use it for regeneration to avoid head pollution, right?

I/we need stylesheet features which is why I am trying jss.

Right now I'm working on a proof of concept for a JS style setup to fit my use case using jss.

Yep, that's exactly what we need to do.

I/we need stylesheet features which is why I am trying jss.

wdym by "stylesheet features" ...

@kof CSS features that you can't use inline such as pseudo classes.

ok, so it was just a self contained statement, unrelated to the discussion.

@kof You suggested the (1) approach which was inlining the styles

no, you misunderstood the meaning of inlining there. I will expand on that in the original issue.

Ah, sorry!

Anyways, back to the goal. Right now this is what happens because there is nothing marrying them:

img

Being able to give jss the style element via createStyleSheet() would give me the ability to use the one rendered by the server.

I see 2 additional ways to avoid head pollution by style tags:

  1. remove original style tag when the new one will be generated
  2. render only one style tag for all styles rendered serverside

You could render all styles on the server in one style element by using https://github.com/jsstyles/jss/blob/master/docs/js-api.md#a-style-sheets-registry

@kof

I prefer to keep the render output on the server the same as what the client would render -- 1 stylesheet per component.

(1) is a possible alternative, but using the same node that jss rendered styles in on the server with toString() is the more natural approach to me.

So how would you do it?

An easy way is to pass an option to .createStyleSheet(...) and use that option within the renderer. But I already see that it's gonna be ugly when using it.

Using an id/hash created from the original styles (before they are given to jss) as the meta option in createStyleSheet(). On the client, before I create a jss stylesheet I can check before creating the style sheet if a style element with the correct hash exists.

Why would it be ugly? (added an example property to my current code)

styleSheet.sheet = this.jss.createStyleSheet(
  styleSheet.getRuleDefinitions(this.theme),
  { element: myElement, meta: styleSheet.name, named: false }
);

Lots of questions in this code snippet, can you show a full class example?

import { create as createJss } from 'jss';
import nested from 'jss-nested';
import camelCase from 'jss-camel-case';
import defaultUnit from 'jss-default-unit';

export function createStyleManager({
  jss = createJss().use(nested(), camelCase(), defaultUnit()),
  theme = {}
} = {}) {
  return Object.create(styleManager, {
    sheetMap: { value: new WeakMap() },
    jss: { value: jss },
    theme: { value: theme }
  });
}

const styleManager = {
  /**
   * Attaches a styleSheet object
   */
  attach(styleSheet) {
    const counter = this.sheetMap.get(styleSheet) || 0;

    if (counter === 0) {
      if (!styleSheet.hasOwnProperty('sheet') || styleSheet.sheet.options.jss !== this.jss) {
        styleSheet.sheet = this.jss.createStyleSheet(
          styleSheet.getRuleDefinitions(this.theme),
          { meta: styleSheet.name, named: false }
        );
      }
      styleSheet.sheet.attach();
    }

    this.sheetMap.set(styleSheet, counter + 1);
  },

  /**
   * Detach a styleSheet object
   *
   * @param  {Object} styleSheet - styleSheet Object
   */
  detach(styleSheet) {
    const counter = this.sheetMap.get(styleSheet) - 1;
    if (counter) {
      this.sheetMap.set(styleSheet, counter);
    } else {
      styleSheet.sheet.detach();
      this.sheetMap.delete(styleSheet);
    }
  }
};

Note -- this file is from an experimental styling setup, I took some cues from your ideas in react-jss for it.

Looks overcomplicated.

Having some sort of id for a style sheet, which is predictable and unique at the same time, would make it easy to automate.

maybe some hashing algorithm.

@kof That's what I was going to do, but was waiting to see if I could get an option added to provide the element first.

To avoid doing right now a good solution and just support your case, I can add element option to the style sheet.

However I see a need for something much nicer.

That would be great.

I agree that something better is needed. Right now I'm trying to validate a proof of concept to solve some issues with basic inline styling that we have been having.

I would like to discuss a solution to implement better support for this natively in jss. Once I have some conclusions I'll probably engage in some of the issues you have open such as #221

added and published

Was this page helpful?
0 / 5 - 0 ratings

Related issues

antoinerousseau picture antoinerousseau  路  3Comments

kof picture kof  路  6Comments

AleshaOleg picture AleshaOleg  路  3Comments

oliviertassinari picture oliviertassinari  路  4Comments

HenriBeck picture HenriBeck  路  4Comments