برنامه نویسی

React and Typescript Components Lib ، قسمت 1: تنظیم و انتشار

مقدمه

در طول یک سال گذشته ، من مقالاتی راجع به موضوعات مختلف مرتبط با React نوشتم. اکنون ، هدف این است که اصول ایجاد یک کتابخانه React را که به قسمت های مختلف تقسیم شده است ، بپوشانیم و آنچه را که سال گذشته به همراه برخی مباحث جدید مورد بحث قرار گرفت ، استفاده کنید: تنظیم برنامه و انتشار ، استفاده از مؤلفه های یک ظاهر طراحی شده ، اضافه کردن TypeScript ، آزمایش واحد با JEST و تست-لیبراسیون ، ادغام ESLINT و زیباتر برای استاندارد سازی کد ، مستند سازی با کتاب داستان ، تنظیم قلاب های پیش از سازگار با Husky و خودکار سازی تولید کد با Hygen.
از آنجا که مباحثی را که قبلاً در مورد آنها نوشتم ، پوشش می دهم ، آن مقالات را در کتابهای مربوط به کتابخانه ارجاع می دهم. برای مواردی که نسخه جدید در مقایسه با آنچه قبلاً نوشتم تغییرات قابل توجهی را ایجاد کرده است ، ابتدا قبل از اجرای آن در کتابخانه ، مقاله اختصاصی را در مورد این موضوع منتشر خواهم کرد.
قسمت 1 نحوه تنظیم کتابخانه را پوشش می دهد ، اولین اجزای مثال را با استفاده از TypeScript با استفاده از اجزای سبک ایجاد کرده و آن را در NPMJ ها منتشر می کند تا دیگران بتوانند به آن دسترسی پیدا کنند.

غلتک

این یک دسته ماژول برای JavaScript است که امکان جمع آوری قطعات کوچک کد را در موجودات بزرگتر و پیچیده تر مانند کتابخانه ها فراهم می کند. در ایجاد کتابخانه استفاده خواهد شد.

npmjs

مکانی که در آن کتابخانه منتشر و برای استفاده از برنامه های دیگر در دسترس قرار خواهد گرفت.

اجزاء

یک کتابخانه یک ظاهر طراحی شده برای مؤلفه های برنامه های React ، انعطاف پذیری در تعریف سبک ها بر اساس غرفه های دریافت شده. من سال گذشته مقاله ای نوشتم که توضیح می دهد که چگونه کار می کند:
مؤلفه های یک ظاهر طراحی شده در واکنش با TypeScript

شرح

تایپ کردن را به یک برنامه JavaScript اضافه می کند و خطاها را در زمان کامپایل تشخیص می دهد.

تنظیم اولیه

یک پوشه با نام کتابخانه ایجاد کنید (توصیه می کنم NPMJ ها را بررسی کنید تا اطمینان حاصل کنید که یک کتابخانه با همین نام از قبل وجود ندارد ، برای جلوگیری از مشکلات هنگام انتشار آن) ، سپس پروژه را در داخل آن آغاز کنید.

yarn init

در حال حاضر ، می توانید تمام تنظیمات پیش فرض را بپذیرید. بعداً ، اطلاعات موجود در بسته تولید شده تنظیم می شود.

به عنوان وابستگی به همسالان ، واکنش های React و یک سبک را اضافه کنید زیرا آنها با کتابخانه همراه نخواهند شد (برنامه با استفاده از کتابخانه کامپوننت نیاز به افزودن آنها دارد). همچنین ، آنها را به عنوان وابستگی های انحرافی برای استفاده در هنگام توسعه کتابخانه مؤلفه اضافه کنید:

yarn add react react-dom styled-components --peer
yarn add react react-dom styled-components --dev

در زمان نوشتن این مقاله ، نسخه های زیر تولید شده است:

"react": "^19.0.0",
"react-dom": "^19.0.0",
"styled-components": "^6.1.14"
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

TypeScript را به پروژه اضافه کنید

TypeScript را به عنوان وابستگی DEV اضافه کنید:

yarn add typescript @types/react --dev

در زمان نوشتن این مقاله ، نسخه های زیر تولید شده است:

"@types/react": "^19.0.8",
"typescript": "^5.7.3"
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

فایل پیکربندی Typescript را به ریشه پروژه اضافه کنید.

