DEV Community

Cover image for storybook with preact + TS + goober
sadnessOjisan
sadnessOjisan

Posted on

storybook with preact + TS + goober

fail setup storybook

Create a component with preact, TS and goober.

import { h } from "preact"
import { styled } from "goober"

const _Button = styled("button")`
  background-color: red;
`

export const Button = () => {
  return <_Button>ok</_Button>
}
Enter fullscreen mode Exit fullscreen mode

Next, create the storybook's story.

npx sb init
Enter fullscreen mode Exit fullscreen mode
import { h } from "preact"
import { Button } from "./button"

export default {
  title: "custom/Button",
  component: Button,
  argTypes: {
    backgroundColor: { control: "color" },
    onClick: { action: "onClick" },
  },
}

const Template = (args: any) => <Button {...args} />

export const Primary = Template.bind({})
Enter fullscreen mode Exit fullscreen mode

And start this.

npm run storybook
Enter fullscreen mode Exit fullscreen mode

Let's look at this story. You will see this fail view.

h is not defined
ReferenceError: h is not defined
    at Object.Template (http://192.168.0.3:6006/main.4bde6a78d76d85c8a393.bundle.js:353:3)
    at finalStoryFn (http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:16622:32)
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:13062:21
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:14861:14
    at wrapper (http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:12801:12)
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:13580:14
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:13594:26
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:13062:21
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:14854:12
    at http://192.168.0.3:6006/vendors~main.4bde6a78d76d85c8a393.bundle.js:14861:14
Enter fullscreen mode Exit fullscreen mode

error

On the other hand, generated story files by npx sb init are successful.

sampleStory

Why is this example success, is My story fail to view.

Let's look at Success Component

Firstly, preact is supported by the storybook official.

FYI: https://www.npmjs.com/package/@storybook/preact

That's why we can generate example preact story files by npx sb init.Let's look at this component.

/** @jsx h */
import { h } from "preact"
import PropTypes from "prop-types"
import "./button.css"

/**
 * Primary UI component for user interaction
 */
export const Button = ({ primary, backgroundColor, size, label, ...props }) => {
  const mode = primary
    ? "storybook-button--primary"
    : "storybook-button--secondary"
  return (
    <button
      type="button"
      className={["storybook-button", `storybook-button--${size}`, mode].join(
        " "
      )}
      style={backgroundColor && { backgroundColor }}
      {...props}
    >
      {label}
    </button>
  )
}

Button.propTypes = {
  /**
   * Is this the principal call to action on the page?
   */
  primary: PropTypes.bool,
  /**
   * What background color to use
   */
  backgroundColor: PropTypes.string,
  /**
   * How large should the button be?
   */
  size: PropTypes.oneOf(["small", "medium", "large"]),
  /**
   * Button contents
   */
  label: PropTypes.string.isRequired,
  /**
   * Optional click handler
   */
  onClick: PropTypes.func,
}

Button.defaultProps = {
  backgroundColor: null,
  primary: false,
  size: "medium",
  onClick: undefined,
}
Enter fullscreen mode Exit fullscreen mode

There are some different points between my components.

  • not TS, but JS.
  • jsx pragma in first line.
  • not use CSS in JSS, but use plain CSS

Those points are just the reason why my story doesn't work.

need config jsx factory

what is /** @jsx h */

This is called a jsx pragma.it tells jsx factory to the compiler. For example, react's jsx factory is createElement, preact's jsx factory is h, but the compiler doesn't know it.

story book builds a source by babel

If you use TypeScript Compiler to build an application, the storybook builds a story by babel. That's why you must config about jsx factory to the babel config file.

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  babel: async options => ({
    ...options,
    presets: [["@babel/typescript", { jsxPragma: "h" }]],
  }),
}
Enter fullscreen mode Exit fullscreen mode

Otherwise, you should write jsx pragma in your story file.

goober needs init

Goober is a CSS in JS library.This needs a setup to run the application for the first time.

import { setup } from "goober"
import { h, render } from "preact"
import { Button } from "./button"

setup(h)

const App = () => {
  return (
    <div>
      <Button></Button>
    </div>
  )
}

render(<App></App>, document.body)
Enter fullscreen mode Exit fullscreen mode

But story book's file doesn't read this entry point. That's why each story file needs setup(h).

import { setup } from "goober"
import { h } from "preact"
import { Button } from "./button"

setup(h)

export default {
  title: "custom/Button",
  component: Button,
  argTypes: {
    backgroundColor: { control: "color" },
    onClick: { action: "onClick" },
  },
}

const Template = (args: any) => <Button {...args} />

export const Primary = Template.bind({})
Enter fullscreen mode Exit fullscreen mode

it works!!

Start storybook after config jsx factory to babel config file and setup goober each story file.

npm run storybook
Enter fullscreen mode Exit fullscreen mode

Success!!

success

Source code is here.

https://github.com/ojisan-toybox/preact-storybook

Top comments (0)