注意
この記事の内容は作業メモですが、作業したのがlinariaバージョン4の時(現在はバージョン6が最新)のため、若干イントールするものやセットアップ方法が異なります。最新の情報はlinariaのドキュメントを参照してください。
これまでNext.jsではない単純なReactプロジェクトでstyled-componentsを使ってCSSをあてていたが、styled-componentsのパフォーマンスが気になるのでzero-runtimeのライブラリを導入したい
zero-runtimeのライブラリは有名なのがいくつかって、その中でvanilla-extractとlinariaを以前調べたことがあった
2つには書き方に大きな違いがあって、
vanilla-extractの場合はcssプロパティをパスカルケースで記述し、
export const container = style({ textAlign: 'center' })
linairiaの場合はcssプロパティをstyled-componentsやCSSと同じケバブケースで記述する
export const container = style.div` text-align: 'center' `
悩んだ結果、移行前となるべく書き方が変わらないようstyled-componentの記法により近いlinariaにすることにした
準備
環境は以下
- linaria: v4
- webpack: v5
- typescript
インストール
$ npm i -D @linaria/babel-preset @linaria/core @linaria/react @linaria/webpack5-loader mini-css-extract-plugin
.babelrc
に以下を記述する
{ "presets": { ... "@linaria" } }
ビルドツールにはwebpackを使っており、webpack.config.jsにloaderを記載する
typescriptを導入している場合は、{ loader: 'babel-loader' }
と{ loader: 'ts-loader' }
の間に@linaria/webpack5-loader
の記述する
module.exports = { ... module: { rules: [ ..., { test: /\.(js|ts|tsx)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader' }, { loader: '@linaria/webpack5-loader', options: { sourceMap: !prod, }, }, { loader: 'ts-loader' }, ], }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, }, { loader: 'css-loader', options: { sourceMap: !prod, }, }, ], }, ], }, plugins: [ ... new MiniCssExtractPlugin({ filename: 'styles-[contenthash].css', }), ], }
これでlinariaでスタイリングできるようになった
マイグレーション
styled-componentsで書かれた既存のスタイルはあるので、これをうまく置換してlinariaのフォーマットに変換する
styled-componentsでは以下のように書かれていて
export const Container = styled('div', props)` color: red; `
linariaでは以下のように記述するのだが、見た通り基本的にはほとんど正規表現を使った置換でいける
export const Container = styled.div` color: red; `
ただ、動的な部分は工夫が必要で、例えば、styled-componentsでは以下のようにpropsとして渡されたisError
でスタイルを動的に切り替えているが、これはlinariaではできない
export const Container = styled('div', props)` color: ${props => props.isError ? "red" : "blue"}; `
そこで、classにisError
がついていたら、つまり、.isError
がついていたらスタイルを切り替えるようにする
これはcss-modulesの考え方と同じ
先ほどのスタイルは以下のように記述し、
export const Container = styled.div` color: blue; &.isError { color: red; } `
jsx側では以下のようにする(classNameの生成にはclsxを使用している)
<Container className={clsx(isError && "isError")}>text</Container>
手作業にはなってしまうが、これで動的な部分もマイグレーションすることができた