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

cssx syntax compiled to jss json dsl #2

Closed
kof opened this issue Apr 18, 2016 · 27 comments
Closed

cssx syntax compiled to jss json dsl #2

kof opened this issue Apr 18, 2016 · 27 comments

Comments

@kof
Copy link

kof commented Apr 18, 2016

I am wondering if you could imagine to compile cssx syntax to json dsl of jss and then use jss lib for rendering at runtime.

@kof kof changed the title cssx syntax compiled to jss dsl cssx syntax compiled to jss json dsl Apr 18, 2016
@krasimir
Copy link
Owner

Interesting. Give me few days and will I'll see how it goes.

@kof
Copy link
Author

kof commented Apr 19, 2016

I think the negative feedback I have got so far to jss was from people who are not ready to write CSS in JSON. They want CSS syntax. This is also the reason for popularity of css-modules.
At the same time the amount of advantages of runtime-rendered CSS is so huge, I don't even want to go ever back to the server rendered CSS, exception are some optimizations for e.g. bootstrapping application.

I have tried to put it on the list here https://github.com/jsstyles/jss/blob/master/docs/benefits.md and also did this presentation recently https://slides.com/kof/javascript-style-sheets/

@ai
Copy link

ai commented Apr 19, 2016

With JSS we will have many already written plugins. So I really want CSSX + JSS solution :D.

@tunnckoCore
Copy link

I also will follow this one, because I'm working on https://github.com/postjson/postjson idea, which also could be useful and interesting in some way. :)

@kof
Copy link
Author

kof commented Apr 19, 2016

@tunnckoCore postjson is very interesting, sounds like I could use postjson in jss as a lower level lib.

@tunnckoCore
Copy link

@kof thanks! Yea, maybe. I'm still thinking what would be the best approach and API for the plugins - there are two ways for the moment haha. I'm open for ideas (feel free to open issues there) and would be happy to hear what you need.

@krasimir
Copy link
Owner

@kof @ai @tunnckoCore Yesterday I did an update of CSSX allowing the generation of plain JavaScript literal. I.e. it's not CSSX lib specific. Here is an example:

var styles = function () {
 return <style>
   .container {
     width: 100%;
   }
   @media (max-width: 600px) {
     .container {
       width: 50%;
     }
   }
 </style>;
}

It is transpiled to:

var styles = function () {
  return (function () {
    var _4 = {};
    _4['width'] = '50%';
    var _3 = {};
    _3['width'] = '100%';
    var _2 = [];

    _2.push(['.container', _3]);

    var _5 = {},
        _6 = [];
    _5['@media (max-width: 600px)'] = _6;

    _6.push(['.container', _4]);

    _2.push(_5);

    return _2;
  }.apply(this));
};

Which is the following JSON:

[
  [
    ".container",
    {
      "width": "100%"
    }
  ],
  {
    "@media (max-width: 600px)": [
      [
        ".container",
        {
          "width": "50%"
        }
      ]
    ]
  }

So it is definitely possible writing a .toJSON method. @kof can you please point me to a place where I could see the jss dsl specification (or at least an example containing all the different types of nodes).

@kof
Copy link
Author

kof commented Apr 21, 2016

Let me know if it good enough json-dsl

@kof
Copy link
Author

kof commented Apr 21, 2016

I saw so much similar code in the cssx client to what jss and it's plugins do, it really makes sense to use jss for client side rendering and combine our efforts in making it better.

@trusktr
Copy link

trusktr commented Apr 23, 2016

I like JSS's Object-literal syntax better. Also, why not just compile to the literal form rather than to the pieces and putting them together? Suppose for example we have this:

var stylesheet = <style>
   .container {
     width: 100%;
   }
   @media (max-width: 600px) {
     .container {
       width: 50%;
     }
   }
</style>

stylesheet.attach() // <-- better leaving it up to the user to decide when to attach/detach

then it'd compile to this:

let stylesheet = jss.createStyleSheet({
    '.container': {
        width: '100%'
    },
    '@media (max-width: 600px)': {
        '.container': {
            width: '50%'
        }
    }
})

stylesheet.attach() // <-- better leaving it up to the user to decide when to attach/detach

Maybe you guys can agree on a common object-literal format, then end users can choose which runtime they prefer, as either would be compatible with the compiled output. In that case, then we'd want to compile to this:

let styles = {
    '.container': {
        width: '100%'
    },
    '@media (max-width: 600px)': {
        '.container': {
            width: '50%'
        }
    }
}

and we'd let the user choose which runtime to use:

let stylesheet = cssx('my-styles', styles)
// or
let stylesheet = jss.createStyleSheet(styles)

@trusktr
Copy link

trusktr commented Apr 23, 2016

Example where we take advantage of JSS' collision-free class names:

var style = <style>
   container {
     width: 100%;
   }
</style>
jss.createStyleSheet(style)

would compile to

var stylesheet = {
   container: {
     width: '100%'
   }
}
jss.createStyleSheet(style)

which generates at runtime:

<style>
  .container-jss-0 {
    width: 100%;
  }
</style>

@krasimir
Copy link
Owner

@trusktr That's exactly what I'm working on right now. I'm changing the transpiler of CSSX to output non-CSSX specific code.

krasimir pushed a commit that referenced this issue Apr 23, 2016
krasimir pushed a commit that referenced this issue Apr 23, 2016
krasimir pushed a commit that referenced this issue Apr 24, 2016
krasimir pushed a commit that referenced this issue Apr 24, 2016
krasimir pushed a commit that referenced this issue Apr 29, 2016
@krasimir
Copy link
Owner

@kof @ai @tunnckoCore @trusktr

Finally I managed to release a jss compatible version - 5.0.0. I bumped the major version twice because I had to make changes everywhere :)

  • cssx transpiler now generates JSON which is (I believe) the same as the one that jss works with. There are no arrays of arrays anymore. For example:
