Найти в Дзене

Настройка монорепозитория с помощью pnpm и TypeScript

Приходилось ли вам работать над проектом, в котором каждое приложение, входящее в его состав, находилось в разных репозиториях? Это может расстраивать и отнимать много времени. Или, возможно, у вас есть код, который вы хотели бы использовать в разных проектах, но не хотите возиться с установкой и управлением пакетом NPM. На помощь приходит монорепозиторий. Он позволяет вам поместить все ваши приложения для проекта в один репозиторий, обмениваться кодом между ними и многое другое! И хотя эта концепция не нова, современные инструменты упрощают ее настройку. В этой статье я покажу вам, как можно настроить монорепо для проекта Node с помощью pnpm и TypeScript. Настройка рабочего пространства монорепо с помощью pnpm Pnpm - это альтернатива npm и yarn. Она имеет довольно много заметных улучшений по сравнению с ними, включая более быструю установку пакетов, неплоскую структуру node_modules, оптимизацию дискового пространства и, что для нас важно, встроенную поддержку монорепозитория. Если в в
Оглавление

Приходилось ли вам работать над проектом, в котором каждое приложение, входящее в его состав, находилось в разных репозиториях? Это может расстраивать и отнимать много времени. Или, возможно, у вас есть код, который вы хотели бы использовать в разных проектах, но не хотите возиться с установкой и управлением пакетом NPM.

На помощь приходит монорепозиторий. Он позволяет вам поместить все ваши приложения для проекта в один репозиторий, обмениваться кодом между ними и многое другое! И хотя эта концепция не нова, современные инструменты упрощают ее настройку. В этой статье я покажу вам, как можно настроить монорепо для проекта Node с помощью pnpm и TypeScript.

Настройка рабочего пространства монорепо с помощью pnpm

Pnpm - это альтернатива npm и yarn. Она имеет довольно много заметных улучшений по сравнению с ними, включая более быструю установку пакетов, неплоскую структуру node_modules, оптимизацию дискового пространства и, что для нас важно, встроенную поддержку монорепозитория. Если в вашей системе еще не установлен pnpm, перейдите по ссылке https://pnpm.io/installation для получения подробной информации о том, как установить его для вашей системы.

Установив pnpm, мы можем создать новый проект Node следующим образом:

$ pnpm init

Теперь у нашего проекта должен быть файл package.json, который мы можем использовать. Давайте добавим пару папок и файлов, которые нам понадобятся. Во-первых, мы должны установить зависимости нашего корневого пакета:

$ pnpm add -D typescript @types/node

Далее создайте новый файл pnpm-workspace.yaml. Здесь мы настроим все различные проекты, которые у нас будут. Откройте этот файл и добавьте в него следующие строки:

# pnpm-workspace.yaml
packages:
  - 'admin'
  - 'client'
  - 'shared'

Здесь мы указываем pnpm, что у нас будет три проекта, которые ему необходимо отслеживать. В нашем примере мы создадим два приложения React с Vite для администратора и клиента, а затем создадим общий проект, код которого они оба будут использовать.

Однако прежде чем мы их создадим, нам нужно настроить наш базовый файл tsconfig.json. Давайте создадим два новых файла. Первый из них - tsconfig.base.json. Добавьте в него следующие параметры конфигурации:

// tsconfig.base.json
{
"compilerOptions": {
    "strict": true,
    "strictNullChecks": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "noUnusedLocals": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "jsx": "react-jsx",
    "moduleResolution": "node"
  }
}

Конечно, вы можете изменять настройки TypeScript по своему усмотрению. У нас все настроено именно так, и это хорошо работает для наших проектов.

Теперь мы можем создать наш настоящий tsconfig.json. Чтобы он наследовался от нашей базы, нам нужно добавить в него следующую строку:

// tsconfig.json
{
  "extends": "./tsconfig.base.json"
}

Теперь мы готовы начать добавлять наши проекты!

Создание общего проекта

