Создание библиотеки компонентов React с помощью Vite и Typescript

Чаще всего для создания React-приложения мы используем наш любимый инструмент: create react app, next, gatsby…
Но это совсем другая история, когда дело доходит до создания библиотеки компонентов. Выбор не так прост. В этой статье мы расскажем, как создать библиотеку с помощью Vite и Typescript.

Почему Vite?

Vite — это современный фронтенд-инструментарий с отличной производительностью. Более подробную информацию вы можете получить здесь. Из коробки он поддерживает typescript и библиотечные связки. Поэтому это идеальный выбор для создания библиотеки React.

Как структурировать и организовать наш проект?

Давайте начнем создавать монорепо. Для управления зависимостями мы используем рабочие пространства yarn.
Чтобы настроить наше монорепо, нам нужно создать файл package.json в корне хранилища.

{
  "name": "lib-example",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*",
      "sites/*"
    ]
  },  
}
Вход в полноэкранный режим Выход из полноэкранного режима

В репозитории есть две папки:

  • packages, содержащая пакет библиотеки компонента
  • sites, содержащая сайт для тестирования библиотеки.

Вот структура дерева.

react-library-vite-example
|- packages
|  |- my-lib
|- sites
|  |- my-site
|- package.json
|- yarn.lock
Вход в полноэкранный режим Выход из полноэкранного режима

Пакет библиотеки

Внутри папки packages создадим новый проект Vite:

yarn create vite my-lib --template react-ts
Войти в полноэкранный режим Выйти из полноэкранного режима

По умолчанию создается веб-приложение React, настроенное на typescript. Теперь нам нужно настроить его на использование библиотечного режима из Vite.

Во-первых, мы должны установить плагин vite, который поможет нам генерировать определения типов для наших компонентов.

yarn add --dev vite-plugin-dts
Войдите в полноэкранный режим Выход из полноэкранного режима

Чтобы подключить библиотеку, нам нужно обновить файл vite.config.js.

import react from '@vitejs/plugin-react';
import path from 'node:path';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';

export default defineConfig({
    plugins: [
        react(),
        dts({
            insertTypesEntry: true,
        }),
    ],
    build: {
        lib: {
            entry: path.resolve(__dirname, 'src/lib/index.ts'),
            name: 'MyLib',
            formats: ['es', 'umd'],
            fileName: (format) => `my-lib.${format}.js`,
        },
        rollupOptions: {
            external: ['react', 'react-dom', 'styled-components'],
            output: {
                globals: {
                    react: 'React',
                    'react-dom': 'ReactDOM',
                    'styled-components': 'styled',
                },
            },
        },
    },
});
Войти в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, что также важно экстернализировать все зависимости, которые вы не хотите собирать в библиотеку: react, react-dom и styled-components.
Наша конфигурация сворачивания генерирует два формата пакета: es и umd.

В качестве примера мы добавляем в нашу библиотеку следующий компонент кнопки (MyButton.tsx).

import styled from 'styled-components';

const MyButton = styled.button`
    border: none;
    border-radius: 0.5rem;
    background-color: #186faf;
    color: hsl(0deg, 0%, 98%);
    padding: 0.75rem;
    cursor: pointer;
    &:hover {
        background-color: #0a558c;
    }
    &:focus {
        outline: none;
        box-shadow: 0 0 0 2px #62b0e8;
        background-color: #0a558c;
    }
`;

export default MyButton;
Войти в полноэкранный режим Выход из полноэкранного режима

Все публичные компоненты React экспортируются в файл src/lib/index.ts.

export { default as MyButton } from './MyButton';
Войти в полноэкранный режим Выход из полноэкранного режима

Вот обновленный package.json для нашей библиотеки:

