Styled-jsx: Rewrite external styles to allow dead code elimination

Created on 11 Nov 2017  路  3Comments  路  Source: vercel/styled-jsx

When using the css tag, styles are rewritten to include both the global and scoped version of them because we cannot guess how the user wants to use them.

So

import css from 'styled-jsx/css'

export default css`body { background: red }`

Becomes

var _defaultExport = ['body{background:red;}'];
_defaultExport.__hash = '1536091005';
_defaultExport.__scoped = ['body.jsx-3002312892{background:red;}'];
_defaultExport.__scopedHash = '3002312892';
exports.default = _defaultExport;

I bet that most of the times users consume them either as global or scoped only. In any case we should change the way how we rewrite them like so:

  • css generates scoped styles only
  • css.global generates global styles only
  • (optional) css.universal generates global and scoped styles
  • css.resolve converts styles to an object literal that contains the the scoped className for the styles and a styles property which references a style component - discussion: (#383 (comment)) example:
// this
const myStyles = css.resolve`div { color: red }`

// is transpiled to
import _JSXStyle from 'styled-jsx/style'
const myStyles = {
  className: 'jsx-123',
  styles: <_JSXStyle styleId={123} css={`div.jsx-123 { color: red }`} />
}

// which can be used as follow:

<div className={myStyles.className}>
   howdy
   {myStyles.styles}
</div>

css.resolve should be a babel macro (so people can use it with Create React App for example).

All the solutions above should support dynamic styles too and optimizeForSpeed.

Except for css.resolve all the others need to transpile to the compiled css string and its stylesId. We use them like this right now:

// this
import styles from '../foo'
<style jsx>{styles}</style>

// becomes
import _JSXStyle from 'styled-jsx/style'
import styles from '../foo'

<_JSXStyle styleId={styles.__scopedHash} css={styles} />

Look at the following fixtures/snapshots to see an example of input > output:

  • Dynamic styles: [[fixture](https://github.com/zeit/styled-jsx/blob/master/test/fixtures/attribute-generation-modes.js)] [[snapshot](https://github.com/zeit/styled-jsx/blob/master/test/__snapshots__/attribute.js.snap)]
  • css: [[fixture](https://github.com/zeit/styled-jsx/blob/master/test/fixtures/styles.js)] [[snapshot](https://github.com/zeit/styled-jsx/blob/master/test/__snapshots__/external.js.snap)]

The current code for css is babel-macro like and can be found here

If we manage do to so then styled-jsx could become a tool to use regular .CSS files in js/react with a plugin like this https://github.com/coox/styled-jsx-css-loader

discussion enhancement help wanted

All 3 comments

I am interested to work on this issue as I see this to be a great learning opportunity to know about css-in-js, writing babel plugin and tinkering with babel-macro.
PS: I have very little experience writing babel plugins

@abiduzz420 hi! That's not a problem at all. Probably the scope of this feature is a bit broad, specially for someone who's never written a plugin before. That said if you or anybody else want to give it a shot, I would suggest to watch Kent's seminar about ASTs, and try to write a super dummy plugin on https://astexplorer.net

This feature can be split in two PRs. The first one should rewrite the current implementation of css to support the new requirements (see above). This should be the best way to start off I think. In a second PR we can re-use most of the code to implement css.resolve and finally make a babel macro plugin (I can do that in a 3rd PR).

Just fork and clone the project, install the dependencies, create a branch and open up test/external.js and do the following:

-test('transpiles external stylesheets', async t => {
+test.only('transpiles external stylesheets', async t => {
   const { code } = await transform('./fixtures/styles.js')
-  t.snapshot(code)
+  console.log(code)
+  // t.snapshot(code)
 })

Now run the tests:

npm test

Make some changes in src/babel-external.js to the visitor/related functions and re run the tests.

fixed in #422

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adamyonk picture adamyonk  路  3Comments

stevensacks picture stevensacks  路  4Comments

maxchehab picture maxchehab  路  3Comments

anderseide picture anderseide  路  5Comments

soulchainer picture soulchainer  路  5Comments