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

How can I externalize the css to a separate file for browsers to cache? #1479

Closed
YarivGilad opened this issue Mar 22, 2017 · 13 comments · May be fixed by hellomouse/next.js#15, ajesse11x/next.js#541 or ajesse11x/next.js#542

Comments

@YarivGilad
Copy link

The default behavior is to inject all styles to the HTML in a style tag.
How can I make sure all styles are cached by browsers separately when I update my app?
Is there an example using extract-text-webpack-plugin in a next.config.js or is there another recommended way to achieve that?

@albinekb
Copy link
Contributor

add a plain old <link rel="stylesheet" type="text/css" href="style.css">?

@iaincollins
Copy link
Contributor

iaincollins commented Mar 22, 2017

You might find the example in nextjs-starter helpful.

In index.js it uses express to add a route like this:

// Add route to serve compiled SCSS from /assets/{build id}/main.css
const sassResult = sass.renderSync({file: './css/main.scss', outputStyle: 'compressed'})
 server.get('/assets/:id/main.css', (req, res) => {
 res.setHeader('Content-Type', 'text/css')
 res.setHeader('Cache-Control', 'public, max-age=2592000')
 res.setHeader('Expires', new Date(Date.now() + 2592000000).toUTCString())
 res.send(sassResult.css)
})

The header.js component of the web page then has something like this:

import Package from '../package'
let pathToCSS = '/assets/' + Package.version + '/main.css'
let stylesheet = <link rel="stylesheet" type="text/css" href={pathToCSS}/>

Of course you don't need express just do this but it just happens to as the rest of the example uses it.

The actual example is a bit more sophisticated as it also does inlining and live reloading in development mode and only adds it as a link in production, but you can see how that's done (with webpack config in next.config.js) in the example.

@YarivGilad
Copy link
Author

YarivGilad commented Mar 22, 2017

I am using a local scoped styled-components
I'm following the with-styled-components example
It results in a <style> tag in the HTML.
I need it to output an external CSS file while still keep the styled-components local scope solution...

@iaincollins
Copy link
Contributor

iaincollins commented Mar 22, 2017

You could adapt that same approach and use next/head to inject the link route to the stylesheet in your page (and have CSS files that correspond to your pages).

e.g. "pages/about" and "css/about.scss"

And inject a link like <link rel="stylesheet" type="text/css" href="/css/{version}/{page}"/> in the header in your page. Your route handler would just need to check the path in your css dir exists.

If you wanted be clever about it you could have this done in a layout file which takes a props that has the CSS file(s) you want to load for that page.

@szimek
Copy link

szimek commented Mar 22, 2017

I've got a similar issue. I'm trying to port our relatively simple React app to next.js 2.0 and it's going really well so far, but I got stuck on CSS. Currently we bundle all CSS (Sass actually) together and use extract-text-webpack-plugin to put all CSS in a style tag in development and a link tag (with CDN prefix and a revision in href for caching) in production. In the future we might switch to a smarter solution, but for now I'd simply like to copy the current one.

Is there a working example how to do something like this?

@iaincollins
Copy link
Contributor

Yes, the nextjs-starter project does that.

@szimek
Copy link

szimek commented Mar 22, 2017

@iaincollins Thanks for the tip! I'll check it out.

@szimek
Copy link

szimek commented Mar 26, 2017

@iaincollins In nextjs-starter you're using version from package.json file for versioning assets. Do you know if there's any way to use hashes generated by webpack, so that I don't have to manually bump version in package.json every time I change an asset?

@iaincollins
Copy link
Contributor

iaincollins commented Mar 27, 2017

@szimek No but that's a great question and a better way of doing it.

If you create a BUILD_ID file (in .next/BUILD_ID) then you could read from and use that, but I'm not sure if/how the current BUILD_ID is exposed if you don't explicitly set one.

It would be great if anyone on the nextjs team can suggest how to access that hash (either at run time or by reading from a path). I think exposing those hashes was discussed fairly recently in an open issue but not sure what the resolution to it was. If I go digging and find out anything will update here (and the demo).

UPDATE: I guess exposing a var with a SHA sum of the compiled CSS could work just as well; may consider doing that if it's easier. Will explore hooking into the existing build process first though.

@szimek
Copy link

szimek commented Jun 12, 2017

@timneutkens Is there any official way to do load external CSS that works properly with browser caching (i.e. will output <style> tag that loads CSS file with webpack's revision hash in its filename), e.g. if someone already has all CSS in separate CSS/SASS/LESS files and doesn't want to port it all to CSS in JS just yet?

@radeno
Copy link
Contributor

radeno commented Jul 11, 2017

There is another way than express route handle. More in #2534

@timneutkens
Copy link
Member

@Ridermansb css imports is going to be supported in next v5

@lock lock bot locked as resolved and limited conversation to collaborators Jan 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
8 participants