var styles = <style>
  button {
    font-size: 12;
    &:hover {
      background: blue;
    }
  }
  ctaButton {
    extend: button;
    &:hover {
      background: red;
    }
  }
  @media (min-width: 1024px) {
    button {
      minWidth: 200;
    }
  }
</style>;

is transpiled to:

var styles = (function () {
  var _1 = {},
      _2 = {},
      _3 = {},
      _4 = {},
      _5 = {},
      _6 = {},
      _7 = {};
  _2['background'] = 'blue';
  _3['&:hover'] = _2;
  _3['font-size'] = '12';
  _4['background'] = 'red';
  _5['&:hover'] = _4;
  _5['extend'] = 'button';
  _6['minWidth'] = '200';
  _7['button'] = _6;
  _1['button'] = _3;
  _1['ctaButton'] = _5;
  _1['@media (min-width: 1024px)'] = _7;
  return _1;
}.apply(this));

which if we execute outputs:

{
  "button": {
    "&:hover": {
      "background": "blue"
    },
    "font-size": "12"
  },
  "ctaButton": {
    "&:hover": {
      "background": "red"
    },
    "extend": "button"
  },
  "@media (min-width: 1024px)": {
    "button": {
      "minWidth": "200"
    }
  }
}
  • I also had to update cssx client-side library to work with the new format. Updating all the tests in all the packages and the examples.

There is a working example that uses jss here (the source code is here).

I'll be happy if someone tests a more complex cases so we see if it works with production-ish ready code.

@kof
Copy link
Author

kof commented Apr 29, 2016

Nice, will try it out soon. Do you think it makes for cssx to focus on cssx as a language and continue providing all transpiling tools, but remove the cssx client and fully rely on jss?

Also I think it would be nice to add cssx as an option on the jss repl http://jsstyles.github.io/repl/
Thinking of a select box which allows to switch between them.

@kof
Copy link
Author

kof commented Apr 29, 2016

Regarding json output from cssx: it would be nice to get number values from those which have no unit. This allows jss-default-unit plugin to set default unit automatically.

@krasimir
Copy link
Owner

Regarding json output from cssx: it would be nice to get number values from those which have no unit. This allows jss-default-unit plugin to set default unit automatically.

I just filed an issue about that #6

Do you think it makes for cssx to focus on cssx as a language and continue providing all transpiling tools, but remove the cssx client and fully rely on jss?

I already started thinking in this direction. I removed 3 features of the CSSX client-side library and it is really simple now. I'm not planning to extend it soon. Just updated the docs so cssx lib is more like an alternative of jss.

@kof
Copy link
Author

kof commented Apr 29, 2016

If you need something for cssx jss doesn't allow to do, just create an issue on jss repository.

@tunnckoCore
Copy link

tunnckoCore commented Apr 29, 2016

Hey! This going very interesting! Soon is my turn to review the jss core more deeply (@kof help will be appreciated), meaning what it does actually, what are the processes/steps. And you can help with PostJSON - it can be third direction.

Btw I'm going deeper and deeper, today pushed https://github.com/limonjs/limon (pluggable lexer) and going to push "pluggable" parser. When finish them both, I'll start playing with few things - json lexer, parser and stringifier; semver lexer, parser and stringifier; and porting PostCSS's tokenizer (because it is awesome).

@krasimir, междудругото парсъра мисля да го кръстя лиман хахаха - лимон и лиман. За жалост лагуна е заето, lemon също, та затова лимон и лиман - само това, че разликата е само в една буква ме притеснява и дразни. Чудя се. Anyway.

@kof
Copy link
Author

kof commented Apr 29, 2016

@tunnckoCore interesting things yes, ping me on gitter if you have any questions, I still didn't have time to think how we could extract the part of jss which is about the ast and it's manipulations by plugins into something generic like postjson. But I think it's definitely possible, it's just a load of work.