{
  "compilerOptions": {
    "target": "ES2016",
    "jsx": "react",
    "module": "ESNext",
    "moduleResolution": "node",
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "dist",
    "declarationDir": "types",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • “هدف”: “ES2016” ، نسخه هدف ECMAScript را مشخص کنید
  • “JSX”: “واکنش” ، کد JSX را به React تبدیل کنید
  • “ماژول”: “esnext” ، ماژول های مدرن جاوا اسکریپت را برای کتابخانه تولید کنید
  • “Moduleresolution”: “گره” ، برای یافتن ماژول ها از قوانین Node.js پیروی کنید
  • “اعلامیه”: درست ، یک پرونده .d.ts را برای انواع کتابخانه تولید کنید
  • “EmitDeclarationonly”: درست است ، فقط اعلامیه های نوع را بدون تولید JS صادر کنید ، زیرا Rollup آن را اداره می کند.
  • “Outdir”: “Dist” ، دایرکتوری که در آن پروژه تولید می شود
  • “DemorationDir”: “انواع” ، که در آن پرونده .d.ts قرار می گیرد
  • “AllowsyntheticDefaultImports”: درست است ، فرض کنید در صورت عدم وجود صادرات به صورت دستی ، صادرات را پیش فرض کنید
  • “EsmoduleInterop”: درست ، امکان سازگاری بهتر بین ماژول های مشترک و ES را فراهم می کند
  • “forceconsientcassinginfilenames”: درست است ، بررسی کنید که آیا واردات پرونده با نام پرونده حساس به پرونده سازگار است
  • “سخت”: درست است ، تعداد زیادی از نوع چک های نوع را به همراه می آورد که یکپارچگی کد عالی را تضمین می کند
  • “SkiplibCheck”: درست است ، اعتبار نوع را برای پرونده .d.ts نادیده بگیرید

ایجاد اجزای مثال

دو مؤلفه مثال ایجاد می شود: یکی ساده برای متن و دیگری برای یک برچسب. اول ، الف src پوشه در ریشه پروژه و در داخل آن تولید می شود. components پوشه ای که تمام اجزای ایجاد شده در آن قرار می گیرند.

شروع با مؤلفه متن ، a Text پوشه در داخل ایجاد می شود components، با دو پرونده:

import React from "react";
import styled from "styled-components";

export interface TextProps {
  children: React.ReactNode;
  color?: string;
  weight?: "normal" | "bold";
  fontWeight?: number;
  fontSize?: string;
  fontFamily?: string;
}

export interface StyledTextProps {
  $color?: string;
  $weight?: "normal" | "bold";
  $fontWeight?: number;
  $fontSize?: string;
  $fontFamily?: string;
}

export const StyledText = styled.span<StyledTextProps>`
  color: ${(props) => 
    props.$color 
      ? props.$color 
      : "#000"};
  font-size: ${(props) => 
    props.$fontSize 
      ? props.$fontSize 
      : "16px"};
  font-weight: ${(props) =>
    props.$fontWeight
      ? props.$fontWeight
      : props.$weight
        ? props.$weight
        : "normal"};
  font-family: ${(props) => 
    props.$fontFamily 
      ? props.$fontFamily 
      : "Arial"};
`;

const Text = ({
  children,
  color,
  weight,
  fontWeight,
  fontSize,
  fontFamily,
}: TextProps) => (
  <StyledText
    $color={color}
    $weight={weight}
    $fontWeight={fontWeight}
    $fontSize={fontSize}
    $fontFamily={fontFamily}
  >
    {children}
  </StyledText>
);

export default Text;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این 5 غرفه را می پذیرد: children، که خود متن را نشان می دهد ، color، که رنگ متن را تعریف می کند ، fontWeight، که وزن قلم متن را تعریف می کند ، fontSize، که اندازه قلم متن را تعریف می کند ، و در نهایت fontFamily، که خانواده قلم متن را تعریف می کند. اگر هیچ یک از این غرفه ها ارائه نشده است ، به جز موارد children، StyledText در حال حاضر یک مقدار پیش فرض برای هر خاصیت تعریف شده است.

export { default } from "./Text";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این مؤلفه در دسترس خواهد بود.

اکنون ، برای مؤلفه برچسب ، a Tag پوشه در داخل ایجاد می شود components، با دو پرونده:

import React from "react";
import styled from "styled-components";
import Text from "../Text/Text";

export interface TagProps {
  type?: "default" | "success" | "alert" | "error";
  text: string;
  textColor?: string;
  textWeight?: "normal" | "bold";
  textFontWeight?: number;
  textFontSize?: string;
  textFontFamily?: string;
  backgroundColor?: string;
  format?: "default" | "semiRounded" | "rounded";
  borderRadius?: string;
  size?: "small" | "medium" | "large";
  padding?: string;
}

export interface StyledTagProps {
  $type?: "default" | "success" | "alert" | "error";
  $textColor?: string;
  $textWeight?: "normal" | "bold";
  $textFontWeight?: number;
  $textFontSize?: string;
  $textFontFamily?: string;
  $backgroundColor?: string;
  $format?: "default" | "semiRounded" | "rounded";
  $borderRadius?: string;
  $size?: "small" | "medium" | "large";
  $padding?: string;
}

export const StyledTag = styled.div<StyledTagProps>`
  border: none;
  padding: ${(props) =>
    props.$padding
      ? props.$padding
      : props.$size === "large"
        ? "15px 20px"
        : props.$size === "medium"
          ? "10px 12px"
          : "7px"};
  background-color: ${(props) =>
    props.$backgroundColor
      ? props.$backgroundColor
      : props.$type === "error"
        ? "#e97451"
        : props.$type === "alert"
          ? "#f8de7e"
          : props.$type === "success"
            ? "#50c878"
            : "#d3d3d3"};
  pointer-events: none;
  border-radius: ${(props) =>
    props.$borderRadius
      ? props.$borderRadius
      : props.$format === "rounded"
        ? "30px"
        : props.$format === "semiRounded"
          ? "5px"
          : "0"};
  width: fit-content;
`;

const Tag = ({
  text,
  type,
  textColor,
  textWeight,
  textFontWeight,
  textFontSize,
  textFontFamily,
  backgroundColor,
  format,
  borderRadius,
  size,
  padding,
}: TagProps) => (
  <StyledTag
    $type={type}
    $backgroundColor={backgroundColor}
    $format={format}
    $borderRadius={borderRadius}
    $size={size}
    $padding={padding}
  >
    <Text
      color={textColor || "#fff"}
      weight={textWeight}
      fontWeight={textFontWeight}
      fontSize={textFontSize}
      fontFamily={textFontFamily}
    >
      {text}
    </Text>
  </StyledTag>
);

export default Tag;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

11 غرفه را می پذیرد.
3 از قبل تعریف شده اند: size که بالشتک را تعریف می کند (اگر large تنظیم می کند 15px 20px، اگر medium تنظیم می کند 10px 12px) type که رنگ پس زمینه را تعریف می کند (اگر error تنظیم می کند #e97451، اگر alert تنظیم می کند #f8de7e، اگر success تنظیم می کند #50c878)) ، و format که شعاع مرزی را تعریف می کند (اگر rounded تنظیم می کند 30px، اگر semiRounded تنظیم می کند 5px).
و 8 قابل تنظیم هستند: text که متن برچسب را تعریف می کند ، textColor که رنگ متن را تعریف می کند ، textFontWeight که وزن فونت متن را تعریف می کند ، textFontSize که اندازه قلم متن را تعریف می کند ، textFontFamily که فونت خانواده متن را تعریف می کند ، backgroundColor که رنگ پس زمینه برچسب را تعریف می کند ، borderRadius که شعاع مرزی برچسب را تعریف می کند ، و سرانجام padding که بالشتک برچسب را تعریف می کند.
اگر هیچ یک از آنها ارائه نشده است ، به جز موارد text، StyledTag در حال حاضر یک مقدار پیش فرض برای هر خاصیت تعریف شده است.

export { default } from "./Tag";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این مؤلفه در دسترس خواهد بود.

پس از تعریف دو مؤلفه ، صادرات آنها در داخل متمرکز خواهد شد src/components پوشه:

export { default as Tag } from "./Tag";
export { default as Text } from "./Text";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سرانجام ، آنچه کتابخانه ارائه می دهد وقتی اضافه شود در داخل متمرکز خواهد شد src پوشه:

export * from "./components";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

به این ترتیب ، دو مؤلفه تعریف شده و قرار گرفتن در معرض آنها متمرکز است و این امکان را می دهد تا پیکربندی Rollup را ادامه دهند.

راه اندازی

برای استفاده از Rollup ، ابتدا کتابخانه های زیر اضافه می شوند:

yarn add rollup rollup-plugin-dts rollup-plugin-peer-deps-external @rollup/plugin-commonjs @rollup/plugin-node-resolve @rollup/plugin-typescript@11.1.6 @rollup/plugin-terser --dev

در زمان نوشتن این مقاله ، نسخه های زیر تولید شده است:

"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "11.1.6",
"rollup": "^4.30.1",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4"
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

برخلاف سایر کتابخانه ها که اضافه می شوند ، نسخه خاصی برای آن تعریف شده است @rollup/plugin-typescript به دلیل موضوعی که از استفاده از آن در نسخه های بعدی جلوگیری می کند.

در مرحله بعد ، ایجاد فایل پیکربندی Rollup در ریشه پروژه ، که از کتابخانه های اضافه شده استفاده می شود ، لازم است:

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
import terser from "@rollup/plugin-terser";
import peerDepsExternal from "rollup-plugin-peer-deps-external";

const packageJson = require("./package.json");

export default [
  {
    input: "src/index.ts",
    output: [
      {
        file: packageJson.main,
        format: "cjs",
      },
      {
        file: packageJson.module,
        format: "esm",
      },
    ],
    plugins: [
      peerDepsExternal(),
      resolve(),
      commonjs(),
      typescript({ tsconfig: "./tsconfig.json" }),
      terser(),
    ],
    external: ["react", "react-dom", "styled-components"],
  },
  {
    input: "src/index.ts",
    output: [{ file: "dist/index.d.ts", format: "esm" }],
    plugins: [dts.default()],
  },
];
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در این پرونده از کتابخانه های اضافه شده به برنامه استفاده می شود.
در input: "src/index.ts"، پرونده ای که اجزای آن صادر می شود تعریف شده است. در output، دو output پرونده ها ایجاد می شوند: اولین مورد در قالب CJS و دوم در قالب ESM ، که در Pack.json با مسیرهای آنها مشخص می شود. در peerDepsExternal() وت external: ["react", "react-dom", "styled-components"]، وابستگی های خارجی کتابخانه تعریف شده است ، به این معنی که این وابستگی ها هنگام افزودن کتابخانه به هم بسته نمی شوند. در Resolve () ، از الگوریتم گره برای یافتن ماژول های شخص ثالث در node_modulesبشر در commonjs()، ماژول های مشترک به ماژول های ES تبدیل می شوند و امکان استفاده از هر دو قالب را فراهم می کنند. در typescript({ tsconfig: "./tsconfig.json" })، ادغام بین Rollup و TypeScript تعریف شده است ، و مکان فایل پیکربندی Typescript ارائه شده است. در terser()، اندازه بسته نرم افزاری کاهش می یابد. سرانجام ، قسمت مربوط به dts.default() افزونه یک فایل خروجی را با انواع مورد استفاده در کتابخانه تعریف می کند.

بسته

در حال حاضر ، package.json باید چیزی شبیه به زیر باشد:

{
  "name": "react-example-lib", // the name of the folder where the project was initialized
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "@rollup/plugin-commonjs": "^28.0.2",
    "@rollup/plugin-node-resolve": "^16.0.0",
    "@rollup/plugin-terser": "^0.4.4",
    "@rollup/plugin-typescript": "^12.1.2",
    "@types/react": "^19.0.8",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "rollup": "^4.30.1",
    "rollup-plugin-dts": "^6.1.1",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "styled-components": "^6.1.14",
    "typescript": "^5.7.3"
  },
  "peerDependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "styled-components": "^6.1.14"
  }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

برخی از تغییرات و اضافات در آن مورد نیاز خواهد بود و به نظر می رسد:

{
  "name": "react-example-lib",
  "version": "0.1.0",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist"
  ],
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/griseduardo/react-example-lib.git"
  },
  "scripts": {
    "build": "rollup -c --bundleConfigAsCjs"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^28.0.2",
    "@rollup/plugin-node-resolve": "^16.0.0",
    "@rollup/plugin-terser": "^0.4.4",
    "@rollup/plugin-typescript": "^12.1.2",
    "@types/react": "^19.0.8",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "rollup": "^4.30.1",
    "rollup-plugin-dts": "^6.1.1",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "styled-components": "^6.1.14",
    "typescript": "^5.7.3"
  },
  "peerDependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "styled-components": "^6.1.14"
  }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • نام: نام کتابخانه تعریف شده است.
  • نسخه: نسخه کتابخانه از 1.0.0 به 0.1.0 تغییر یافت ، زیرا هنوز برای استفاده آماده نیست
  • اصلی: مسیر خروجی برای قالب CJS
  • ماژول: مسیر خروجی برای فرمت ESM
  • انواع: مسیر انواع کتابخانه
  • پرونده ها: پوشه ای که کل کتابخانه در آن قرار خواهد گرفت
  • مخزن: در صورتی که برنامه در آن قرار دارد نیز در GitHub قرار دارد
  • اسکریپت ها: ساخت تعریف شده است ، که اجرای آن را اجرا می کند

