فرید هاشمیان
فرید هاشمیان
خواندن ۷ دقیقه·۱ سال پیش

ایجاد پکیج اختصاصی 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 rollup
npm i -D @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-postcss rollup-plugin-typescript2
npx 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.ts

export 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.ts

export { default as CustomButton } from &quot./Button&quot

src/components/index.ts

export * from &quot./Button&quot

src/index.ts

export * 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.ts

import 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.ts

import 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.ts

import 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 storybook


npm 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


Component libraryrollupcreate packagepackage registryquot quot
شاید از این پست‌ها خوشتان بیاید