Stylex: 새로운 CSS-in-JS

이번에 새로 Meta에서 발표한 새로운 CSS-in-JS 라이브러리 Stylex를 사용해보았다.

현재 Meta에서 개발한 페이스북이나, 인스타그램과 같은 서비스에서 사용하고 있다고 한다.



사용해 보기

1. 설치 및 세팅

pnpm install @stylexjs/stylex @stylexjs/open-props
pnpm install -D @stylexjs/babel-plugin @stylexjs/eslint-plugin @stylexjs/nextjs-plugin
next.config.js
/** @type {import('next').NextConfig} */
/** @type {import('next').NextConfig} */
const stylexPlugin = require('@stylexjs/nextjs-plugin');
const babelrc = require('./.babelrc.js');
const plugins = babelrc.plugins;
const [_name, options] = plugins.find(
  plugin => Array.isArray(plugin) && plugin[0] === '@stylexjs/babel-plugin',
);
const rootDir = options.unstable_moduleResolution.rootDir ?? __dirname;

module.exports = stylexPlugin({
  rootDir,
  useCSSLayers: true,
})({
  transpilePackages: ['@stylexjs/open-props'],
});
babelrc.js
module.exports = {
  presets: ["next/babel"],
  plugins: [
    [
      "@stylexjs/babel-plugin",
      {
        dev: process.env.NODE_ENV === "development",
        runtimeInjection: false,
        genConditionalClasses: true,
        treeshakeCompensation: true,
        unstable_moduleResolution: {
          type: "commonJS",
          rootDir: __dirname,
        },
      },
    ],
  ],
};

현재 Nextjs에서 세팅을 할때에는 공식문서 나와 있는데로 하면 오류가 있고 github issue를 참고하여 수정을 했다.


2. 스타일링 하기

component/button.tsx
export interface ButtonProps
  extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'ref'> {
  color?: ColorsType;
  size?: SizesType;
  textColor?: string;
}

const styles = stylex.create({
  base: {
    width: '100%',
    border: 'none',
    borderRadius: '0.25rem',
    cursor: 'pointer',
    ':hover': {
      opacity: 0.9,
    },
  },
  backgroundColor: bg => ({
    backgroundColor: bg,
    ':hover': {
      opacity: 0.9,
    },
  }),
  textColor: textColor => ({
    color: textColor || '#ffffff',
  }),
});

const buttonSize = stylex.create({
  sm: {
    fontSize: 14,
    padding: '0.25rem 0.5rem',
  },
  md: {
    fontSize: 16,
    padding: '0.5rem 1rem',
  },
  lg: {
    fontSize: 18,
    padding: '0.75rem 1.5rem',
  },
  xl: {
    fontSize: 20,
    padding: '1rem 2rem',
  },
});

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ children, color = 'primary', size = 'md', textColor, ...restProps }, ref) => {
    return (
      <button
        ref={ref}
        {...stylex.props(
          styles.base,
          styles.backgroundColor(colors[color]),
          styles.textColor(textColor),
          buttonSize[size],
        )}
        {...restProps}
      >
        {children}
      </button>
    );
  },
);

Button.displayName = 'Button';

느낀점

최종적으로는 저는 우선적으로 Client Component를 사용가능하고 가독성이 좋은 라이브러리를 사용을 하고 싶은데 tailwind나 stylex 둘다 가독성면에서는 그저 그랬다. 앞으로 stylex 업데이트를 기다려 봐야 할 것 같다.