Extracted static stylesheet file into header
See original GitHub issueMany issues are trying to solve extracting CSS file as separate link for production env. Eg: #1479 #1396 #1615
There is another solution what is works, and is quite elegant. (maybe isn’t 😄 )
This solution works for Next v3 beta and Docker. My source directory is src
and build directory is one level up .next
. We are using separated style files in /style directory with index.css where are all css files imported.
Required Webpack plugins and loaders
- extract-text-webpack-plugin
- css-loader
- raw-loader
- postcss-loader
next.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
distDir: '../.next',
webpack: (config, { dev }) => {
config.module.rules.push({
test: /\.css$/,
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]'
}
});
if (!dev) {
config.module.rules.push({
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: false,
url: true,
sourceMap: false,
minimize: true,
localIdentName: false
? '[name]-[local]-[hash:base64:5]'
: '[hash:base64:5]'
}
},
{ loader: 'postcss-loader' }
]
})
});
config.plugins.push(new ExtractTextPlugin('app.css'));
} else {
config.module.rules.push({
test: /\.css$/,
use: [{ loader: 'raw-loader' }, { loader: 'postcss-loader' }]
});
}
return config;
}
};
File is emitted in build directory and then is processed with css-loader and postcss-loader. After processing is extracted next to app.js file. Do not use babel-loader for global as in this example: https://github.com/zeit/next.js/tree/v3-beta/examples/with-global-stylesheet It is not neccessary and doesn’t work well with postcss-calc.
Docker
In dockerfile, copy generated app.css to static directory
RUN mkdir src/static/styles && cp .next/app.css src/static/styles/app.css
Header link for production, style for development
pages/_document.js
we also used React-Helmet, so this example is
import Document, { Head, Main, NextScript } from 'next/document';
import stylesheet from '../styles/index.css';
export default class extends Document {
render() {
return (
<html>
<Head>
{process.env.NODE_ENV == 'production'
? <link
rel="stylesheet"
type="text/css"
href={`/static/styles/app.css?${this.props.__NEXT_DATA__
.buildStats['app.js'].hash}`}
/>
: <style
global
dangerouslySetInnerHTML={{
__html: stylesheet
}}
/>}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
Link to app.css is appended with querystring with same hash as is used in app.js path for disabling cache after redeploy.
What we can do better?
Next Server define route for production app.js
file (https://github.com/zeit/next.js/blob/v3-beta/server/index.js#L151). This example should be more elegant if we can define route for app.css
Then this could be automated or at least we should have better links for app.css file. Ex:
<link
rel="stylesheet"
type="text/css"
href={`/_next/${this.props.__NEXT_DATA__.buildStats['app.js'].hash}/app.css`}
/>
Issue Analytics
- State:
- Created 6 years ago
- Reactions:23
- Comments:13 (6 by maintainers)
Top GitHub Comments
I’m also in need of this setup and this is the best solution so far. Below is my
next.config.js
in which:sourceMap: 'inline'
at postcss-loaderIt is available only on custom document (in pages/_document.js), please see the README