Comments (7)
Here's one more discovery that might help those who have little CSS in style.css
. That's the case when most of the styles come from styled-components or a similar framework. Turns out you can improve your website's performance by including the contents of .next/static/style.css
directly into document, e.g. like this:
let style = null;
if (process.env.NODE_ENV === "production") {
style = fs.readFileSync(`${process.cwd()}/.next/static/style.css`, "utf8");
}
// inside _document's Head:
{typeof style === "string" ? (
<style dangerouslySetInnerHTML={{ __html: style }} />
) : (
<link rel="stylesheet" href="/_next/static/style.css" />
)}
This helped me change the lighthouse performance score in production from 89 to 96 because First meaningful paint time decreased from 2.06 to 1.10 seconds. This is an advice in the original report that I followed:
When a stylesheet is heavy, it's cheaper to load it as a separate file and cache that request in the browser – this keeps the size of the server-rendered HTMLs small while avoiding extra round trips in consequent page requests. However, when style.css
contains just normalize.css and a couple of simple global selectors, always keeping the entire stylesheet within the document's <head>
and avoiding extra round trips appears to be a better thing. Obviously, caching is no longer a problem, because <style>{style}</style>
is read from .next/static/style.css
when your Next.js server starts.
Don't forget to import styles in a higher order component that works as a page wrapper:
# e.g. in hocs/page.js
import "./path/to/your/root/stylesheet.css"
Can this issue be considered as resolved?
If you want to check your website's performance, simply run
npm install --global lighthouse
lighthouse http://example.com/ --view
if ...style.css`
screws up syntax highlighting in your editor, here's a trick:
let style = null;
if (process.env.NODE_ENV === "production") {
// ${"css"} prevents editors from incorrectly highlighting code after css`
style = readFileSync(`${process.cwd()}/.next/static/style.${"css"}`, "utf8");
}
from next-plugins.
I ended up doing the following in _document.js
- this works for the time being, however we need to make sure the BUILD_ID is the same on a multi-deployment basis!
Note this builds from a
src
directory!
import Document, { Head, Main, NextScript } from 'next/document';
import { readFileSync } from 'fs';
let version = '';
if (process.env.NODE_ENV === 'production') {
version = `?v=${readFileSync(`${process.cwd()}/src/.next/BUILD_ID`)}`;
}
export default class extends Document {
render() {
return (
<html>
<Head>
<link rel="stylesheet" href={`/_next/static/style.css${version}`} />
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
)
}
}
from next-plugins.
It's also possible to use file's hash instead of BUILD_ID
as version:
import { createHash } from "crypto";
import { readFileSync } from "fs";
// ...
let version = "";
if (process.env.NODE_ENV === "production") {
const hash = createHash("sha256");
hash.update(readFileSync(`${process.cwd()}/.next/static/style.css`));
version = `?v=${hash.digest("hex").substr(0, 8)}`;
}
// ...
If the styles don't change between the builds, there's no need to download them and so everyone is better off.
In general, it's more efficient to calculate file cache using streams, but this should be unnecessary in our case. if .next/static/style.css
is big enough to cause a hiccup during server setup, something is probably wrong 😃
crypto.createHash
has been a part of Node's core nearly since the beginning of times, so there is no need to install a new module.
What are the caveats of this trick? If anyone sees them, could you please share?
from next-plugins.
Even though the workarounds in two previous comments solve the issue with style.css
caching, all other static assets like images remain under the over-caching thread.
It'd be truly great to bring some webpack magic here! This would not only allow correct caching by turning paths into something like image.eld7hd4p.png
, but would also make it possible to store images in folders with components. It's a bit of a shame that the images have to go to static
in next.js, which separates them from a place where they really belong.
from next-plugins.
If you're going with the inlining approach, you may need to use:
<style dangerouslySetInnerHTML={{ __html: style }} />
Otherwise, things like quotes get converted to HTML entities.
from next-plugins.
Thank you @bryandowning, you are right! I updated the comment and removed <style>{{ style }}</style>
.
from next-plugins.
Will be possible when vercel/next.js#4119 lands for Next 6
from next-plugins.
Related Issues (20)
- Can not install @zeit/next-css HOT 1
- Yarn 2 - missing webpack@^4.0.0 dependency in @zeit/next-css@npm:1.0.1 HOT 1
- Cannot get CSS variables to work with npm module. HOT 2
- @zeit/next-workers: ValidationError: Invalid options object. HOT 3
- antd style does not take effect HOT 1
- with-less will disable build in css-loader HOT 2
- Absolute import with TypeScript produces errors with non ts files
- devtool option isn't working with useSourceMap HOT 4
- Unable to load fonts from SCSS using NextJS 9.5.5 HOT 1
- Source maps resolved wrongly @zeit/next-source-maps HOT 2
- @zeit/next-sass has to be updated to use node-sass v5 HOT 2
- Loading background image from SCSS doesn't work HOT 1
- Style hot reload not triggered with legacy @zeit/next-css or @zeit/next-less plugins HOT 1
- next-workers not working in Next 10? HOT 3
- Module parse failed using next-less in a typescript next js project
- CSS and SCSS with NextJS (issue while using multiple loaders: next-sass, next-css) HOT 1
- Error: PostCSS plugin tailwindcss requires PostCSS 8. HOT 1
- `localIdentName` default value for `dev` HOT 1
- Webpack plugin InjectManifest nextjs source maps "You must provide the URL of lib/mappings.wasm by calling SourceMapConsumer.initialize({ 'lib/mappings.wasm': ... }) before using SourceMapConsumer"
- less config error HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from next-plugins.