Closed11

Next.jsで styled-components から linaria への置き換えを試みる

Zennのフロントエンド(Next.js)ではCSSをあてるのに styled-components を使っている。これをlinariaへ置き換えようと試みる。

動機はパフォーマンスのため。

  • どちらも CSS in JS ライブラリ
  • styled-components は ランタイムでCSSを生成する。
  • linaria は ゼロランタイムを売りにしていて、ビルド時にCSSファイルを生成する。柔軟性で劣るがパフォーマンスは良い。

インストール

$ yarn add @zeit/next-css linaria

現状だと@zeit/next-cssも入れなきゃならなさそう。

next.config.jsの設定を行う。meijinさんの記事の通り。

next.config.js
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;
  },
});

.babelrclinaria/babelを追加。

.babelrc
{
  "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を導入できそう。

https://www.npmjs.com/package/next-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.jsonpathsで設定してるエイリアス。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の導入はもう少し様子見した方が良さそうな気がしてきたので一旦中断する。また時間ができたときに取り組む。

このスクラップは2020/11/29にクローズされました
ログインするとコメントできます