Следующим шагом будет создание нашего общего проекта. Для начала создайте новую папку под названием shared и добавьте в нее новый файл package.json. Этот проект будет содержать простой тип и функцию, которыми мы сможем обмениваться между нашими базами кода. Добавьте следующие строки в ваш новый файл package.json:

// shared/package.json
{
    "name": "@monorepo/shared",
    "private": true
}

Обратите внимание, что если вы хотите иметь какие-либо общие компоненты React, вам нужно будет добавить React в качестве зависимости к этому проекту. Вы можете посмотреть это в демонстрационном репозитории, ссылку на который мы оставим в конце статьи.

Давайте добавим сюда новый файл index.ts. В этом файле у нас будет интерфейс, представляющий пользователя, и функция, показывающая оповещение для приветствия пользователя:

// shared/index.ts
export interface User {
    firstName: string;
    lastName: string;
    email: string;
    isAdmin: boolean;
}

export function greetUser(user: User) {
    alert(`Hello, ${user.firstName} ${user.lastName}! You are ${user.isAdmin ? 'an admin.' : 'not an admin.'}`);
}

Это все, что нам нужно, чтобы начать обмен кодом между клиентскими приложениями.

Настройка фронтенд-приложений React

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

Мы можем создать их в терминале с помощью следующих команд:

$ pnpm create vite admin --template react-ts
$ pnpm create vite client --template react-ts

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

// admin/package.json
{
    "name": "@monorepo/admin",
    // ...
    "dependencies": {
        "@demo/shared": "workspace:*",
        // ...
  },
}

// client/package.json
{
    "name": "@monorepo/client",
    // ...
    "dependencies": {
        "@demo/shared": "workspace:*",
        // ...
  },
}

Запустите pnpm install для установки необходимых зависимостей для каждого проекта, и теперь мы можем обмениваться кодом между нашими приложениями React.

Совместное использование кода между приложениями

Давайте начнем с приложения администратора. В вашем файле App.tsx создадим нового пользователя-администратора и добавим кнопку для приветствия нового пользователя:

// admin/src/App.tsx
import { User, greetUser } from "@monorepo/shared"

function App() {
    const user: User = {
        firstName: "Admin",
        lastName: "User",
        email: "adminuser@test.com"
        isAdmin: true,
    };

    const onGreetClicked = () => {
        greetUser(user);
    }

    return (
        <div className="App">
            <h1>Admin App</h1>
            <button onClick={onGreetClicked}>Greet Admin!</button>
        </div>
    );
}

export default App;

Теперь, если мы запустим приложение администратора и перейдем на эту страницу в браузере, мы увидим наш заголовок и кнопку. При нажатии на кнопку должно появиться оповещение с текстом "Hello, Admin User! You are an admin".

В клиентском приложении откройте файл App.tsx и обновите его следующим кодом:

// client/src/App.tsx
import { User, greetUser } from "@monorepo/shared"

function App() {
    const user: User = {
        firstName: "Client",
        lastName: "User",
        email: "clientuser@test.com"
        isAdmin: false,
    };

    const onGreetClicked = () => {
        greetUser(user);
    }

    return (
        <div className="App">
            <h1>Client App</h1>
            <button onClick={onGreetClicked}>Greet Client!</button>
        </div>
    );
}

export default App;

Снова запустите приложение и нажмите на кнопку. Вы должны увидеть предупреждение с текстом "Hello, Client User! You are not an admin".

Таким образом, у нас теперь есть полностью функционирующее монорепо и мы можем обмениваться кодом между нашими приложениями!

Заключение

В этой статье мы рассмотрели, как настроить монорепо с помощью pnpm, а также узнали, как можно обмениваться кодом между нашими приложениями. Несмотря на свою простоту, мы надеемся, что этот пример покажет вам потенциал использования монорепо для ваших TypeScript-проектов.

Более подробную информацию о монорепо и технологии, использованной для этого примера, можно найти по ссылкам ниже.