<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های فرید هاشمیان</title>
        <link>https://virgool.io/feed/@sfaridhr76</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-16 10:28:29</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>فرید هاشمیان</title>
            <link>https://virgool.io/@sfaridhr76</link>
        </image>

                    <item>
                <title>ایجاد پکیج اختصاصی npm و Rollup و react  در gitlab</title>
                <link>https://virgool.io/@sfaridhr76/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D9%BE%DA%A9%DB%8C%D8%AC-%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B5%DB%8C-npm-%D9%88-rollup-%D9%88-react-%D8%AF%D8%B1-gitlab-khfstf6re54i</link>
                <description>با سلام خدمت دوستان عزیزتوی این پست قرار هست در مورد ساخت پکیج اختصاصی توضیحاتی بدم.با من همراه باشید .برای شروع اول به این سوال میخوام جواب بدم چه نیازی هست اصلا  من بیام پکیج اختصاصی بنویسم ؟🤔🤔از دلایلی که برای این کار هست اگر در شرکتی مشغول به کار هستید و روی پروژه ای کار میکنید که پروژه به صورت خصوصی تعریف شده است  شما باساخت پکیج به صورت خصوصی حریم خصوصی راحفظ میکنید یعنی با ساختن پکیج خصوصی، شما تنها به اعضایی که دسترسی به آن را دارند اجازه می‌دهید تا کد و محتوای پروژه را مشاهده و مشارکت کنند. این برای پروژه‌هایی که اطلاعات حساسی را شامل می‌شوند یا تغییرات قابل مشاهده برای عموم نامطلوب است، بسیار مهم است.کنترل دسترسی به کد: با ایجاد پکیج خصوصی، شما می‌توانید تنظیم کنید که کد و تغییرات در پروژه تنها توسط اعضای خاص دیده شود و اجازه ندهید هر کسی به آن دسترسی داشته باشد. این برای پروژه‌هایی که ممکن است به کاربران غیرمجاز دسترسی داده شود یا از انتشار دسترسی عمومی خودداری می‌کنید، مفید است. محافظت از اطلاعات حساس: اگر پروژه شامل اطلاعات حساس مانند اطلاعات شخصی یا محرمانه است، ساختن پکیج خصوصی می‌تواند به شما کمک کند تا از دسترسی غیرمجاز به این اطلاعات جلوگیری کنید وبهترین حفاظت را برای آن فراهم کنید.یکی دیگر از دلایل دسترسی راحت تر و سریع تر برای ادیت کردن و ورژن دادن روی پکیج هست که باعث سرعت بیشتر میشه و نکته جالب دیگه این هست که شما میتونید پکیج رو در پروژه هایی که دسترسی دارید داخل مجموعه استفاده کنید.خب در ادامه میخوایم با هم یه مثال ساده پیاده سازی کنیم 🙃🙃نکته : ما در این مثال میخوایم ساختار را به صورتی بچینیم که بتوان چندین پکیج ساخت تنها با استفاده از یک repoositoryنکته: این  روش با روش monorepo متفاوت است . یکی از تفاوت های اصلیشان در این است در این روش پکیج ها وابستگی به هم ندارند. تفاوت های دیگه رو شما در کامنت ها به من بگید :)برای شروع ما یک فولدر با نام دلخواه  ایجاد میکنیم 
mkdir packages
 cd packagesسپس برای ذخیره تغییرات ما به  git  نیاز داریم git initداخل فایل .gitignore  موارد زیر را قرار میدهیم */node_modules
