Эффективно делитесь кодом с Lerna

Привет кодетор! Сегодня я хотел бы изучить с вами, как настроить монорепозиторий с помощью Учить. Мы будем создавать монорепозиторий с внешним пакетом, внутренним пакетом и общим пакетом, который будет использовать общие типы и методы между ними. Я четко изложу проблему, с которой мы сталкиваемся, менее красивое решение и наше оптимизированное решение с использованием Lerna.

Эта проблема

Потому что я люблю Машинопись (и вы тоже должны!), я не могу не определить действительно потрясающие интерфейсы объектов, поэтому я всегда знаю, с чем я работаю.
Скриншот 16.12.2022, 04.38.32.png
Итак, вот мой удивительный пользователь. Я также хочу настроить функцию, которая возвращает мне полное имя пользователя.
Скриншот 16.12.2022, 04.40.32.png
Так в чем проблема? Ну, скажем, я использую этот код в своем бэкенде, чтобы настроить свои API и определить правильную типизацию. Это правильный способ написания API! Но что, если я ТАКЖЕ хочу использовать интерфейс и метод, чтобы убедиться, что я извлекаю правильные типы и для целей отображения во внешнем интерфейсе? что теперь?

Грязное решение

Вытащите свой старый добрый CopyPaste и получите common папка во внешнем и внутреннем интерфейсе с одним и тем же кодом. Звучит красиво, но что, если мой пользователь станет более сложным? Я хочу добавить список увлечений, адрес электронной почты, пароль. Теперь мне нужно не забыть обновить код в двух местах. А что, если у меня теперь есть сервер отчетов, который служит той же цели?
Список можно продолжить.
Решение несостоятельное. Что же нам теперь делать?

Решение для обучения

Мы используем монорепо! По сути, это единый репозиторий для всего вашего кода. Это позволяет разным репозиториям использовать общий код, как если бы это была библиотека npm. Лерна делает все символические ссылки и магию за кулисами. Давайте посмотрим, как это работает!

Настраивать

Откройте пустую папку в вашем любимом редакторе кода. Затем запустите
npx lerna init
npm i

Скриншот 2022-08-29 в 08.30.10.png

Это создало репозиторий lerna с packages папка и lerna.json конфигурационный файл. Вам не нужно возиться с этим, если вы не должны.

внутри packagesсоздайте три папки: common, frontend, backend
давайте углубимся common набрав в терминале: cd packages/common
Затем инициализируйте репозиторий npm, используя npm init -y.
Во вновь созданном package.jsonизмените имя проекта на что-то вроде этого:
Скриншот 16.12.2022, 06.56.17.png
в формате «@{projectName}/{module}», как я сделал. Это стандартное соглашение и лучшая практика для монорепозиториев.

Я добавил скрипт «dev-common», который просто компилирует машинописный текст и следит за изменениями.

NB: «main» должен указывать на «dist/index.js», как мы настроим позже.

Теперь, пока общее, давайте установим зависимости: npm i typescript
И давайте создадим 3 файла: index.ts, types.ts, functions.ts

В types.tsДобавить:

interface User {
  firstName: string;
  lastName: string;
}

export { User };

и для functions.ts:

import { User } from "./types";

const getUserFullName = (user: User) => `${user.firstName} ${user.lastName}`;

export { getUserFullName };

и для index.ts:

export * from "./functions";
export * from "./types";

Наконец, нам нужен tsconfig.json файл:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "rootDir": "src",
    "outDir": "dist",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "$schema": "
  "display": "Recommended"
}

NB: убедитесь, что целью является ES5, чтобы мы могли скомпилировать низкоуровневый javascript, а ключи Declaration и DeclarationMap были истинными, чтобы он создавал для нас файлы объявлений Typescript.

Вернемся к нашему корню (cd ../..) и в нашем package.json определим скрипт:

 "dev-common": "lerna run dev-common",

и давайте запустим его: npm run dev-common

Скриншот 16.12.2022, 07.01.02.png

Надеюсь, мы получим это. Обратите внимание, что он строит dist папка в общем пакете

