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 pass an existing element to the DOM Renderer #231

Closed
nathanmarks opened this issue May 6, 2016 · 35 comments
Closed

Option to pass an existing element to the DOM Renderer #231

nathanmarks opened this issue May 6, 2016 · 35 comments

Comments

@nathanmarks
Copy link
Member

nathanmarks commented May 6, 2016

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().

@kof
Copy link
Member

kof commented May 6, 2016

Can you explain the goal please?

@nathanmarks
Copy link
Member Author

@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.

@kof
Copy link
Member

kof commented May 6, 2016

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?

@kof
Copy link
Member

kof commented May 6, 2016

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

@kof
Copy link
Member

kof commented May 6, 2016

See #221

@kof
Copy link
Member

kof commented May 6, 2016

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

@nathanmarks
Copy link
Member Author

nathanmarks commented May 6, 2016

@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.

@kof
Copy link
Member

kof commented May 6, 2016

Have you thought about trying the first approach?

@kof
Copy link
Member

kof commented May 6, 2016

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?

@nathanmarks
Copy link
Member Author

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.

@nathanmarks
Copy link
Member Author

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

@kof
Copy link
Member

kof commented May 6, 2016

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

wdym by "stylesheet features" ...

@nathanmarks
Copy link
Member Author

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

@kof
Copy link
Member

kof commented May 6, 2016

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

@nathanmarks
Copy link
Member Author

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

@kof
Copy link
Member

kof commented May 6, 2016

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

@nathanmarks
Copy link
Member Author

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.

@kof
Copy link
Member

kof commented May 6, 2016

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

@kof
Copy link
Member

kof commented May 6, 2016

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

@nathanmarks
Copy link
Member Author

@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.

@kof
Copy link
Member

kof commented May 6, 2016

So how would you do it?

@kof
Copy link
Member

kof commented May 6, 2016

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.

@nathanmarks
Copy link
Member Author

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.

@nathanmarks
Copy link
Member Author

nathanmarks commented May 6, 2016

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 }
);

@kof
Copy link
Member

kof commented May 6, 2016

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

@nathanmarks
Copy link
Member Author

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);
    }
  }
};

@nathanmarks
Copy link
Member Author

nathanmarks commented May 6, 2016

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

@kof
Copy link
Member

kof commented May 6, 2016

Looks overcomplicated.

@kof
Copy link
Member

kof commented May 6, 2016

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

@kof
Copy link
Member

kof commented May 6, 2016

maybe some hashing algorithm.

@nathanmarks
Copy link
Member Author

nathanmarks commented May 6, 2016

@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.

@kof
Copy link
Member

kof commented May 6, 2016

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

@kof
Copy link
Member

kof commented May 6, 2016

However I see a need for something much nicer.

@nathanmarks
Copy link
Member Author

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

kof added a commit that referenced this issue May 6, 2016
@kof
Copy link
Member

kof commented May 6, 2016

added and published

@kof kof closed this as completed May 6, 2016
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

2 participants