/.pnp
.pnp.js
*/build
# testing
/coverage
*/storybook-static
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
.vscode
npm-debug.log*
yarn-debug.log*
yarn-error.log*در قدم بعدی میخوایم اولین پکیج خود را بسازیمmkdir react-button-kit 
cd react-button-kit 
npm init -yسپس از دستور زیر  برای نصب نیازمندی های پروژه استفاده میکنیم
npm i -D react typescript react-dom @types/react rollupnpm i -D @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-postcss rollup-plugin-typescript2npx storybook@latest initزمان نصب  storybook باید ماژول باندلر خود را webpack  انتخاب کنید. بعد از نصب نیازمندی ها فایل package.json باید به صورت زیر باشد {  &quot;name&quot;: &quot;react-button-kit&quot;,  &quot;version&quot;: &quot;1.0.0&quot;,  &quot;description&quot;: &quot;&quot;,.....  &quot;peerDependencies&quot;: {    &quot;react&quot;: &quot;^18.2.0&quot;,    &quot;react-dom&quot;: &quot;^18.2.0&quot;  }}در اینجا Peer Dependencies در واقع وابستگی‌هایی هستند که یک پکیج برای استفاده صحیح از خود به آنها نیاز دارد. این وابستگی‌ها بیشتر در مورد پکیج‌هایی است که از خود پروژه شما از طریق نصب شده‌اند و در همان محیط اجرایی (environment) فعلی وجود دارند.معمولاً وابستگی‌های peer به عنوان بسته‌هایی است که توسط افراد دیگر برای استفاده در نرم‌افزارها، فریم‌ورک‌ها یا ابزارهای بیرونی ایجاد شده‌اند. در مواردی که یک پروژه می‌خواهد این پکیج‌ها را به‌طور مستقیم استفاده کند، نیاز به تعریف peerDependencies و نسخه‌های موردنیاز از آنها دارد.با تعریف وابستگی‌های peer، به افراد مختلف اجازه داده می‌شود تا پکیج‌هایی را که فرضاً برای نشست دستوری (Runtime) نیاز دارند، به صورت جداگانه نصب و تنظیم کنند. این کاهش اتصال تنگاتنگ به بسته‌ی خاصی که توسعه دهنده‌ی اصلی وابستگی دارد، انعطاف‌پذیری و قابلیت سازگاری میزبان و ماهرانه در اجرای پروژه‌ها را افزایش می‌دهد.در ادامه ساختار پروژه را به صورت زیر میسازیمکامپوننت Button ButtonTypes.tsexport interface ButtonProps  extends React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt; {
  title: string;
}Button.style.css.custom-button-style {
  background-color: blue;
  color: white;
} Button.tsx import React, { FC } from &amp;quotreact&amp;quot
import { ButtonProps } from &amp;quot./ButtonTypes&amp;quot

import &amp;quot./Button.style.css&amp;quot
const CustomButton: FC&lt;ButtonProps&gt; = ({ title, ...props }) =&gt; {
  return (
    &lt;button
      className={props.className ? props.className : &amp;quotcustom-button-style&amp;quot}
      {...props}
    &gt;
      {title}
    &lt;/button&gt;
  );
};

export default CustomButton;Button/index.tsexport { default as CustomButton } from &amp;quot./Button&amp;quotsrc/components/index.tsexport * from &amp;quot./Button&amp;quotsrc/index.tsexport * from &amp;quot./components&amp;quotپیکربندی TypeScriptفایل tsconfig.json به صورت زیر است{
 &amp;quot$schema&amp;quot: &amp;quothttps://json.schemastore.org/tsconfig&amp;quot,
  &amp;quotdisplay&amp;quot: &amp;quotCreate React App&amp;quot,
  &amp;quot_version&amp;quot: &amp;quot2.0.0&amp;quot,
  &amp;quotcompilerOptions&amp;quot: {
    &amp;quotlib&amp;quot: [&amp;quotdom&amp;quot, &amp;quotdom.iterable&amp;quot, &amp;quotesnext&amp;quot],
    &amp;quotmodule&amp;quot: &amp;quotesnext&amp;quot,
    &amp;quotmoduleResolution&amp;quot: &amp;quotbundler&amp;quot,
    &amp;quottarget&amp;quot: &amp;quotes2015&amp;quot,
    &amp;quotallowJs&amp;quot: true,
    &amp;quotallowSyntheticDefaultImports&amp;quot: true,
    &amp;quotesModuleInterop&amp;quot: true,
    &amp;quotforceConsistentCasingInFileNames&amp;quot: true,
    &amp;quotisolatedModules&amp;quot: true,
    &amp;quotjsx&amp;quot: &amp;quotreact-jsx&amp;quot,
    &amp;quotnoEmit&amp;quot: true,
    &amp;quotnoFallthroughCasesInSwitch&amp;quot: true,
   &amp;quotresolveJsonModule&amp;quot: true,
    &amp;quotskipLibCheck&amp;quot: true,
    &amp;quotstrict&amp;quot: true
  }
}فایلrollup.config.jsبه صورت زیر استimport peerDepsExternal from &amp;quotrollup-plugin-peer-deps-external&amp;quot
import resolve from &amp;quot@rollup/plugin-node-resolve&amp;quot
import commonjs from &amp;quot@rollup/plugin-commonjs&amp;quot
import typescript from &amp;quotrollup-plugin-typescript2&amp;quot
import postcss from &amp;quotrollup-plugin-postcss&amp;quot