@tunnckoCore
Copy link

Yea, done. :)

@trusktr
Copy link

trusktr commented May 1, 2016

@krasimir Idea: maybe let the user choose the runtime:

// User chooses CSSX:

let style = <style runtime="cssx">
  .foo {
    height: 100%;
  }
</style>

// or, maybe instead of <style>, template tag syntax:
let style = cssx`
  .foo {
    height: 100%;
  }
// User chooses CSSX:

let style = <style runtime="jss" named="false">
  .foo {
    height: 100%;
  }
</style>

let style2 = <style runtime="jss">
  foo {
    height: 100%;
  }
</style>

// or, maybe instead of <style>, template tag syntax:
let style = jss`
  foo {
    height: 100%;
  }
`

But I'm not sure how to enable named:false in the template tag form of the jss example, so maybe the <style> tag is more useful.

Also, what happens if a user places a <style> tag in a React component, which is bound to happen if CSSX gained wide adoption:

render() {
  return <div>
    <h1>My React App</h1>
    <style runtime="jss">
      .foo {
        height: 100%;
      }
    </style>
  </div>
}

Maybe a compile-timeerror would be thrown in that case, with an explanation pointing to some docs on how to use CSSX?

Or maybe you can somehow scope that style to the element where the <style> tag is located? Maybe it'd require matching rules. F.e.:

render() {
  return <div>
    <h1 className="foo">My React App</h1>
    <style runtime="jss">
      .foo {
        color: red;
      }
    </style>
  </div>
}

That's just an outer-level idea. I'm not sure what JS that'd actually translate to. Maybe it'd remove the stylesheet entirely from the JSX, before JSX handles it, so it'd look like the following before JSX transforms the code:

var _cssx_classes1 = (function () {
  ...
}.apply(this));

render() {
  return <div>
    <h1 classname="{_cssx_classes1.foo}">my react app</h1>
  </div>
}

@krasimir
Copy link
Owner

krasimir commented May 6, 2016

@trusktr thank you for commenting here. Here is my feedback:

Regarding the runtime attribute

CSSX is translated to JavaScript similarly to JSX. The difference is that CSSX result is not doing anything. It's not using any library. It's just a creation of object literal. What happen with this next depends on the developer. For example:

let style = <style>
  .foo {
    height: 100%;
  }
</style>

Is transformed to:

let style = (function () {
  var _1 = {},
      _2 = {};
  _2['height'] = '100%';
  _1['.foo'] = _2;
  return _1;
}.apply(this));

which is the same saying:

let style = {
  ".foo": {
    "height": "100%"
  }
}

How the style variable is used is completely up to the developer. So, if we add a runtime attribute we'll make a big assumption which I want to escape from.

Also, what happens if a user places a <style> tag in a React component.

We'll indeed get an error. If we have to provide a message that points the developer to CSSX docs then we have to contribute to JSX transpilation which will assume that by adding <style> you mean CSSX which is not quite right. You may have a React class component which name is style.

Or maybe you can somehow scope that style to the element where the <style> tag is located?

There is react-cssx project where we have a CSSX component and we do have scoping of CSSX styles. However, I'm thinking that the project here should be really about transpiling. Even though we have a consumer of the transpiled code will be nice to use jss or css-modules instead because they did a good progress and have some sort of adoption already.

Maybe it'd remove the stylesheet entirely from the JSX, before JSX handles ...

This requires changes in how JSX is transpiled which is part of babylon project. If I have to submit a PR with this I'm 99% sure that it will be rejected because (a) it's a custom thing and (b) will decrease the performance of the transpiler.

@trusktr
Copy link

trusktr commented May 6, 2016

@krasimir

It's just a creation of object literal. What happen with this next depends on the developer.

Maybe "format" is better than "runtime". So that way a developer can choose between CSSX or JSS object formats, depending on what the developer prefers, then do as needed with the object.

About the JSX stuff, for sure. Just throwing some ideas out there. I myself am fine just having the object transpiled from the CSS syntax, f.e.

jss.createStyleSheet(<style format="jss">
  ...
</style>)

@krasimir
Copy link
Owner

krasimir commented May 6, 2016

So that way a developer can choose between CSSX or JSS

I adopted the JSS format. So now CSSX and JSS use same thing. (I mean in the released version 5).

@trusktr
Copy link

trusktr commented May 6, 2016

adopted the JSS format

Oh okay, gotcha. That works in my case since I'm using JSS. :]

Can't wait to try this soon!

@krasimir
Copy link
Owner

krasimir commented May 6, 2016

Great. You may be interested in this example.

@trusktr
Copy link

trusktr commented May 20, 2016

Just got to try this for the first time finally (cssx-loader + jss). So awesome!

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

5 participants