Next.jsで styled-components から linaria への置き換えを試みる
動機はパフォーマンスのため。
- どちらも CSS in JS ライブラリ
- styled-components は ランタイムでCSSを生成する。
- linaria は ゼロランタイムを売りにしていて、ビルド時にCSSファイルを生成する。柔軟性で劣るがパフォーマンスは良い。
インストール
$ yarn add @zeit/next-css linaria
現状だと@zeit/next-css
も入れなきゃならなさそう。
next.config.js
の設定を行う。meijinさんの記事の通り。
const withCSS = require("@zeit/next-css");
module.exports = withCSS({
webpack(config, options) {
config.module.rules.push({
test: /\.(js|tsx)$/,
use: [
{
loader: "linaria/loader",
options: {
sourceMap: process.env.NODE_ENV !== "production",
},
},
],
});
return config;
},
});
.babelrc
にlinaria/babel
を追加。
{
"presets": ["next/babel", "linaria/babel"]
}
環境は
next@10.0.1
linaria@2.0.2
この状態で動かしたらエラーが出まくった。
Error: Cannot find module '/Users/path/zenn-app/next/.next/server/pages-manifest.json'
おそらくNext.jsのビルトインのCSSが無効化されてしまっているから。
このパッケージを使えば、Next.jsのビルトインのCSSサポートを維持しつつ、linariaを導入できそう。
next-linaria
を使うなら@zeit/next-css
をアンインストールして、以下のようにする。
const withLinaria = require('next-linaria');
module.exports = withLinaria({
webpack(config, options) {
config.module.rules.push({
test: /\.(js|tsx)$/,
use: [
{
loader: "linaria/loader",
options: {
sourceMap: process.env.NODE_ENV !== "production",
},
},
],
});
return config;
},
});
メンテナンスが不安だけど中身は50行くらいのファイル。参考にして自分で書くこともできそう。@zeit/next-css
もメンテはされていないしな。
試してみる
import { styled } from 'linaria/react';
import { mediaQuery } from '@utils/style-helpers';
const Title = styled.h1`
font-size: 2rem;
`;
const Container = styled.div`
${mediaQuery.sm} {
border: 1px solid red;
}
&:hover {
border-color: blue;
}
${Title} {
margin-bottom: 24px;
}
`;
export function Foo() {
return (
<Container color="#333">
<Title>Hello world</Title>
</Container>
);
}
早速こんなエラーが出た
Error: Can't resolve '@utils/style-helpers' in '/Users/path/Documents/works/develop/zenn/zenn-app/next/src/pages'
It may happen when your code or third party module is invalid or uses identifiers not available in Node environment, eg. window.
Note that line numbers in above stack trace will most likely not match, because Linaria needed to transform your code a bit.
@utils/style-helpers
は、メディアクエリ等の変数を入れてるやつ。パスが解決できていないっぽい。
以下のように書き換えたら問題なく動いた。
import { mediaQuery } from '@utils/style-helpers';
@
はtsconfig.json
のpaths
で設定してるエイリアス。Next.jsはこのpaths
を見てパスを解決してくれる。
Linariaは2020/11/29の時点ではこれに対応しておらず@babel-plugin-module-resolver
を使う必要があるとのこと。
We should document that we do not support TS paths and Jest module mapper and provide a solution on how to work around the issues using @babel-plugin-module-resolver
参考:https://github.com/callstack/linaria/issues/630
@babel-plugin-module-resolver
の導入は簡単。
参考:Import module aliasing in NextJs
Zennへのlinariaの導入はもう少し様子見した方が良さそうな気がしてきたので一旦中断する。また時間ができたときに取り組む。