Next.js: Need update in example code about external stylesheet

Created on 30 Jun 2017  Â·  18Comments  Â·  Source: vercel/next.js

In example code about external stylesheet https://github.com/zeit/next.js/tree/master/examples/with-global-stylesheet , it still has dangerouslySetInnerHTML. According to this styled-jsx improvement` https://github.com/zeit/styled-jsx/pull/148, we can reference imported stylesheet now.

I tried to change code and it works.

 export default () =>
   <div>
-    <style dangerouslySetInnerHTML={{ __html: stylesheet }} />
+    <style jsx global>{stylesheet}</style>
     <p>ciao</p>
   </div>

The dangerouslySetInnerHTML does not look right and might trigger eslint error. If my understanding is right, I'll submit a PR for this.

example

Most helpful comment

Alright @mocheng it works indeed! Apparently a combo of babel-plugin-wrap-in-js and webpack's raw-loader does the trick. But I wouldn't use it in production yet because the babel plugin doesn't have tests and when doing server side rendering styled-jsx writes the css in a style tag in the page which means that it is never cached therefore if you have a lot of css and big external files your page size can grow considerably.

Since there is a solution though we might explore ways to allow this in a performant way – maybe we should write external compiled files for SSR in actual .css files and then load them using a regular link tags rather than an inline style.

All 18 comments

@giuseppeg this won't work right? Since it's not a JS export

In my case, using <style jsx global> for the stylesheet results in this:

Module build failed: SyntaxError: The Identifier stylesheet is either undefined or it is not an external StyleSheet reference i.e. it doesn't come from an import or require statement

@timneutkens correct, styled-jsx transpiles only exported js strings/template literals.
Maybe with something like webpack raw-loader you can make it work but afaik only client side code gets bundled via webpack so it won't work for SSR.

@eliot-akira in your case the error could be due to the fact that you don't import the stylesheet.

@giuseppeg thanks for the confirmation 👌

@giuseppeg @timneutkens Sorry to bother you, but it does work in SSR.

With this commit https://github.com/mocheng/next.js/commit/7ac857aac79b360b95becd92a3cb3a416ddb76ac , the server-side-rendered HTML has .foo{color:green} in its <style id="__jsx-style-14162456061"> tag of <head>.

I understand that @giuseppeg 's point is that webpack config only affects browser side bundling. But, this change proves that it work in SSR by injecting style into inline style.

afaik only client side code gets bundled via webpack so it won't work for SSR
@mocheng this was more like "I think that...", I was looking for someone to confirm :)

It seems that in the example webpack is doing the magic, but if it would be very cool if that works for ssr too. Have you also tried without the global property on the style tag?

@giuseppeg without global, the inline style tag would have something like .foo[data-jsx-ext~="24162456061"]{color:green} which is scoped style.

With global, the inline style tag would have .foo{color:green}.

This is really cool 😲

I will give it a try, if this works it is amazing because it means that people can write regular CSS in separate .css files and benefit from tooling etc.

Alright @mocheng it works indeed! Apparently a combo of babel-plugin-wrap-in-js and webpack's raw-loader does the trick. But I wouldn't use it in production yet because the babel plugin doesn't have tests and when doing server side rendering styled-jsx writes the css in a style tag in the page which means that it is never cached therefore if you have a lot of css and big external files your page size can grow considerably.

Since there is a solution though we might explore ways to allow this in a performant way – maybe we should write external compiled files for SSR in actual .css files and then load them using a regular link tags rather than an inline style.

@giuseppeg I once tried to utilize ExtractTextPugin to extract CSS/SCSS into bundle CSS files to be referenced in style tag in head, but it is hard (if not impossible) to do it by customizing webpack config. I bet it would be easier if next.js itself provides such feature.

I think that we could do that in styled-jsx I'll think about it and write a proposal. The api could be <style jsx as="link">

Noticed styles/index.scss is bundled in commons.js
Basically same css duplicated - inlined into the page and part of app.js
Any tips how to exclude it from app.js?
image

for regular global styles files I would just serve them from /static and include them in the page with a link tag. You can use a prebuild script to copy or build them into static.

So is it normal behaviour with bundling?
In my case I have external component-based .styl files that are imported and injected to <style jsx> so it's not really regular global styles.

import ComponentStyles from 'components/my-component.styl';
...
<style jsx>{ComponentStyles}</style>

@ilionic it'll be inlined in the page when you do server side rendering and in your bundle in case you load that page on the client (via router/ajax)

see also the conversation above https://github.com/zeit/next.js/issues/2413#issuecomment-314212017

Ok I see, it's about finding compromise between performance, page size and dev experience.
Currently using combination of both methods - global css file with some theme dependencies ( like bootstrap ) above the fold loaded using link tag in non-render blocking way. It's rarely changed and cacheable.

Critical css above-the fold is inlined ( using style jsx ) also it's nicer dev experience having component based styles with hot reload.
It works but as you pointed @giuseppeg page size started growing considerably ( including js bundle )
So until we can migrate from global css to css-in-js solutions looking for possible optimisations.

Was this page helpful?
0 / 5 - 0 ratings