ایجاد پکیج اختصاصی npm و Rollup و react  در gitlab

با سلام خدمت دوستان عزیزتوی این پست قرار هست در مورد ساخت پکیج اختصاصی توضیحاتی بدم.با من همراه باشید .برای شروع اول به این سوال میخوام جواب بدم چه نیازی هست اصلا من بیام پکیج اختصاصی بنویسم ؟🤔🤔از دلایلی که برای این کار هست اگر در شرکتی مشغول به کار هستید و روی پروژه ای کار میکنید که پروژه به صورت خصوصی تعریف شده است شما باساخت پکیج به صورت خصوصی حریم خصوصی راحفظ میکنید یعنی با ساختن پکیج خصوصی، شما تنها به اعضایی که دسترسی به آن را دارند اجازه می‌دهید تا کد و محتوای پروژه را مشاهده و مشارکت کنند. این برای پروژه‌هایی که اطلاعات حساسی را شامل می‌شوند یا تغییرات قابل مشاهده برای عموم نامطلوب است، بسیار مهم است.کنترل دسترسی به کد: با ایجاد پکیج خصوصی، شما می‌توانید تنظیم کنید که کد و تغییرات در پروژه تنها توسط اعضای خاص دیده شود و اجازه ندهید هر کسی به آن دسترسی داشته باشد. این برای پروژه‌هایی که ممکن است به کاربران غیرمجاز دسترسی داده شود یا از انتشار دسترسی عمومی خودداری می‌کنید، مفید است. محافظت از اطلاعات حساس: اگر پروژه شامل اطلاعات حساس مانند اطلاعات شخصی یا محرمانه است، ساختن پکیج خصوصی می‌تواند به شما کمک کند تا از دسترسی غیرمجاز به این اطلاعات جلوگیری کنید وبهترین حفاظت را برای آن فراهم کنید.یکی دیگر از دلایل دسترسی راحت تر و سریع تر برای ادیت کردن و ورژن دادن روی پکیج هست که باعث سرعت بیشتر میشه و نکته جالب دیگه این هست که شما میتونید پکیج رو در پروژه هایی که دسترسی دارید داخل مجموعه استفاده کنید.خب در ادامه میخوایم با هم یه مثال ساده پیاده سازی کنیم 🙃🙃نکته : ما در این مثال میخوایم ساختار را به صورتی بچینیم که بتوان چندین پکیج ساخت تنها با استفاده از یک 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 باید به صورت زیر باشد { "name": "react-button-kit", "version": "1.0.0", "description": "",..... "peerDependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }}در اینجا Peer Dependencies در واقع وابستگی‌هایی هستند که یک پکیج برای استفاده صحیح از خود به آنها نیاز دارد. این وابستگی‌ها بیشتر در مورد پکیج‌هایی است که از خود پروژه شما از طریق نصب شده‌اند و در همان محیط اجرایی (environment) فعلی وجود دارند.معمولاً وابستگی‌های peer به عنوان بسته‌هایی است که توسط افراد دیگر برای استفاده در نرم‌افزارها، فریم‌ورک‌ها یا ابزارهای بیرونی ایجاد شده‌اند. در مواردی که یک پروژه می‌خواهد این پکیج‌ها را به‌طور مستقیم استفاده کند، نیاز به تعریف peerDependencies و نسخه‌های موردنیاز از آنها دارد.با تعریف وابستگی‌های peer، به افراد مختلف اجازه داده می‌شود تا پکیج‌هایی را که فرضاً برای نشست دستوری (Runtime) نیاز دارند، به صورت جداگانه نصب و تنظیم کنند. این کاهش اتصال تنگاتنگ به بسته‌ی خاصی که توسعه دهنده‌ی اصلی وابستگی دارد، انعطاف‌پذیری و قابلیت سازگاری میزبان و ماهرانه در اجرای پروژه‌ها را افزایش می‌دهد.در ادامه ساختار پروژه را به صورت زیر میسازیمکامپوننت Button ButtonTypes.tsexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { title: string; }Button.style.css.custom-button-style { background-color: blue; color: white; } Button.tsx import React, { FC } from &quotreact&quot import { ButtonProps } from &quot./ButtonTypes&quot import &quot./Button.style.css&quot const CustomButton: FC<ButtonProps> = ({ title, ...props }) => { return ( <button className={props.className ? props.className : &quotcustom-button-style&quot} {...props} > {title} </button> ); }; export default CustomButton;Button/index.tsexport { default as CustomButton } from &quot./Button&quotsrc/components/index.tsexport * from &quot./Button&quotsrc/index.tsexport * from &quot./components&quotپیکربندی TypeScriptفایل tsconfig.json به صورت زیر است{ &quot$schema&quot: &quothttps://json.schemastore.org/tsconfig&quot, &quotdisplay&quot: &quotCreate React App&quot, &quot_version&quot: &quot2.0.0&quot, &quotcompilerOptions&quot: { &quotlib&quot: [&quotdom&quot, &quotdom.iterable&quot, &quotesnext&quot], &quotmodule&quot: &quotesnext&quot, &quotmoduleResolution&quot: &quotbundler&quot, &quottarget&quot: &quotes2015&quot, &quotallowJs&quot: true, &quotallowSyntheticDefaultImports&quot: true, &quotesModuleInterop&quot: true, &quotforceConsistentCasingInFileNames&quot: true, &quotisolatedModules&quot: true, &quotjsx&quot: &quotreact-jsx&quot, &quotnoEmit&quot: true, &quotnoFallthroughCasesInSwitch&quot: true, &quotresolveJsonModule&quot: true, &quotskipLibCheck&quot: true, &quotstrict&quot: true } }فایلrollup.config.jsبه صورت زیر استimport peerDepsExternal from &quotrollup-plugin-peer-deps-external&quot import resolve from &quot@rollup/plugin-node-resolve&quot import commonjs from &quot@rollup/plugin-commonjs&quot import typescript from &quotrollup-plugin-typescript2&quot import postcss from &quotrollup-plugin-postcss&quot const packageJson = require(&quot./package.json&quot); export default { input: &quotsrc/index.ts&quot, output: [ { file: packageJson.main, format: &quotcjs&quot, sourcemap: true, }, { file: packageJson.module, format: &quotesm&quot, sourcemap: true, }, ], plugins: [ peerDepsExternal(), resolve(), commonjs(), typescript({ useTsconfigDeclarationDir: true }), postcss(), ], };سپس در فایل package.json کد زیر را قرار میدهیم... &quotmain&quot: &quotbuild/index.js&quot, &quotmodule&quot: &quotbuild/index.es.js&quot, &quottypes&quot: &quotbuild/src/index.d.ts&quot, &quotfiles&quot: [ &quotbuild&quot ], &quotscripts&quot: { &quotbuild&quot: &quotrollup -c --bundleConfigAsCjs&quot, &quotprepublishOnly&quot: &quotnpm run build&quot, &quotstorybook&quot: &quotstorybook dev -p 6006&quot, &quotstorybook:export&quot: &quotbuild-storybook&quot, &quotbuild-storybook&quot: &quotstorybook build&quot }, ...فایل .babelrc.json به صورت زیر است.babelrc.json{ &quotsourceType&quot: &quotunambiguous&quot, &quotpresets&quot: [ [ &quot@babel/preset-env&quot, { &quottargets&quot: { &quotchrome&quot: 100, &quotsafari&quot: 15, &quotfirefox&quot: 91 } } ], &quot@babel/preset-typescript&quot, &quot@babel/preset-react&quot ], &quotplugins&quot: [] }سپس تنظیمات storybook را اضافه میکنیم .storybook/main.tsimport type { StorybookConfig } from &quot@storybook/react-webpack5&quot const config: StorybookConfig = { stories: [&quot../src/**/*.mdx&quot, &quot../src/**/*.stories.@(js|jsx|mjs|ts|tsx)&quot], addons: [ &quot@storybook/addon-links&quot, &quot@storybook/addon-essentials&quot, &quot@storybook/addon-onboarding&quot, &quot@storybook/addon-interactions&quot, ], framework: { name: &quot@storybook/react-webpack5&quot, options: {}, }, features: { storyStoreV7: false }, // برای تنظیم پروژه برای حالت مونو ریپو docs: { autodocs: &quottag&quot, }, }; export default config; .storybook/preview.tsimport type { Preview } from &quot@storybook/react&quot const preview: Preview = { parameters: { actions: { argTypesRegex: &quot^on[A-Z].*&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 &quot@storybook/react&quot import { CustomButton } from &quot../src&quot const meta = { title: &quotExample/Button&quotو component: CustomButton, parameters: { layout: &quotcentered&quot, }, tags: [&quotautodocs&quot], } satisfies Meta<typeof CustomButton>; export default meta; type Story = StoryObj<typeof meta>; export const Primary: Story = { args: { title: &quotButton&quot, }, };ودر نهایت کامند زیر را اجرا میکنیمnpm run storybooknpm run buildتبریک پکیج شما آماده است در مرحله بعد مراحل publish شدن پکیج را خدمت شما عزیزان شرح خواهم داد.در این مرحله شما نیاز دارید یک project (repository ) جدید ایجاد کنید .شما میتوانید تغییرات را در هر مرحله از تغییر push کنید و در هر package ورژن بزنید (مرحله push کردن اختیاری است به این معنی که لزومی به push کردن به داخل ریپو برای ساخت پکیج نداریم این کار فقط برای ذخییره تغییرات برای مراحل بعدی است ولی خود ریپو را لازم داریم برای تنظیمات پکیج )بعد از ساخت project این مسیر را بروید Settings >General>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> Repository > Deploy tokens > AddTokenتوکن را در محلی امن نگه دارید کنید چون در ادامه به آن نیاز داریمدر این مرحله تنظیمات برای publish پروژه را انجام میدهیم برای این منظور در root پروژه فایل .npmrc را میسازیم # Set URL for your scoped packages. <@my-org/package-name>: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 <your_project_id> //gitlab.com/api/v4/projects/<PROJECT_ID>/packages/npm/:_authToken=${CI_JOB_TOKEN}در اینجا @my-org/package-name را نام کاربری خود و یا نام ارگانی که داخل gitlab ست شده است قرار دهید.به جای PROJECT_ID زمانی که project جدید ساختی یک آی دی یکتا به شما تعلق میگیرد آن را دی این قسمت جایگذاری کنید.سپس داخل package.json خط های زیر را اضافه میکنیم&quotname&quot: &quot@mazraeapp/react-time-calender-kit&quot, &quotversion&quot: &quot1.0.1&quot, ... &quotpublishConfig&quot: { &quot<@my-org/package-name>:registry&quot:&quothttps://gitlab.com/api/v4/projects/<PROJECT_ID>/packages/npm/&quot }, و در نهایت کامند زیر را اجرا میکنیم CI_JOB_TOKEN=your_token npm publishدر اینجا your_token همان توکنی هست که که بالاتر در تنظیمات آن را گرفته بودیمتبریک اولین پکیچ شما pulbish شد نکته : برای آپدیت های بعدی شما باید پکیج خود را ورژن بدهیدبرای نصب پکیج داخل پروژه های خود هم تنها نیاز دارید فایل .npmrc را به صورت زیر وارد کنید <@my-org/package-name>:registry=https://gitlab.mazraeapp.com/api/v4/packages/npm///gitlab.com/api/v4/packages/npm/:_authToken=<Token>//gitlab.com/api/v4/projects/<PROJECT_ID>/packages/npm/:_authToken=<Token>و کامند زیر رای برای نصب پکیج وارد کنیدnpm i <@my-org/package-name>/react-button-kitممنونم از اینکه تا اینجا همراه من بودید لینک سورس کد پروژه :https://gitlab.com/faridhash76/packages&amp;amp;amp;amp;amp;lt;br/&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