const packageJson = require(&amp;quot./package.json&amp;quot);

export default {
  input: &amp;quotsrc/index.ts&amp;quot,
  output: [
    {
      file: packageJson.main,
      format: &amp;quotcjs&amp;quot,
      sourcemap: true,
    },
    {
      file: packageJson.module,
      format: &amp;quotesm&amp;quot,
      sourcemap: true,
    },
  ],
  plugins: [
    peerDepsExternal(),
    resolve(),
    commonjs(),
    typescript({ useTsconfigDeclarationDir: true }),
    postcss(),
  ],
};سپس در فایل package.json کد زیر را قرار میدهیم...
 &amp;quotmain&amp;quot: &amp;quotbuild/index.js&amp;quot,
  &amp;quotmodule&amp;quot: &amp;quotbuild/index.es.js&amp;quot,
  &amp;quottypes&amp;quot: &amp;quotbuild/src/index.d.ts&amp;quot,
  &amp;quotfiles&amp;quot: [
     &amp;quotbuild&amp;quot
  ],
&amp;quotscripts&amp;quot: {
    &amp;quotbuild&amp;quot: &amp;quotrollup -c --bundleConfigAsCjs&amp;quot,
    &amp;quotprepublishOnly&amp;quot: &amp;quotnpm run build&amp;quot,
    &amp;quotstorybook&amp;quot: &amp;quotstorybook dev -p 6006&amp;quot,
    &amp;quotstorybook:export&amp;quot: &amp;quotbuild-storybook&amp;quot,
    &amp;quotbuild-storybook&amp;quot: &amp;quotstorybook build&amp;quot
 },
...فایل .babelrc.json به صورت زیر است.babelrc.json{
  &amp;quotsourceType&amp;quot: &amp;quotunambiguous&amp;quot,
  &amp;quotpresets&amp;quot: [
    [
      &amp;quot@babel/preset-env&amp;quot,
      {
        &amp;quottargets&amp;quot: {
          &amp;quotchrome&amp;quot: 100,
          &amp;quotsafari&amp;quot: 15,
          &amp;quotfirefox&amp;quot: 91
        }
      }
    ],
    &amp;quot@babel/preset-typescript&amp;quot,
    &amp;quot@babel/preset-react&amp;quot
  ],
  &amp;quotplugins&amp;quot: []
}سپس تنظیمات storybook را اضافه میکنیم .storybook/main.tsimport type { StorybookConfig } from &amp;quot@storybook/react-webpack5&amp;quot

const config: StorybookConfig = {
  stories: [&amp;quot../src/**/*.mdx&amp;quot, &amp;quot../src/**/*.stories.@(js|jsx|mjs|ts|tsx)&amp;quot],
  addons: [
    &amp;quot@storybook/addon-links&amp;quot,
    &amp;quot@storybook/addon-essentials&amp;quot,
    &amp;quot@storybook/addon-onboarding&amp;quot,
    &amp;quot@storybook/addon-interactions&amp;quot,
  ],
  framework: {
    name: &amp;quot@storybook/react-webpack5&amp;quot,
    options: {},
  },
  features: { storyStoreV7: false },   //   برای تنظیم پروژه برای حالت مونو ریپو
  docs: {
    autodocs: &amp;quottag&amp;quot,
  },
};
export default config; .storybook/preview.tsimport type { Preview } from &amp;quot@storybook/react&amp;quot

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: &amp;quot^on[A-Z].*&amp;quot },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
};

export default preview;بعد از initilize  شدن اتوماتیک فایل هایی برای ما ساخته میشود ما در این مرحله نیازی به فایل های داخل پوشه stories نداریم و همه را پاک کرده و داخل پوشه stories  فایل Button.stories.ts   میسازیمButton.stories.tsimport type { Meta, StoryObj } from &amp;quot@storybook/react&amp;quot
import { CustomButton } from &amp;quot../src&amp;quot

const meta = {
 title: &amp;quotExample/Button&amp;quotو
component: CustomButton,
parameters: {
layout: &amp;quotcentered&amp;quot,
},
tags: [&amp;quotautodocs&amp;quot],
} satisfies Meta&lt;typeof CustomButton&gt;;
export default meta;
type Story = StoryObj&lt;typeof meta&gt;;

