با سلام خدمت دوستان عزیز
توی این پست قرار هست در مورد ساخت پکیج اختصاصی توضیحاتی بدم.
با من همراه باشید .
برای شروع اول به این سوال میخوام جواب بدم چه نیازی هست اصلا من بیام پکیج اختصاصی بنویسم ؟🤔🤔
از دلایلی که برای این کار هست اگر در شرکتی مشغول به کار هستید و روی پروژه ای کار میکنید که پروژه به صورت خصوصی تعریف شده است شما باساخت پکیج به صورت خصوصی حریم خصوصی راحفظ میکنید یعنی با ساختن پکیج خصوصی، شما تنها به اعضایی که دسترسی به آن را دارند اجازه میدهید تا کد و محتوای پروژه را مشاهده و مشارکت کنند. این برای پروژههایی که اطلاعات حساسی را شامل میشوند یا تغییرات قابل مشاهده برای عموم نامطلوب است، بسیار مهم است.
کنترل دسترسی به کد: با ایجاد پکیج خصوصی، شما میتوانید تنظیم کنید که کد و تغییرات در پروژه تنها توسط اعضای خاص دیده شود و اجازه ندهید هر کسی به آن دسترسی داشته باشد. این برای پروژههایی که ممکن است به کاربران غیرمجاز دسترسی داده شود یا از انتشار دسترسی عمومی خودداری میکنید، مفید است.
محافظت از اطلاعات حساس: اگر پروژه شامل اطلاعات حساس مانند اطلاعات شخصی یا محرمانه است، ساختن پکیج خصوصی میتواند به شما کمک کند تا از دسترسی غیرمجاز به این اطلاعات جلوگیری کنید وبهترین حفاظت را برای آن فراهم کنید.
یکی دیگر از دلایل دسترسی راحت تر و سریع تر برای ادیت کردن و ورژن دادن روی پکیج هست که باعث سرعت بیشتر میشه و نکته جالب دیگه این هست که شما میتونید پکیج رو در پروژه هایی که دسترسی دارید داخل مجموعه استفاده کنید.
خب در ادامه میخوایم با هم یه مثال ساده پیاده سازی کنیم 🙃🙃
نکته : ما در این مثال میخوایم ساختار را به صورتی بچینیم که بتوان چندین پکیج ساخت تنها با استفاده از یک 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 "react" import { ButtonProps } from "./ButtonTypes" import "./Button.style.css" const CustomButton: FC<ButtonProps> = ({ title, ...props }) => { return ( <button className={props.className ? props.className : "custom-button-style"} {...props} > {title} </button> ); }; export default CustomButton;
Button/index.ts
export { default as CustomButton } from "./Button"
src/components/index.ts
export * from "./Button"
src/index.ts
export * from "./components"
پیکربندی TypeScript
فایل tsconfig.json به صورت زیر است
{ "$schema": "https://json.schemastore.org/tsconfig", "display": "Create React App", "_version": "2.0.0", "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext"], "module": "esnext", "moduleResolution": "bundler", "target": "es2015", "allowJs": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "react-jsx", "noEmit": true, "noFallthroughCasesInSwitch": true, "resolveJsonModule": true, "skipLibCheck": true, "strict": true } }
فایلrollup.config.jsبه صورت زیر است
import peerDepsExternal from "rollup-plugin-peer-deps-external" import resolve from "@rollup/plugin-node-resolve" import commonjs from "@rollup/plugin-commonjs" import typescript from "rollup-plugin-typescript2" import postcss from "rollup-plugin-postcss" const packageJson = require("./package.json"); export default { input: "src/index.ts", output: [ { file: packageJson.main, format: "cjs", sourcemap: true, }, { file: packageJson.module, format: "esm", sourcemap: true, }, ], plugins: [ peerDepsExternal(), resolve(), commonjs(), typescript({ useTsconfigDeclarationDir: true }), postcss(), ], };
سپس در فایل package.json
کد زیر را قرار میدهیم
... "main": "build/index.js", "module": "build/index.es.js", "types": "build/src/index.d.ts", "files": [ "build" ], "scripts": { "build": "rollup -c --bundleConfigAsCjs", "prepublishOnly": "npm run build", "storybook": "storybook dev -p 6006", "storybook:export": "build-storybook", "build-storybook": "storybook build" }, ...
فایل .babelrc.json به صورت زیر است
.babelrc.json
{ "sourceType": "unambiguous", "presets": [ [ "@babel/preset-env", { "targets": { "chrome": 100, "safari": 15, "firefox": 91 } } ], "@babel/preset-typescript", "@babel/preset-react" ], "plugins": [] }
سپس تنظیمات storybook را اضافه میکنیم
.storybook/main.ts
import type { StorybookConfig } from "@storybook/react-webpack5" const config: StorybookConfig = { stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], addons: [ "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-onboarding", "@storybook/addon-interactions", ], framework: { name: "@storybook/react-webpack5", options: {}, }, features: { storyStoreV7: false }, // برای تنظیم پروژه برای حالت مونو ریپو docs: { autodocs: "tag", }, }; export default config;
.storybook/preview.ts
import type { Preview } from "@storybook/react" const preview: Preview = { parameters: { actions: { argTypesRegex: "^on[A-Z].*" }, 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 "@storybook/react" import { CustomButton } from "../src" const meta = { title: "Example/Button"و component: CustomButton, parameters: { layout: "centered", }, tags: ["autodocs"], } satisfies Meta<typeof CustomButton>; export default meta; type Story = StoryObj<typeof meta>; export const Primary: Story = { args: { title: "Button", }, };
ودر نهایت کامند زیر را اجرا میکنیم
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 خط های زیر را اضافه میکنیم
"name": "@mazraeapp/react-time-calender-kit", "version": "1.0.1", ... "publishConfig": { "<@my-org/package-name>:registry":"https://gitlab.com/api/v4/projects/<PROJECT_ID>/packages/npm/" },
و در نهایت کامند زیر را اجرا میکنیم 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;lt;br/&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