コンニチハ!ハルミです。
React のライブラリである Framer Motion は、リッチなアニメーションを簡単に実装できる強力なライブラリです。
しかし、Framer Motion は比較的バンドルサイズが大きく、読み込みパフォーマンスに影響を与えることがあります。
これは、Framer Motion がアニメーションを実現するために、多くのコードをバンドルに含める必要があるためです。
この記事では、Framer Motion のバンドルサイズを軽量化してパフォーマンスを上げる方法を紹介します。
はじめに
当記事は React を使用します。
Reactの知識があることを前提としておりますのでご了承ください。
Framer Motion とは
念のためにFramer Motion が何なのか簡単に説明します。
Framer Motion は、Reactアプリケーション向けのオープンソースのアニメーションライブラリで、シンプルかつ強力な宣言的な記法を提供します。
このライブラリは、UIに動きを加えるためのツールとして広く利用されており、特にモダンなWeb開発において重要な役割を果たしています。
近いものに有名な GSAP (GreenSock Animation Platform) がありますが、
Framer Motion は GSAP よりもシンプルで直感的に使えるという特徴があります。
バンドルサイズを軽量化する方法
早速本題に入っていきましょう。
通常のFramer Motionでは、以下のように要素にmotionを先頭につけてアニメーションを設定します。
import { motion } from "framer-motion";
export const Sample = () => {
return <motion.div
whileHover={{ scale: 1.2, rotate: 90 }}
whileTap={{
scale: 0.8,
rotate: -90,
borderRadius: "100%"
}}
>Hello World</motion.div>;
};
ホバーで拡大、クリックで縮小できるよ!
しかし、このようにすると使用しない関数までバンドルされてしまいます。
これを防ぐために m と LazyMotion を使用します。
m は motion と全く同じように使用しますが、
このmコンポーネントにはアニメーション、レイアウト アニメーション、ドラッグ ジェスチャなどの機能がプリロードされていません。
このmに対して、LazyMotionを使用して、手動で機能をロードします。
現在、ロードできる機能パッケージは2つあります。
- domAnimation
- domMax
domAnimationはアニメーション、バリアント、終了アニメーション、タップ/ホバー/フォーカス ジェスチャのサポートを提供します。
domMaxは上記のすべてに加え、パン/ドラッグ ジェスチャとレイアウト アニメーションもサポートします。
つまり、通常のDOMアニメーションを使用する場合はdomAnimationのみをロードすることで バンドルサイズを軽量化することができます。
import { m, LazyMotion, domAnimation } from "framer-motion";
export const Sample = () => {
return (
<LazyMotion features={domAnimation}>
<m.div
whileHover={{ scale: 1.2, rotate: 90 }}
whileTap={{
scale: 0.8,
rotate: -90,
borderRadius: "100%"
}}
>
Hello World
</m.div>
</LazyMotion>
);
};
これでバンドルサイズを軽量化することができます。
Next.jsで使う場合はLazyMotionをlayout.tsxで使用しておくと
ルート配下のページではmを使うだけでよくなるのでシンプルになります。
import { LazyMotion, domAnimation } from "framer-motion";
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ja">
<body>
<LazyMotion features={domAnimation}>
{children}
</LazyMotion>
</body>
</html>
);
}
当サイトにもFramer Motionを使用していますが、
mを使用したところPageSpeed Insightsでのスコアが3点ほど上がりました。
motionのバンドルサイズはかなり大きめなので、基本的にはmを使用した方がよいでしょう。
厳格モード
LazyMotionにstrictを指定すると、motionを使用した場合にエラーを吐きます。
これによって、誤ってmotionをインポートしてしまうことを防ぐことができます。
function App() {
// これはエラーになります🔥
return (
<LazyMotion strict>
<motion.div />
</LazyMotion>
)
}
遅延読み込みについて
公式ドキュメントによると、Webpack や Rollup などのバンドラーを使用している場合は、初期レンダリングを実行した後にのみ機能を取得する動的インポート関数を渡すことができるようです。
こちらの機能は当方の環境では試せていないので、試したい方は公式ドキュメントを参照してください。
動的インポートは、こちらの機能を使わなくても各フレームワークの機能を使えば実現できるので、 そちらを使った方がよいかもしれません。
おわりに
Framer Motion のバンドルサイズを軽量化してパフォーマンスを上げる方法を紹介しました。
これで、Framer Motion を使ってよりスムーズなアニメーションを実現できるようになるでしょう。
これに限らず、JSライブラリはバンドルサイズが大きいものが多いので、
パフォーマンスチューニングの際には注意しましょう。
それでは、また👋