export const Primary: Story = {
args: {
title: &amp;quotButton&amp;quot,
},
};ودر نهایت کامند زیر را اجرا میکنیمnpm run storybooknpm run buildتبریک پکیج شما آماده است در مرحله بعد مراحل publish شدن پکیج را خدمت شما عزیزان شرح خواهم داد.در این مرحله شما نیاز دارید یک project (repository ) جدید ایجاد کنید .شما میتوانید تغییرات را در هر مرحله از تغییر push  کنید و در هر package    ورژن بزنید (مرحله push  کردن اختیاری است به این معنی که لزومی به push   کردن به داخل ریپو برای ساخت پکیج نداریم این کار فقط برای ذخییره تغییرات برای مراحل بعدی است ولی خود ریپو را لازم داریم برای تنظیمات پکیج )بعد از ساخت project  این مسیر را بروید Settings &gt;General&gt;Visibility, project features, permissionsبخشPackage registry و گزینه Publish, store, and view packages in a project را فعال کنید.برای نصب/انتشار بسته ها باید خود را در رجیستری NPM Gitlab احراز هویت کنید.می‌توانید برای احراز هویت از یک توکن دسترسی شخصی با دامنه api انتخاب شده استفاده کنید یا از یک توکن نصب با مجوزهای read_package_registry و write_package_registry استفاده کنید. برای ساخت Deploy Token:Settings&gt; Repository &gt; Deploy tokens &gt; AddTokenتوکن را در محلی امن نگه دارید کنید چون در ادامه به آن نیاز داریمدر این مرحله تنظیمات برای publish  پروژه را انجام میدهیم برای این منظور در root پروژه فایل .npmrc  را میسازیم # Set URL for your scoped packages.
&lt;@my-org/package-name&gt;:registry=https://gitlab.com/api/v4/npm/

# Add the token for the scoped packages URL. This will allow you to download
//gitlab.com/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}

# Add token for uploading to the registry. Replace &lt;your_project_id&gt;
//gitlab.com/api/v4/projects/&lt;PROJECT_ID&gt;/packages/npm/:_authToken=${CI_JOB_TOKEN}در اینجا @my-org/package-name را نام کاربری خود و یا نام ارگانی که داخل gitlab  ست شده است قرار دهید.به جای  PROJECT_ID  زمانی که project جدید ساختی یک آی دی یکتا به شما تعلق میگیرد آن را دی این قسمت جایگذاری کنید.سپس داخل package.json  خط های زیر را اضافه میکنیم&amp;quotname&amp;quot: &amp;quot@mazraeapp/react-time-calender-kit&amp;quot,
  &amp;quotversion&amp;quot: &amp;quot1.0.1&amp;quot,
...
&amp;quotpublishConfig&amp;quot: {    
   &amp;quot&lt;@my-org/package-name&gt;:registry&amp;quot:&amp;quothttps://gitlab.com/api/v4/projects/&lt;PROJECT_ID&gt;/packages/npm/&amp;quot
  },
و در نهایت کامند زیر را اجرا میکنیم 

CI_JOB_TOKEN=your_token npm publishدر اینجا your_token  همان توکنی هست که که بالاتر در تنظیمات آن را گرفته بودیمتبریک اولین پکیچ شما pulbish شد  نکته : برای آپدیت های بعدی شما باید پکیج خود را ورژن بدهیدبرای نصب پکیج داخل پروژه های خود هم تنها نیاز دارید فایل .npmrc را به صورت زیر وارد کنید &lt;@my-org/package-name&gt;:registry=https://gitlab.mazraeapp.com/api/v4/packages/npm///gitlab.com/api/v4/packages/npm/:_authToken=&lt;Token&gt;//gitlab.com/api/v4/projects/&lt;PROJECT_ID&gt;/packages/npm/:_authToken=&lt;Token&gt;و کامند زیر رای برای نصب پکیج وارد کنیدnpm i &lt;@my-org/package-name&gt;/react-button-kitممنونم از اینکه تا اینجا همراه من بودید لینک سورس کد پروژه :https://gitlab.com/faridhash76/packages&amp;amp;amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;amp;amp;gt;لینکدین من:https://www.linkedin.com/in/farid-hashلینک های مراجع :https://docs.gitlab.com/ee/user/packages/npm_registry/https://blog.harveydelaney.com/creating-your-own-react-component-library/https://dev.to/siddharthvenkatesh/component-library-setup-with-react-typescript-and-rollup-onj</description>
                <category>فرید هاشمیان</category>
                <author>فرید هاشمیان</author>
                <pubDate>Sat, 09 Dec 2023 19:27:24 +0330</pubDate>
            </item>
            </channel>
</rss>