فایل

با اصلاح این کتابخانه ، نشان دادن آنچه با افزایش هر نسخه برای کسانی که از آن استفاده می کنند تغییر کرده است. برای این کار ، یک پرونده در ریشه ایجاد می شود:

## 0.1.0

_Jan. 29, 2025_

- initial config
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پرونده readme

بخش مهم دیگر اضافه کردن یک ReadMe است که توضیح می دهد برنامه در مورد چیست ، نحوه اضافه کردن آن و نحوه استفاده از اجزای آن. به ریشه اضافه می شود:

شرح تصویر

پرونده gitignore

در مورد انتشار کتابخانه در NPMJ ها و ایجاد یک مخزن GitHub برای آن ، مهم نیست که پوشه های خاصی را در GitHub بارگذاری نکنید. یک پرونده .gitignore به ریشه پروژه اضافه می شود:

dist
node_modules
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پوشه ها

سرانجام ، ساختار پوشه اولیه به این شکل خواهد بود:

شرح تصویر

انتشار کتابخانه

اولین قدم که باید انجام شود بررسی اینکه آیا اجرای برنامه با موفقیت انجام می شود یا خیر. برای انجام این کار ، yarn build در ترمینال اجرا می شود ، همانطور که در package.jsonبشر در صورت موفقیت ، الف dist پوشه به طور خودکار در ریشه پروژه ایجاد می شود.
پس از آن ، ایجاد یک حساب کاربری در NPMJS ، جایی که این کتابخانه منتشر خواهد شد ، لازم است.
پس از ایجاد حساب در سایت ، باید از طریق ترمینال در داخل پروژه وارد شوید:

