🌲

Chakra UI のバンドルサイズを削る方法 2023/01版

2023/01/28に公開

Chakra UI のバンドルサイズが大きくて大変なので、現時点(v2.4.9)での削減方法を紹介します。

必要なコンポーネントのみを宣言する

@chakra-ui/react がエクスポートする ChakraProvider は、全てのコンポーネントのテーマを含んでしまっています。逆に、コンポーネントのテーマを全く含まない ChakraBaseProvider が用意されているため、これを使います。

まず、extendBaseTheme を用いて必要なコンポーネントのみを含めたテーマを作ります。
それを ChakraBaseProvider に渡すことで、テーマを適用します。

import { FC } from "react";
import { ChakraBaseProvider, extendBaseTheme, Box, Button, Checkbox, Tag } from "@chakra-ui/react";
import { Button as ButtonTheme, Checkbox as CheckboxTheme } from "@chakra-ui/theme/components";

const theme = extendBaseTheme({
  components: {
    Button: ButtonTheme,
    Checkbox: CheckboxTheme,
  },
});

const App: FC = () => {
  return (
    <ChakraBaseProvider theme={theme}>
      <Box>
        <Button>This is styled!</Button>
	<Checkbox>This is also styled!</Checkbox>
	<Tag>This is NOT styled</Tag>
      </Box>
    </ChakraBaseProvider>
  );
};

extendBaseTheme に渡していないコンポーネントはスタイルがつかないので注意してください。

Framer Motion に依存するコンポーネントを使わない

アニメーションライブラリである Framer Motion は、めちゃめちゃサイズがでかいので出来るだけバンドルしたくありません。v2.4.9 時点では、以下のコンポーネントが Framer Motion に依存しているため、これらを1つでも使うと一気にバンドルサイズが膨らみます。

  • Transition
  • Tooltip
  • Popover
  • Modal
  • Menu
  • Toast

Toast だけが特殊で、グローバルステートを持つため、ChakraProviderChakraBaseProvider が依存してしまっています。

https://github.com/chakra-ui/chakra-ui/blob/%40chakra-ui/react%402.4.9/packages/components/react/src/chakra-provider.tsx#L20-L41

これは @chakra-ui/react で実装されているため、よりプリミティブな @chakra-ui/provider からエクスポートされる ChakraProvider を使うことで回避できます。

 import { FC } from "react";
-import { ChakraBaseProvider, extendBaseTheme, Box, Button, Checkbox, Tag } from "@chakra-ui/react";
+import { extendBaseTheme, Box, Button, Checkbox, Tag } from "@chakra-ui/react";
+import { ChakraProvider as ChakraBaseProvider } from "@chakra-ui/provider";
 import { Button as ButtonTheme, Checkbox as CheckboxTheme } from "@chakra-ui/theme/components";

 const theme = extendBaseTheme({
   components: {
     Button: ButtonTheme,
     Checkbox: CheckboxTheme,
   },
 });

 const App: FC = () => {
   return (
     <ChakraBaseProvider theme={theme}>
       <Box>
         <Button>This is styled!</Button>
         <Checkbox>This is also styled!</Checkbox>
         <Tag>This is NOT styled</Tag>
       </Box>
     </ChakraBaseProvider>
   );
 };

Rollup や Vite を使わない

Chakra UI の内部コードでは再エクスポートを多用しています。

そして Rollup や Vite では再エクスポートにおける副作用判定にバグがあるらしく、うまく Tree Shaking が効かない場合があります。
https://github.com/vitejs/vite/issues/7635

これが治るまでは webpack を使うのが無難でしょう。他のバンドラは試してないのでわかりません。

おわりに

前述のバグのように、様々な外部要因で結果が変わりうるので、webpack-bundle-analyzer などで逐一チェックしながら最適化してください。
また、v3 で Breaking Change を伴う大きな改善を予定しているらしいので、ひとまずはこれで凌ぎましょう。

Discussion