Next.js と Emotion でいろいろハマった件 2
Nextjs で export する時に、Emotion の出力結果を <head>
にインライン展開する方法についてです。
また、PostCSS が効かなかったので、ビルド時に Autoprefixer を実行するように対応してみた内容もまとめました。
Version
- TypeScript 4.0.5
- Next.js 10.0.1
- React 17.0.1
- Emotion 10/11
インライン展開したい
ずっと npm run dev
で作業していて全然気が付かなかったやつ。
Emotion で書いた CSS は何もせずに next build
でビルドしても描画されるのですが、そのままではインライン展開されていません。
インライン展開するには Example に倣って emotion-server
パッケージで extract する必要がありました。
next.js/examples/with-emotion at master · vercel/next.js · GitHub
_document.js
の static async getInitialProps(ctx) { }
をそっくりそのまま使います。
AutoPrefixer を使いたい
Emotion は内部で Stylus を使用しているそうで IE11 用のベンダープレフィックスは付与されません。
Next.js は Autoprefixer がビルトインされているのですが、emotion-server
でインライン展開したものにうまく適用させることができませんでした。
そのため、インライン展開の時 emotion-server
から出力される CSS に直接 Autoprefixer を当てることにしました。
私がやったのは以下のような感じです。
パッケージのインストール
npm install -D autoprefixer postcss
適当なフォルダにスクリプトを用意する
今回は Warning については console.warn
ではなくログファイルに出力しています。
add-prefix.js
const autoprefixer = require('autoprefixer');
const postcss = require('postcss');
const fs = require('fs');
const path = require('path');
export async function addPrefix(css) {
const log = path.join(process.cwd(), 'logs/autoprefixer.log');
fs.writeFileSync(log, '');
return postcss([
autoprefixer({
flexbox: 'no-2009',
grid: "autoplace",
overrideBrowserslist: [
"last 1 version",
"> 1%",
"ie 11"
]
})
]).process(css).then(result => {
result.warnings().forEach(warn => {
// console.warn(warn.toString());
// logging
fs.appendFileSync(log, `${warn.toString()}\n`);
});
return result.css;
});
}
emotion-server
の出力結果に対してスクリプトを適用する
_document.tsx
...
import { addPrefix } from '../適当なフォルダ/add-prefix';
...
export default class AppDocument extends NextDocument<Props> {
static async getInitialProps(ctx) {
const initialProps = await NextDocument.getInitialProps(ctx);
const styles = extractCritical(initialProps.html);
+ const postCss = await addPrefix(styles.css);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
<style
data-emotion-css={styles.ids.join(' ')}
dangerouslySetInnerHTML={{ __html: postCss /* styles.css */ }}>
</style>
</>
)
}
}
...
あとがき
関わっていた案件のターゲットブラウザに IE11 が入っていたのに Grid バンバン使ったのが良くなかった。