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

[wip] Transpile external css #100

Closed
wants to merge 4 commits into from
Closed

[wip] Transpile external css #100

wants to merge 4 commits into from

Conversation

giuseppeg
Copy link
Collaborator

fixes #83

@giuseppeg
Copy link
Collaborator Author

@rauchg @nkzawa early feedbacks are appreciated, what do you think about the syntax? should we stick with the style tag instead?

@rauchg
Copy link
Member

rauchg commented Feb 1, 2017

  1. Isn't src better?
  2. How would we keep track of the file for hot code reloading?

@giuseppeg
Copy link
Collaborator Author

Isn't src better?

I am going for <style jsx src="./styles.js" />

How would we keep track of the file for hot code reloading?

We don't have to it should happen automatically because the external stylesheet is a regular js module. Not sure if I am missing something though but I will able to tell soon – I am half way through implementing the import injection and style tag replacement :)

Copy link
Collaborator Author

@giuseppeg giuseppeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to think if this solution could work at all since the hash computation could not be possible with this approach

return attr && attr.get('value').node.value
}

const getImport = ([styleText, styleId, importPath]) => (
Copy link
Collaborator Author

@giuseppeg giuseppeg Feb 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to fix this (and maybe call it makeImportExternal) because transpiled (external) stylesheets are exporting a single object (default)

@giuseppeg
Copy link
Collaborator Author

I thought a little bit about this approach and I think that it could work in case we are cool with allowing only a single style tag when using external css:

/* valid */

export default () => (
  <p>
      test
      <style jsx src="./style.js" />
  </p>
)

/* not valid */

export default () => (
  <p>
      test
      <style jsx>{`p { font-size: 3em }`}</style>
      <style jsx src="./style.js" />
  </p>
)

This is because I would use the resolved src path for hashing.

@nkzawa @rauchg if you like this solution and think that this feature could add value to the library I will finalize it and put in a mergeable state.

@nkzawa
Copy link
Contributor

nkzawa commented Feb 2, 2017

I think it can work even if there are multiple style elements since we already support with global ?

export default (
<style jsx>{`
p { color: ${foo} }
`}</style>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this syntax mean we can't import others from imported styles ? 🤔

Copy link
Contributor

@arunoda arunoda Feb 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we simply for a template string like:

const foo = 'red'

export default `
  p { color: ${foo} }
`

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be the best api however is not that easy to achieve this because in the consumer file (the one that imports this) we need to hash `p { color: ${foo} }` and once we have the hash we need to transform the css (add the prefix to it etc).

@giuseppeg
Copy link
Collaborator Author

giuseppeg commented Feb 2, 2017

I think it can work even if there are multiple style elements since we already support with global ?

when external files are transpiled they don't have knowledge of the consumer component therefore when transforming the css we don't have all of the necessary information to create a proper hash (jsxId).

/* external file */

`p { color: red }`

The jsxId here is hash(`p { color: red }`) === 'woot'
i.e. p[data-jsx="woot"] { color: red }

/* consumer */

`p { font-size: 3em }` // own styles
src="./style.js"

The jsxId in this case will be hash(externalIdReference + `p { font-size: 3em }`) === 'wat'

i.e. p[data-jsx="wat"] { font-size: 3em }
and elements are scoped using wat: <p data-jsx="wat">test</p>
external styles won't apply because they have id woot instead.

Does this syntax mean we can't import others from imported styles ?

Uh this is kinda tricky, I am using that syntax so that I can tell whether a module is an external styled-jsx sheet. If we don't do so then we'd need a separate plugin to transpile external files.

@giuseppeg
Copy link
Collaborator Author

giuseppeg commented Feb 2, 2017

The only way I can think of to allow multiple style elements is to transpile external css like so:

p[data-jsx~="woot"] { color: red }

(notice the ~)

and the consumer eventually will be:

p[data-jsx~="wat"] { font-size: 3em }

and

<p data-jsx="woot wat">test</p>

@rauchg
Copy link
Member

rauchg commented Feb 3, 2017

The other thing I've been thinking about is that we could have "flow" analysis. This would work:

import style from './style'
export default (
  <div>
    <p>hi</p>
    <style jsx>{style}</style>
  </div>
)

and this would work:

cons style = `
  p { color: red }
`
export default (
  <div>
    <p>hi</p>
    <style jsx>{style}</style>
  </div>
)

@giuseppeg
Copy link
Collaborator Author

🤔 I thought about case 1 for external files but in order to do so we'd need to hash using the resolved file name. Also when transpiling an external file we need a way to tell if that's just an external stylesheet or any other module/react component. That's why in my wip I export JSX (a style tag).

@rauchg
Copy link
Member

rauchg commented Feb 3, 2017

Why can't we just hash based on contents? The idea is that by analyzing the "flow" we can access the raw string exactly the same as if it was inlined inside <style jsx>. Hence, IMHO, why the approach is elegant

@rauchg
Copy link
Member

rauchg commented Feb 3, 2017

It also seems like a natural complement of the work we've been doing to allow constants inside the source

@tgoldenberg
Copy link

@rauchg based on .jsx syntax, my first reaction was to automatically assume that you could do this <style jsx>{style}</style>. The fact that it does not do this goes against basic React syntax conventions. Also, not being able to load multiple style tags seems counter-intuitive, as well. If we are going to break people's expectations, we should make it very clear in the beginning, in order to avoid unnecessary confusion. Will be really excited to see the solution in action, and great work!

@rauchg
Copy link
Member

rauchg commented Feb 3, 2017

@tgoldenberg all of those problems are tractable. We tend to ship and iterate.

@rauchg
Copy link
Member

rauchg commented Feb 3, 2017

Also, whenever we go against intuition, we attempt to provide very clear error messages: for example, if you're trying to use prop or state inside the style text

@giuseppeg
Copy link
Collaborator Author

giuseppeg commented Feb 4, 2017

Don't get me wrong I actually like the idea of flow analysis.

The idea is that by analyzing the "flow" we can access the raw string exactly the same as if it was inlined inside <style jsx>.

This means that we'd need to read (or eval) external files as we transpile and in general the traversal would get a bit trickier. Also we may need to revisit the expressions logic since at the moment we just replace them with placeholders before hashing (we don't analyse them).

In the end though probably this will result in the better api.

@giuseppeg
Copy link
Collaborator Author

giuseppeg commented Feb 4, 2017

as I said maybe for external files we can hash the resolved file path instead of the content (css)

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

Successfully merging this pull request may close these issues.

Allow for importing styles
5 participants