Большой! Мы установили некоторые общие вещи. Давайте теперь перейдем в папку бэкэнда:
cd ../backend
npm init -y
а также изменить название проекта.
Скриншот 2022-08-29 в 08.48.56.png

Сделаем быстрый сервер:

npm i express @types/express typescript
npm i --save-dev nodemon ts-node

Скопируйте и вставьте tsconfig.json из common в backend также.
Создать файл index.ts:

import { User } from "@seanh/common";
import express from "express";

const users: User[] = [
  { firstName: "Sean", lastName: "Hurwitz" },
  { firstName: "Batman", lastName: "Michaels" },
];

const app = express();

app.use(express.json());

app.get("/", (req, res) => {
  res.send("Hello!");
});

app.get("/users", (req, res) => {
  res.json(users);
});

app.listen(2050, () => {
  console.log(`server up on http://localhost:${2050}`);
});

Обратите внимание, как мы импортируем пользовательский интерфейс из @seanh/common. Но откуда он знает? Потому что в package.jsonэто то что ты делаешь:

{
  "name": "@seanh/backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
     "dev-backend": "tsc -w & nodemon dist/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@seanh/common": "1.0.0",
    "@types/express": "^4.17.13",
    "express": "^4.18.1",
    "typescript": "^4.8.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.19",
    "ts-node": "^10.9.1"
  }
}

Я вручную добавил первую строку в зависимости. Убедитесь, что версия точно соответствует версии в package.json из common папка. (Кроме того, я добавил простой скрипт для запуска сервера).
Теперь давайте перейдем к корню нашего проекта в терминале. вы можете использовать либо cd ../.. или открыть новый терминал. Затем запустите:
npx lerna bootstrap
Это побуждает lerna создавать символические ссылки, символические ссылки на различные пакеты в репозитории в соответствии с их зависимостью друг от друга. Поскольку общая папка является зависимостью от внутренней папки, lerna свяжет ее с серверной частью и придаст ей поведение пакета, как если бы он был загружен из npm!

в корневой package.json можно добавить скрипт:
"dev-backend": "lerna run dev-backend"
Это запустит скрипт dev-backend в любом пакете, в котором он есть (в данном случае это только бэкэнд).

Мы надеемся, что запуск этого запустит сервер и перейдет к локальный хост вернет вам:
Скриншот 2022-08-29 в 09.33.42.png
Итак, вы можете видеть, что внутренняя папка успешно использует код нашей общей папки!
Теперь добавим интерфейс. пойти в frontend папка:
cd packages/frontend
Я просто разверну приложение React для простоты использования, но на самом деле вы можете сделать что угодно:

npx create-react-app --template typescript .

(примечание: вы можете получить сообщение об ошибке, потому что lerna уже добавила package.json в папку внешнего интерфейса. Просто удалите файл и перезапустите create-react-app)

Очистить App.tsx и добавьте этот код:

import { getUserFullName, User } from "@seanh/common";
import { useEffect, useState } from "react";

function App() {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    fetch("http://localhost:2050/users")
      .then((r) => r.json())
      .then((r) => setUsers(r));
  }, []);

  return (
    <div>
      <h1>Users</h1>
      <ul>
        {users.map((user) => (
          <li key={user.firstName}>{getUserFullName(user)}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

не забудьте добавить "@seanh/common": "1.0.0", в зависимостях фронтенда package.json.

Вернуться к корню(cd ../..) и беги npx lerna bootstrap очередной раз
Я добавил этот скрипт в корень package.json:
"dev-frontend": "lerna run start"

Теперь вы можете бежать npm run dev-frontend и, надеюсь, приложение раскручивается!

Скриншот 16.12.2022, 07.08.54.png

Вуаля. Фронтенд использует типы и метод из общей библиотеки!

Заключение

В этой краткой статье рассказывается о монорепозиториях и о том, как настроить их для повторного использования кода. Дайте мне знать, что вы думаете в разделе комментариев ниже!

Похожие записи

Добавить комментарий

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