npm login

جایی که شما نیاز به وارد کردن نام کاربری/ایمیل و رمز عبور (همان موارد ایجاد شده در سایت) دارید. پس از ورود به سیستم ، می توانید کتابخانه را منتشر کنید:

npm publish --access public

پس از اجرای موفقیت آمیز ، این کتابخانه در سایت NPMJS قابل مشاهده خواهد بود و باعث می شود برنامه های دیگر برای اضافه کردن و استفاده از مؤلفه های تعریف شده در داخل آن (متن و برچسب) در دسترس باشند. پس از reactبا react-domوت styled-components به عنوان وابستگی همسالان اضافه شدند ، اگر برنامه اضافه شده کتابخانه هیچ یک از آنها را نداشته باشد ، مطلع می شود که اینها وابستگی های لازم برای عملکرد کتابخانه در زمان افزودن هستند.

پایان

هدف از این مقاله نشان دادن نحوه ایجاد و انتشار یک کتابخانه مؤلفه در واکنش با TypeScript بود. برای دستیابی به این هدف ، نحوه تنظیم TypeScript و پیکربندی Rollup را پوشش می دهد ، دو مؤلفه را با استفاده از TypeScript با اجزای سبک تعریف می کند ، برخی از پرونده ها را ارائه می دهد که من معتقدم برای ردیابی تغییرات در کتابخانه و نشان دادن نحوه استفاده از آن مفید هستند و در آخر ، مراحل انتشار آن در NPMJS. مراحل بعدی شامل اجرای ویژگی های جدید در کتابخانه ، مانند آزمون ها ، قوانین قبل از تعهد و سایر موارد ذکر شده در مقدمه خواهد بود. من مخزن را در GitHub قرار می دهم و آن را در NPMJ ها منتشر می کنم تا با آنچه در مقاله می نویسم دنبال کنم.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا