پکیج npm یک ابزار کوچک قابل استفاده مجدد است، به اضافه متادیتا و یک قرارداد نسخه. بخش سخت برای من نوشتن تابع نیست. بخش سخت این است که مصرفکننده بداند کدام عدد راست است. package.json یک نسخه میگوید، برچسب git یکی دیگر، و یادداشت انتشار یا نیست یا با diff نمیخواند. انتشار دستی اینجا خراب میشود چون چند جا باید یک حقیقت را بگویند و وسط عجله یکی جا میماند.
GitHub برای این کار فقط محل کد نیست. جایی است که تاریخچه، بازبینی، و workflow انتشار به هم میرسند. npm محل توزیع است. این جدایی وقتی سالم است که منبع حقیقت تغییر، ریپو باشد و رجیستری نتیجه انتشار باشد نه یک آپلود جدا که کسی از لپتاپ زده. اتوماسیون این مسیر را کوتاه میکند. اگر قانون کامیت و مرز شاخه روشن نباشد، فقط همان ناهماهنگی را سریعتر به رجیستری میفرستد.
قرارداد کامیت ورودی نسخه است
کامیت قراردادی برای من سلیقه پیام نیست. ورودی تصمیم semver است. شکل آشنایش type(scope): description است. feat یعنی قابلیت تازه و معمولاً نسخه minor. fix یعنی رفع اشکال و معمولاً patch. تغییر ناسازگار، وقتی صریح علامت خورده باشد، major. نوعهایی مثل docs یا refactor میتوانند در تاریخچه بمانند بدون اینکه بهتنهایی انتشار بسازند. این نگاشت را ابزار حدس نمیزند مگر اینکه تو همان قرارداد را واقعاً رعایت کنی.
اگر پیامها را بعد از ادغام تمیز نمیکنی، اتوماسیون یا نسخه را بیدلیل بالا میبرد یا هیچ کاری نمیکند و تو فکر میکنی خراب است. هر دو بدند. برای پکیجی که دیگران نصب میکنند، دروغ نسخه بدتر از دیر منتشر کردن است. چون مصرفکننده بر اساس عدد تصمیم میگیرد بهروزرسانی امن است یا نه.
ابزاری که این قرارداد را به نسخه، changelog، برچسب، و انتشار وصل میکند اغلب semantic-release است، با افزونههایی برای یادداشت، git، و GitHub. نام افزونه را از نسخه قفلشده خودت بردار. اصل مهم است: ابزار مالک شماره نسخه باشد. برای همین version در دوره توسعه گاهی روی مقدار مخصوص توسعه میماند تا کسی دستی یک عدد را جلو نزند و با برچسب بعدی تصادم کند. ابزار را وابستگی توسعه همان ریپو نگه دار. نصب سراسری روی ماشین تو برای بقیه مشارکتکنندهها وجود ندارد و بخشی از قرارداد نیست.
اول اسم را دستی بگیر، بعد دستت را از انتشار بردار
اولین انتشار معمولاً دستی است. باید اسم بسته در رجیستری مال تو شود و یک نسخه اولیه واقعاً نصب شود. این همان لحظهای است که متادیتا، نقطه ورود، و فایلهایی که نباید داخل بسته بروند را روی ماشین خودت میبینی. یک نسخه پیشانتشار برای این آزمون مناسب است، به شرطی که مصرفکننده تصادفی را به آن قفل نکنی. وقتی نصب و سند و مجوز درست بود، تازه اتوماسیون را روشن کن.
بعد از آن نقش تو از اپراتور به ناظر عوض میشود. workflow روی شاخه انتشار، معمولاً main، بعد از سبز شدن تست اجرا شود. نه روی هر push به هر شاخه. توکن npm بهصورت راز GitHub بماند، فقط مجوز انتشار همان بسته را داشته باشد، داخل ریپو نیاید، و مثل رمز عوض شود. لاگ workflow باید معلوم کند نسخه ساخته شد یا عمداً ساخته نشد چون کامیت قابل انتشار نبود.
حفاظت شاخه اینجا تزئین پروژههای بزرگ نیست. اگر پکیج را مستقیم روی main هل بدهی، هر کامیت نیمهکاره میتواند نسخه عمومی شود. بازبینی کوتاه و سبز بودن بررسیها قبل از ادغام، ارزانتر از جمع کردن یک انتشار اشتباه از رجیستری است. برای تغییر ناسازگار، حتی اگر ابزار بتواند major بسازد، من هنوز یک نگاه انسانی میخواهم. اتوماسیون در علامت شکست خوب است. در توضیح مهاجرت برای مصرفکننده اغلب عجله دارد.
بسته یک قرارداد عمومی است
اسم بسته باید مسئله را بگوید. utils و helpers اسم نیستند. نقطه ورود باید فقط چیزی را صادر کند که حاضر هستی پشتیبانی کنی. هر تابع اضافی سطح عمومی، سطح ناسازگاری آینده است. ساختار پوشه مهم کمتر از این است که تست، قبل از انتشار، همان رفتار عمومی را بسنجد. اگر workflow بدون تست سبز منتشر کند، اتوماسیون فقط سرعت رساندن باگ به بقیه است.
README سطح محصول است. نصب، یک مثال کوتاه، و اینکه چه چیزی را عمداً انجام نمیدهد. نشان وضعیت ساخت وقتی مفید است که واقعاً به همان workflow وصل باشد. نشان دروغین بدتر از نبود نشان است. مجوز را هم همان اول انتخاب کن. این تصمیم حقوقی را به شب انتشار نسپار.
وابستگی را کوچک نگه دار. هر وابستگی هم بار نگهداری است هم سطح آسیبپذیری. npm audit جای طراحی را نمیگیرد، ولی نادیده گرفتن هشداری که به کد منتشرشده میرسد یعنی مصرفکننده را در جریان چیزی گذاشتهای که خودت حاضر نبودی ببینی. نسخه وابستگی را طوری قفل کن که نصب تکرارپذیر باشد، و بهروزرسانی امنیتی را از مسیر جدا، مثل Dependabot، بیاور نه اینکه با دست در همان کامیت فیچر قاطی شود.
وقتی اتوماسیون شکست خورد
شکست رایج احراز هویت، تصادم نسخه، و مجوز workflow است. برای همین باید انتشار دستی را هنوز بفهمی، نه اینکه فقط دکمه را بشناسی. اگر توکن مرد، اگر برچسب نیمهکاره ماند، یا اگر changelog رفت جلو و رجیستری نه، کسی باید بتواند از روی لاگ بگوید کدام گام تمام شده. این را در یک یادداشت کوتاه کنار ریپو بنویس. آینده تو همان مشارکتکننده است.
چیزی که دورش را خط میکشم: انتشار از لپتاپ بعد از اینکه اتوماسیون روشن شده، چون «فقط این بار». قاطی کردن کامیت قالب با کامیت رفتار، تا minor بیمعنی ساخته شود. راز در مثال README. و این تصور که چون GitHub Release قشنگ است، مصرفکننده دیگر نیازی به نسخه صادق ندارد.
پکیج خوب فقط کد خوب نیست. تجربه کسی است که آن را نصب میکند و میتواند بگوید این شماره چه فرقی با قبلی دارد. کامیت قراردادی، تست قبل از انتشار، و توکن تنگ این تجربه را میسازند. بقیه مراسم است. مراسم را خودکار کن فقط بعد از اینکه حقیقت نسخه یکی شده باشد.