{
    "name": "my-lib",
    "version": "0.0.0",
    "scripts": {
        "dev": "vite",
        "build": "tsc && vite build",
        "preview": "vite preview"       
    },
    "dependencies": {
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "styled-components": "^5.3.3"
    },
    "devDependencies": {
        "@babel/core": "^7.16.12",
        "@types/node": "^17.0.12",
        "@types/react": "^17.0.38",
        "@types/react-dom": "^17.0.11",
        "@types/styled-components": "^5.1.21",
        "@vitejs/plugin-react": "^1.1.4",
        "acorn-jsx": "^5.3.2",
        "babel-loader": "^8.2.3",
        "typescript": "^4.5.5",
        "vite": "^2.7.13",
        "vite-plugin-dts": "^0.9.9"
    },
    "license": "UNLICENSED",
    "peerDependencies": {
        "react": "^16.8.0 || 17.x",
        "react-dom": "^16.8.0 || 17.x",
        "styled-components": "^5.0.0"
    },
    "files": [
        "dist"
    ],
    "main": "./dist/my-lib.umd.js",
    "module": "./dist/my-lib.es.js",
    "types": "./dist/index.d.ts",
    "exports": {
        ".": {
            "import": "./dist/my-lib.es.js",
            "require": "./dist/my-lib.umd.js"
        }
    }
}

Вход в полноэкранный режим Выйти из полноэкранного режима

Запустите yarn build для компиляции библиотеки.

Поскольку мы собираем все зависимости в библиотеку (кроме внешних), нам нужно очистить package.json опубликованного пакета npm. Мы сделаем это, добавив скрипт prepack.

"prepack": "json -f package.json -I -e "delete this.devDependencies; delete this.dependencies"",
Вход в полноэкранный режим Выход из полноэкранного режима

Я использую CLI для работы с JSON (yarn add -D json).

Сайт для тестирования библиотеки компонентов

Начнем с создания нового проекта Vite в папке sites.

yarn create vite my-site --template react-ts
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Нам нужно добавить следующую зависимость в наш файл package.json, чтобы протестировать нашу библиотеку компонентов:

"dependencies": {
   "my-lib": "*",
   ...
},
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь мы можем ссылаться и использовать наш компонент кнопки.

import { MyButton } from 'my-lib';

function App() {    
    return (
        <div className="App">
            ...
                    <MyButton onClick={...}>Click here!</MyButton>
            ...                
        </div>
    );
}

export default App;
Войти в полноэкранный режим Выйти из полноэкранного режима

Запустите yarn install и yarn run dev, чтобы запустить сервер разработки.

Настройте storybook

Мы также хотим создать документацию для наших компонентов пользовательского интерфейса. Storybook — это фантастический проект, который поможет нам создать игровую площадку для наших компонентов React.

Выполните следующую команду для настройки Storybook:

cd /packages/my-lib && npx sb init --builder storybook-builder-vite
Войти в полноэкранный режим Выйти из полноэкранного режима

На момент написания статьи аддон взаимодействия не работает хорошо с Vite. Вот настроенная конфигурация (.storybook/main.js):

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: "@storybook/react",
  core: {
    builder: "storybook-builder-vite",
  },
};
Вход в полноэкранный режим Выйти из полноэкранного режима

Наконец, мы создаем файл story для нашего компонента кнопки.

import { ComponentMeta, ComponentStoryObj } from '@storybook/react';
import MyButton from './MyButton';

const meta: ComponentMeta<typeof MyButton> = {
    title: 'Design System/MyButton',
    component: MyButton,
};
export default meta;

export const Primary: ComponentStoryObj<typeof MyButton> = {
    args: {
        disabled: false,
        children: 'Hello',
    },
};
Войти в полноэкранный режим Выход из полноэкранного режима

Запустите yarn run storybook, чтобы запустить Storybook.

Если вы хотите узнать больше о Storybook, ознакомьтесь с официальной документацией.

Что дальше?

Мы только что создали отличный проект запуска Vite. Но мы можем пойти дальше и настроить дополнительные инструменты, такие как eslint, prettier, jest…

Вы можете найти исходный код на Github.
Это было полезно для меня в моих проектах. Надеюсь, это поможет и вам.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *