IlmHamroh
JavaScript Full-stack/24-qism. Node.js14/55-dars22 daqiqa
Mundarija (38)

npm paket nashr qilish: build, .d.ts, npm pack va scope bilan

Qisqacha: npm'ga manba kod emas, tayyor JS chiqariladi: tsc src/*.ts dan dist/ ga .js, .d.ts (tiplar) va .map yozadi. Nashrdan oldin paketni npm pack bilan arxivga yig'ib, boshqa papkaga o'rnatib sinaysiz — foydalanuvchi aynan shu arxivni oladi. Nom band bo'lmasligi uchun scope ishlatiladi (@login/valyuta, birinchi nashr --access public bilan). Haqiqiy npm publish uchun hisob, 2FA yoki trusted publishing kerak; noto'g'ri versiyani o'chirish emas, npm deprecate qilinadi.

Bu darsda

  • .ts paket nega node_modules ichida ishlamasligini haqiqiy xato bilan ko'rasiz va build zanjirini tushuntira olasiz.
  • dist/ ichidagi .js, .d.ts, .map fayllar nima uchun kerakligini bilasiz.
  • Paketni npm pack bilan yig'ib, boshqa loyihaga o'rnatib, npx va import bilan sinay olasiz.
  • Scope, --access public, publishConfig, 2FA, trusted publishing (OIDC), npm deprecate va changesets nima ekanini bilasiz.
  • publint va "Are The Types Wrong?" vositalari bilan paketni nashrdan oldin tekshira olasiz.

Oldin bilishingiz kerak: package.json IV: kirish nuqtalari, Semver va versiya diapazonlari, Ta'minot zanjiri xavfsizligi, CJS va ESM birga, Workspaces va monorepo asoslari.

1. Nega bu kerak?

O'tgan darsda valyuta ni ikki paketga bo'lib ko'rdik va bitta paket qoldirdik. CJS va ESM darsida esa unga bin, exports va files qo'shgan edik. Endi valyuta — boshqalar o'rnatadigan paket bo'lishga tayyor. Do'stingiz Toshkentdagi kompyuterida npx @login/valyuta 100 USD yozsa, unga sizning kodingiz kelishi kerak.

Bu yerda yangi muammo paydo bo'ladi. Sizning kompyuteringizda node src/bin.ts ishlaydi. Do'stingizning kompyuterida esa — ishlamasligi mumkin. Foydalanuvchi src/ ni emas, siz yig'gan arxivni oladi. Arxivga nima tushdi, u qayerda ochildi, qaysi Node'da ishga tushdi — bularning hammasi sizning qo'lingizdan chiqadi.

O'xshatish: non zavodi. Xamir (manba kod) zavodda qoladi. Do'konga esa yopilgan, qadoqlangan, yorlig'i yopishtirilgan non boradi. Qadoqni ochib ko'rmasdan do'konga jo'natish — xato. Bu darsda biz "qadoq" ni (.tgz arxiv) yasaymiz, ochib tekshiramiz, keyin qanday jo'natilishini o'rganamiz.

Bir narsani oldindan halol aytamiz. Kanon tajribasida haqiqiy npmjs.com ga nashr qilinmadi: buning uchun hisob va kalit kerak, kurs esa birovning nomidan hisob ochmaydi. Biz hamma narsani npm pack va npm publish --dry-run bilan sinadik. Haqiqiy npm publish ni siz o'zingiz, o'z hisobingiz bilan qilasiz — buyruqlari pastda.

2. Nega npm'ga .ts emas, JS chiqariladi

2.1 Tajriba: .ts bin'li paket

Workspaces darsida workspace ichidagi .ts fayl type stripping bilan ishladi. Kanon yana bir tajriba qildi: bin to'g'ridan-to'g'ri cli.ts ga qaratilgan paketni npm pack qilib, boshqa papkaga o'rnatdi. Paket ichidagi fayl node_modules da yotibdi. Natija:

text
Error [ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING]: Stripping types is currently unsupported for files under node_modules, for "file:///C:/Users/…/ilova/node_modules/tsbin/cli.ts"

Tarjimasi: "node_modules ostidagi fayllar uchun tiplarni o'chirish hozircha qo'llab-quvvatlanmaydi". Bu tasodif emas, Node'ning ataylab qilingan qarori. Paket muallifi qaysi TypeScript sozlamalari bilan yozganini Node bilmaydi. Shuning uchun begona .ts ni bajarmaydi.

Workspace'da nega ishladi? Chunki u yerda node_modules/@valyuta/core — Windows'da junction, ya'ni haqiqiy fayl node_modules dan tashqarida yotardi. Node haqiqiy yo'lga qaraydi.

Xulosa bitta: npm'ga faqat JS chiqariladi. TypeScript — sizning ish quroliz, foydalanuvchiga tayyor mahsulot boradi.

2.2 Build zanjiri

Butun yo'lni bitta rasmda ko'ring. Chapda — sizning kompyuteringiz, o'ngda — foydalanuvchiniki:

flowchart LR
  A["src/*.ts"] -->|tsc| B["dist/: .js .d.ts .map"]
  B -->|npm pack| C["login-valyuta-0.2.0.tgz"]
  C -->|npm publish| D[("npm registr")]
  D -->|npm i| E["node_modules/@login/valyuta"]
  C -.->|"sinov: npm i ../x.tgz"| E

Nuqtali chiziqqa e'tibor bering: biz registrni chetlab o'tamiz va arxivni to'g'ridan o'rnatamiz. Foydalanuvchi oladigan narsa baribir o'sha arxiv — shuning uchun sinov halol.

2.3 tsconfig.build.json: faqat build uchun sozlama

valyuta da ikkita tsconfig bor. Asosiysi (tsconfig.json) — tekshiruv uchun: noEmit: true, allowImportingTsExtensions: true. Build uchun alohida fayl uni kengaytiradi:

jsonc
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "noEmit": false,
    "allowImportingTsExtensions": false,
    "rewriteRelativeImportExtensions": true,
    "rootDir": "src",
    "outDir": "dist",
    "declaration": true,
    "sourceMap": true
  },
  "include": ["src"]
}
Kalit Nima qiladi
rewriteRelativeImportExtensions import "./cli.ts" ni JS'da "./cli.js" ga o'zgartiradi
rootDir / outDir src/kurs.ts → dist/kurs.js (papka tuzilmasi saqlanadi)
declaration har .js yonida .d.ts — tiplar
sourceMap .js.map — xato izi .ts qatoriga ishora qiladi
include: ["src"] testlar (test/) build'ga tushmaydi

package.json da ikkita skript bu faylni ishlatadi:

json
{
  "build": "tsc -p tsconfig.build.json",
  "prepack": "npm run build"
}

prepack — lifecycle skript (scripts chuqur). U npm pack va npm publish dan oldin avtomatik ishlaydi. Natijada eski dist/ ni nashr qilib yuborish xavfi yo'qoladi: arxiv har safar yangi build'dan yig'iladi.

Tekshirib ko'ring: prepack bo'lmasa va siz src/kurs.ts ni o'zgartirib, darhol npm publish qilsangiz, foydalanuvchiga nima boradi?

Javob

Eski kod. npm publish dist/ papkasini qanday bo'lsa, shunday arxivga soladi — oxirgi npm run build qachon bo'lgan bo'lsa, o'sha holat. src/ dagi o'zgarish foydalanuvchiga bormaydi. prepack aynan shu xatoga qarshi.

3. dist/ ichida nima bor

3.1 Uch xil fayl

Biz holat 12 ni scratch papkada build qildik. dist/ ichida har modul uchun uchta fayl chiqdi:

text
bin.d.ts  bin.js  bin.js.map
cli.d.ts  cli.js  cli.js.map
index.d.ts  index.js  index.js.map
kurs.d.ts  kurs.js  kurs.js.map
manba.d.ts  manba.js  manba.js.map
  • .js — Node bajaradigan kod. Tiplar o'chirilgan, ./cli.ts importlari ./cli.js ga aylangan.
  • .d.ts — tip e'loni fayli (declaration file): faqat tiplar, kod yo'q. O'xshatish — dori qutisidagi yo'riqnoma: dorining o'zi emas, lekin qanday ichishni aytadi. Foydalanuvchining muharriri shu fayldan avtomatik to'ldirish va xatolarni oladi.
  • .js.map — source map (Source map'lar). Xato izi dist/kurs.js:40 emas, src/kurs.ts:52 ni ko'rsatishi uchun.

dist/bin.js ning birinchi qatori — shebang. tsc uni src/bin.ts dan o'zgartirmasdan ko'chiradi:

text
#!/usr/bin/env node
// Kirish nuqtasi (package.json "bin"): signal, exit kod. Mantiq — cli.ts da
import { main } from "./cli.js";

Shebang'siz bin fayl Linux va macOS'da shell skript deb bajariladi. Workspaces tajribasida aynan shunday xato topilgan edi (import: command not found).

3.2 .d.ts ichiga qarash

dist/kurs.d.ts ning boshi:

ts
export interface Kurs {
    kod: string;
    nomi: string;
    nominal: number;
    kurs: number;
    farq: number;
    sana: string;
}
export declare const SOM: Kurs;
export declare function konvert(miqdor: number, dan: Kurs, ga: Kurs): number;
/** 11903.15 → "11 903.15" (minglik — bo'sh joy, kasr — nuqta, 2 xona) */
export declare function sonniYoz(n: number, xona?: number): string;

declare — "bu nom mavjud, uning kodi boshqa joyda (.js da)". JSDoc izohlari ham saqlanadi: foydalanuvchi sonniYoz ustiga sichqonchani olib borsa, shu izohni ko'radi.

Bir qiziq joy: dist/index.d.ts ichida import yo'li "./kurs.ts" bo'lib qoldi — rewriteRelativeImportExtensions faqat .js ni o'zgartiradi. Bu xato emasmi? Biz tekshirdik: o'rnatilgan paketni boshqa loyihada tsc 6.0.3 bilan tekshirdik. TypeScript ./kurs.ts ni ./kurs.d.ts ga moslab topdi va tip xatosini to'g'ri ushladi:

text
ishlat.ts(6,9): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Bu konvert("100", usd, SOM) qatoriga berilgan xato. Demak tiplar foydalanuvchiga yetib boradi.

Tekshirib ko'ring: Foydalanuvchi oddiy JavaScript yozadi, TypeScript ishlatmaydi. .d.ts unga foyda beradimi?

Javob

Ha. VS Code JS fayllarda ham .d.ts dan foydalanadi: avtomatik to'ldirish, parametr nomlari, JSDoc izohlari ko'rinadi. Tip xatolarini esa faqat // @ts-check yoki TypeScript bilan ko'radi.

3.3 tsc dan boshqa yo'l: tsup va tsdown

Kutubxonalar ko'pincha tsc o'rniga bundler asosidagi build vositasini ishlatadi. Ular bir nechta faylni bitta faylga yig'adi, ESM va CJS ni birdaniga chiqara oladi, .d.ts ni ham yig'adi:

Vosita 2026-10-23 holatiga versiya Asosi
tsc typescript 6.0.3 TypeScript kompilyatori, bundle qilmaydi
tsup 9.0.0 esbuild
tsdown 0.23.1 Rolldown (bundlerlar 2026)

valyuta uchun tsc yetarli: prod bog'liqlik 0, faqat ESM, fayllar kichik. Ikki formatli (dual) paket chiqarish kerak bo'lsa — tsup yoki tsdown tanlanadi. Lekin dual package hazard ni eslang: ikki nusxa — ikki xil holat. Node 24 da CJS loyiha ESM paketni require qila oladi (CJS va ESM birga), shuning uchun yangi paket uchun faqat ESM chiqarish odatiy tanlovga aylanmoqda. Bu vositalarni biz kanonda o'rnatmadik — versiyalar npm view dan.

4. npm pack: qadoqni ochib ko'rish

4.1 Arxivni yig'ish

npm pack — npm publish ning "jo'natmaydigan" egizagi. U paketni aynan nashr qilinadigan .tgz arxivga yig'adi va papkada qoldiradi. Kanon natijasi (holat 12, nom hali valyuta):

bash
npm pack
text
filename: valyuta-0.2.0.tgz
package size: 10.1 kB
unpacked size: 40.9 kB
shasum: 01ecaa4b3508b9ef9c0e95e5d64117a3ab05f28e
integrity: sha512-M9uPtrCmC7LFx[...]rYI0K7hGn8mhg==
total files: 17

Chiqishdan oldin prepack ishlaydi — tsc build qiladi. 17 fayl: dist/ dagi 15 ta, fixture va package.json. src/, test/, tsconfig* yo'q — buni files: ["dist", "fixtures"] ta'minlaydi (kirish nuqtalari).

shasum va integrity — arxivning hash'i. npm o'rnatishda aynan shu bilan arxiv yo'lda buzilmaganini tekshiradi (lock-fayllar).

4.2 Boshqa papkaga o'rnatish

Endi foydalanuvchi bo'lamiz. Butunlay boshqa papka, yangi loyiha:

bash
mkdir ilova && cd ilova
npm init -y
npm i ../valyuta/valyuta-0.2.0.tgz
text
added 1 package, and audited 2 packages in 2s
found 0 vulnerabilities

"1 package" — valyuta ning prod bog'liqligi yo'q. Uni o'rnatgan odam boshqa hech narsa yuklamaydi. Bu — kanonning ataylab qilingan qarori.

npm Windows'da node_modules/.bin/ ga bitta buyruq uchun uchta "shim" (kichik ishga tushiruvchi fayl) yozadi:

text
valyuta
valyuta.cmd
valyuta.ps1

Birinchisi — Git Bash va Linux uchun, .cmd — oddiy Windows terminali uchun, .ps1 — PowerShell uchun. Linux va macOS'da esa bitta symlink bo'ladi (hujjat bo'yicha; kanonda Linux sinalmagan).

4.3 Ikki xil sinov: buyruq va kutubxona

Paketning ikki yuzi bor — CLI (bin) va kutubxona (exports). Ikkalasini ham sinaymiz:

bash
VALYUTA_OFFLINE=1 npx valyuta 100 USD
text
100.00 USD = 1 190 315.00 UZS
bash
node -e 'import("valyuta").then((m) => console.log(Object.keys(m)))'

Biz ishga tushirdik (scope'li nom bilan, keyingi bo'limda) — 9 ta eksport keldi:

text
API, SOM, apidanOl, birlikKursi, fixturedanOl, konvert, royxatniOqi, sonniYoz, yozuvniOqi

CommonJS loyiha ham ishlata oladimi? eski.cjs faylida require bilan sinadik:

text
function 9

typeof v.konvert — function, eksportlar soni — 9. Node 24 da require(esm) sukut bo'yicha yoqilgan (CJS va ESM birga). bin.ts dagi top-level await kutubxona kirishiga (index.ts) tushmagani uchun shunday bo'ldi.

Diqqat: sinovni loyihaning o'z papkasida qilmang. U yerda src/, node_modules/ va boshqa fayllar bor — arxivda yo'q fayl tasodifan topilib, "ishlayapti" deb aldaydi. Faqat boshqa papka halol javob beradi.

Tekshirib ko'ring: files dan "fixtures" ni olib tashlasangiz, npm pack qancha fayl ko'rsatadi va VALYUTA_OFFLINE=1 npx valyuta 100 USD nima bo'ladi?

Javob

16 fayl — fixture arxivga tushmaydi. Offline rejim fixture faylni o'qiydi, u yo'q — ENOENT xatosi bilan yiqiladi. Sizning loyihangizda fayl turgani uchun bu xato faqat boshqa papkadagi sinovda ko'rinadi.

5. Nom, scope va --access public

5.1 Nom band bo'lmasin

npm'da nom — global va yagona: bitta nom, bitta egasi. Kanon 2026-10-23 da tekshirdi:

bash
npm view valyuta
text
npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/valyuta - Not found

404 — nom bo'sh. Lekin kursni minglab odam o'qiydi va hammasi bitta valyuta ni ola olmaydi. Shuning uchun sizga scope tavsiya qilinadi: @login/valyuta, bunda login — npmjs.com dagi foydalanuvchi nomingiz. Scope'ni .npmrc darsida ko'rgansiz: @ bilan boshlanadigan nomlar fazosi. Har foydalanuvchining scope'i o'ziniki — u yerda nom to'qnashuvi bo'lmaydi.

5.2 Biz ishga tushirdik: scope'li nom

Holat 12 nusxasida nomni o'zgartirdik va arxiv yig'dik:

bash
npm pkg set name=@login/valyuta
npm pack
text
npm notice name: @login/valyuta
npm notice version: 0.2.0
npm notice filename: login-valyuta-0.2.0.tgz
npm notice package size: 10.1 kB
npm notice total files: 17

Arxiv nomida @ va / yo'q — fayl nomida ular bo'lmaydi, shuning uchun login-valyuta. Hajm o'sha, lekin shasum boshqa chiqdi (719e41b8…) — package.json ichidagi nom o'zgardi.

5.3 --access public

Scope'li paket sukut bo'yicha yopiq (restricted) hisoblanadi. Yopiq paket — npm'ning pullik imkoniyati. Bepul hisobda birinchi nashrni ochiq qilish kerak. Biz --dry-run bilan ikkalasini solishtirdik (bo'sh .npmrc bilan — hech qanday hisob ulanmagan):

bash
npm publish --dry-run
text
npm warn publish This command requires you to be logged in to https://registry.npmjs.org/ (dry-run)
npm notice Publishing to https://registry.npmjs.org/ with tag latest and default access (dry-run)
+ @login/valyuta@0.2.0
bash
npm publish --dry-run --access public
text
npm warn publish This command requires you to be logged in to https://registry.npmjs.org/ (dry-run)
npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access (dry-run)
+ @login/valyuta@0.2.0

Farq — default access va public access. Birinchi qator: "bu buyruq uchun tizimga kirgan bo'lishingiz kerak" — dry-run baribir ishladi, lekin haqiqiy nashr shu joyda to'xtardi.

Har safar --access public yozmaslik uchun uni package.json ga yozib qo'yish mumkin:

json
{
  "publishConfig": {
    "access": "public"
  }
}

publishConfig — faqat nashr paytida qo'llanadigan sozlamalar. Unga tag yoki boshqa registry ham yozish mumkin.

Tekshirib ko'ring: Nima uchun scope'siz valyuta uchun --access public kerak emas edi?

Javob

Scope'siz paketlar har doim ochiq — yopiq bo'la olmaydi. "Yopiq" tanlovi faqat scope'li paketlarda bor, shuning uchun ularda sukut bo'yicha xavfsiz tomoni (yopiq) olinadi.

6. Haqiqiy nashr: hisob, 2FA va trusted publishing

Bu bo'lim hujjat bo'yicha — biz bajarmadik. Siz o'z hisobingiz bilan qilasiz.

6.1 Qo'lda nashr

bash
npm login
npm publish --access public

npm login brauzerni ochadi, siz npmjs.com da kirasiz. Hisobda 2FA (ikki bosqichli tasdiq) yoqilgan bo'lsa, nashrda qo'shimcha tasdiq so'raladi. 2FA — parolingiz o'g'irlansa ham, paketingizga zararli versiya chiqarib bo'lmasligi uchun.

Nega bu muhim? Ta'minot zanjiri darsida 2025-yil "Shai-Hulud" hujumini ko'rgansiz: o'g'irlangan npm tokenlar orqali yuzlab paketga zararli versiya chiqarildi. Token — parol o'rnida ishlatiladigan maxfiy satr: kim uni qo'lga kiritsa, sizning nomingizdan nashr qiladi. Hujumdan keyin GitHub (npm egasi) nashr qoidalarini qattiqlashtirdi:

Sana Nima o'zgardi (GitHub e'lonlari bo'yicha)
2025-09-22 reja e'lon qilindi: nashr faqat 2FA bilan, qisqa muddatli token yoki trusted publishing orqali
2025-10 / 11 yozish huquqli yangi tokenlar — sukut 7 kun, ko'pi bilan 90 kun; eski (classic) token yaratish o'chirildi
2025-12-09 hamma classic tokenlar butunlay bekor qilindi; npm login endi 2 soatlik seans beradi

Bu qoidalar hali ham o'zgarib turadi (2026-10 holatiga). Nashrdan oldin npm hujjatini o'qing — kursdagi jadval faqat yo'nalishni ko'rsatadi.

6.2 Trusted publishing (OIDC)

Eng xavfsiz yo'l — kompyuteringizda umuman token saqlamaslik. Trusted publishing (ta'minot zanjiri darsida tanishgansiz) quyidagicha ishlaydi:

  1. npmjs.com da paket sozlamasiga yozasiz: "bu paketni faqat login/valyuta repozitoriysidagi nashr.yml workflow nashr qila oladi".
  2. GitHub Actions ishga tushganda GitHub o'sha workflow uchun qisqa muddatli imzolangan guvohnoma beradi (OIDC — OpenID Connect, "men aynan shu repodagi shu workflow'man" degan raqamli hujjat).
  3. npm guvohnomani tekshiradi va bitta nashrga ruxsat beradi. Saqlanadigan, o'g'irlanadigan token yo'q.

Bonus: shunday nashr qilingan paketga npm avtomatik provenance (kelib chiqish guvohnomasi) qo'shadi — "bu arxiv aynan shu commit'dan, shu workflow'da yig'ilgan" degan ochiq yozuv. Shart: repozitoriy ham, paket ham ochiq (public) bo'lishi kerak. Trusted publishing'siz ham CI'da npm publish --provenance bilan shu yozuvni olish mumkin. Workflow'ning kerakli qismi (npm hujjatidagi namuna asosida; bizda push qilinmagan va ishlamagan):

yaml
permissions:
  id-token: write
  contents: read
steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-node@v6
    with:
      node-version: 24
      registry-url: https://registry.npmjs.org
  - run: npm ci
  - run: npm publish --access public

id-token: write — GitHub'ga OIDC guvohnomasini yaratishga ruxsat. npm hujjatiga ko'ra trusted publishing npm CLI 11.5.1+ va Node 22.14.0+ ni talab qiladi; bizning Node 24.21.0 va npm 11.19.0 mos. Ishlaydigan joylar: GitHub Actions, GitLab CI/CD, CircleCI (bulutdagi runner'lar; o'z serveringizdagi runner hali yo'q). Trusted publishing yoqilgach, npm paket sozlamasida tokenli nashrni butunlay taqiqlashni tavsiya qiladi ("Require two-factor authentication and disallow tokens").

7. Versiyalar hayoti: npm version, changesets, deprecate

7.1 npm version

Har nashr — yangi versiya: bir versiyani ikki marta nashr qilib bo'lmaydi. Semver qoidasi bo'yicha raqamni npm version oshiradi:

bash
npm version patch --no-git-tag-version
text
v0.2.1

--no-git-tag-version — faqat package.json ni o'zgartiradi. U bo'lmasa, npm git commit va v0.2.1 tegini ham yaratadi (repo toza bo'lishi shart).

7.2 changesets

Bir necha odam ishlaydigan loyihada "qaysi o'zgarish qaysi versiyaga" savoli murakkablashadi. changesets (@changesets/cli, 2026-10-23 holatiga 3.0.3) har PR'da kichik markdown fayl qoldirishni so'raydi: "patch: kesh xatosi tuzatildi". Nashr paytida u fayllarni yig'ib, versiyani oshiradi va CHANGELOG.md yozadi. Monorepo'larda ayniqsa ko'p ishlatiladi. Bizning bitta paketli valyuta uchun npm version yetarli — changesets kanonda ishlatilmadi.

7.3 Xato versiya chiqdi: deprecate, unpublish emas

Faraz qiling, 0.2.1 da konvert noto'g'ri hisoblaydi. Uni o'chirib tashlash kerakmi? Yo'q. npm unpublish ni qattiq cheklaydi. Hujjat bo'yicha birinchi 72 soatda o'chirish mumkin. Keyin — faqat paketga hech kim bog'lanmagan, o'tgan haftada 300 dan kam yuklangan va egasi bitta bo'lsa. Sababi — 2016-yildagi left-pad voqeasi: bitta kichik paket o'chirilgani minglab loyiha build'ini buzgan edi.

To'g'ri yo'l — tuzatilgan 0.2.2 ni chiqarish va eskisini deprecate (eskirgan deb belgilash) qilish:

bash
npm deprecate @login/valyuta@0.2.1 "xato; 0.2.2 ga yangilang"

Shundan keyin 0.2.1 ni o'rnatgan har kishi npm warn deprecated ogohlantirishini ko'radi. Paket o'chmaydi, lekin odamlar ogohlantiriladi.

8. Nashrdan oldin avtomatik tekshiruv

8.1 publint

publint — package.json va arxiv tarkibini tekshiradigan vosita: exports dagi fayl arxivda bormi, types to'g'ri joydami. Holat 12 nusxasida ishga tushirdik:

bash
npx publint@0.3.25
text
Running publint v0.3.25 for @login/valyuta...
Packing files with `npm pack`...
Linting...
All good!

8.2 Are The Types Wrong?

@arethetypeswrong/cli (attw) tiplarni turli moduleResolution rejimlarida tekshiradi. Natija qiziqroq chiqdi:

bash
npx @arethetypeswrong/cli@0.18.5 --pack . --format table-flipped
text
"@login/valyuta"  node10: 💀 Resolution failed
"@login/valyuta"  node16 (from CJS): ⚠️ ESM (dynamic import only)
"@login/valyuta"  node16 (from ESM): 🟢 (ESM)
"@login/valyuta"  bundler: 🟢

(Asl chiqish — chiziqli jadval; telefon uchun qatorlarga ajratdik.) Ikki ogohlantirishni o'qiymiz:

  • node10 — TypeScript'ning eski moduleResolution: "node" rejimi. U exports ni bilmaydi va top-level main/types qidiradi. Bizda ular yo'q. Bunday eski sozlamali loyihalar valyuta tiplarini topmaydi.
  • node16 from CJS — attw "CJS loyiha bu paketni faqat import() bilan ola oladi" deydi. Lekin biz yuqorida Node 24 da require ishlaganini ko'rdik. Farq shunda: attw tiplar dunyosidagi eski qoidani tekshiradi, Node 24 esa require(esm) ni allaqachon biladi.

Biz bu ikkisini qabul qildik: paket engines.node >=24 va zamonaviy TypeScript loyihalar uchun. Eski loyihalarni qo'llash kerak bo'lsa — main va types maydonlari yoki dual build (tsup/tsdown) kerak bo'lardi. Muhimi — qaror ongli, tasodifiy emas.

9. CLI qadami: holat 12 ni qadoqlab sinash

Bu darsda kod o'zgarmaydi — holat 12 (CJS va ESM birga darsida commit qilingan) ustida ishlaymiz. Bitta narsa esa doimiy o'zgaradi: paket nomi. Shu darsdan boshlab loyihangiz @login/valyuta deb ataladi.

Nima Oldin Shu darsdan keyin
package.json → "name" valyuta @login/valyuta
terminal buyrug'i (bin kaliti) valyuta valyuta — o'zgarmaydi
self-reference importi import("valyuta") import("@login/valyuta")
arxiv nomi valyuta-0.2.0.tgz login-valyuta-0.2.0.tgz

Kurs matnidagi kanon chiqishlarida keyin ham valyuta nomi ko'rinadi — kanon loyiha shu nom bilan o'lchangan. Sizda @login/valyuta chiqsa, bu to'g'ri. Nom o'zgarishini hozir alohida commit qilmang — u holat 18 commiti bilan birga ketadi (path va os darsida).

  1. valyuta papkasida: npm pkg set name=@login/valyuta (login o'rniga — o'z npm nomingiz), so'ng npm pack. 17 fayl, taxminan 10.1 kB chiqishi kerak.
  2. .gitignore da *.tgz borligini tekshiring (kanonda bor) — arxiv repoga tushmasin.
  3. Boshqa papkada: npm init -y, npm i ../valyuta/login-valyuta-0.2.0.tgz.
  4. VALYUTA_OFFLINE=1 npx valyuta 100 USD → 100.00 USD = 1 190 315.00 UZS.
  5. node -e 'import("@login/valyuta").then((m) => console.log(Object.keys(m)))' → 9 ta nom.
  6. npm publish --dry-run --access public — "public access" qatorini ko'ring.

Haqiqiy nashrni hozir qilmang. Paket hali 0.2.0 — kesh, bayroqlar va README keyingi darslarda qo'shiladi. Yakuniy 1.0.0 va tarqatish — CLI'ni tarqatish darsida.

10. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING Paket .ts bilan nashr qilingan Build qiling, bin/exports → dist/*.js
O'rnatilgan paketda eski kod dist/ qayta yig'ilmagan prepack: npm run build
ENOENT faqat foydalanuvchida Fayl files ro'yxatida yo'q npm pack --dry-run ni o'qing
E402 Payment Required Scope'li paket yopiq nashr qilinmoqda --access public yoki publishConfig
E403 … cannot publish over Bu versiya allaqachon nashr qilingan npm version patch
E404 scope'li nomda login sizning npm nomingiz emas Scope = hisob yoki tashkilot nomi
Tiplar topilmaydi exports da types yo'q yoki oxirida types — har shartning birinchisi
bin Linux'da shell xatosi beradi Shebang yo'q #!/usr/bin/env node

E402, E403 xabarlari — npm hujjatidan; biz ularni haqiqiy registrda ko'rmadik (nashr qilmadik).

11. Mashqlar

1-mashq (oson): arxivda nima bor?

npm pack chiqishiga qarab javob bering.

  • Holat 12 arxivida nechta fayl bor?
  • dist/ dagi qaysi fayl turi faqat tiplarni saqlaydi? .
  • npm pack dan oldin avtomatik build qiladigan skript nomi:
  • Scope'li paketni bepul hisobda nashr qilish uchun bayroq: --access
Yechim
  • 17 — 15 ta dist/ fayli, fixture va package.json.
  • d.ts — tip e'loni fayli; kod yo'q.
  • prepack — npm pack va npm publish dan oldin ishlaydi.
  • public — scope'li paket sukut bo'yicha yopiq.

2-mashq (o'rta): nashrga tayyormi?

package.json obyektini tekshiradigan tekshirPaket(pkg) funksiyasini yozing. U muammolar ro'yxatini qaytarsin:

  • private: true → "private: nashr qilinmaydi";
  • version semver emas (X.Y.Z, raqamlar) → "version: semver emas";
  • nom @ bilan boshlanadi, lekin publishConfig.access "public" emas → "scope: --access public kerak";
  • files yo'q → "files: hamma fayl arxivga tushadi";
  • exports["."] obyekt bo'lsa va uning birinchi kaliti types bo'lmasa → "exports: types birinchi bo'lsin".

Muammo yo'q bo'lsa — bo'sh massiv. Satr tekshiruvi uchun muntazam ifodalar kerak bo'ladi, obyekt kalitlari tartibi uchun Object.keys (Object.* metodlari).

Yechim
js
function tekshirPaket(pkg) {
  const muammolar = [];
  if (pkg.private === true) {
    muammolar.push("private: nashr qilinmaydi");
  }
  if (!/^\d+\.\d+\.\d+$/.test(pkg.version ?? "")) {
    muammolar.push("version: semver emas");
  }
  const ochiq = pkg.publishConfig?.access === "public";
  if (pkg.name?.startsWith("@") && !ochiq) {
    muammolar.push("scope: --access public kerak");
  }
  if (!Array.isArray(pkg.files)) {
    muammolar.push("files: hamma fayl arxivga tushadi");
  }
  const nuqta = pkg.exports?.["."];
  if (nuqta && typeof nuqta === "object") {
    if (Object.keys(nuqta)[0] !== "types") {
      muammolar.push("exports: types birinchi bo'lsin");
    }
  }
  return muammolar;
}

const yaxshi = {
  name: "@login/valyuta",
  version: "0.2.0",
  files: ["dist", "fixtures"],
  publishConfig: { access: "public" },
  exports: {
    ".": { types: "./dist/index.d.ts", default: "./dist/index.js" },
  },
};
const yomon = {
  name: "@login/valyuta",
  version: "1.0",
  private: true,
  exports: {
    ".": { default: "./dist/index.js", types: "./dist/index.d.ts" },
  },
};
console.log(tekshirPaket(yaxshi));
for (const m of tekshirPaket(yomon)) console.log(m);

Konsolda:

text
[]
private: nashr qilinmaydi
version: semver emas
scope: --access public kerak
files: hamma fayl arxivga tushadi
exports: types birinchi bo'lsin

Regex 1.0.0-beta.1 kabi prerelease versiyalarni rad etadi — haqiqiy loyihada semver paketining valid() funksiyasi ishlatiladi. exports kalitlari tartibi muhim: Node va TypeScript shartlarni yuqoridan pastga o'qiydi, birinchi mosi yutadi (kirish nuqtalari).

3-mashq (qiyin): o'z paketingizni qadoqlang

Kichik kutubxona yarating: @login/somchi — bitta funksiya somgaYoz(n) (1190315 → "1 190 315 so'm"). TypeScript'da yozing, tsconfig.build.json bilan dist/ ga build qiling (declaration: true), exports da types birinchi, files: ["dist"], prepack skripti. npm pack qiling, boshqa papkaga o'rnating va node -e bilan import qilib sinang. Oxirida npx publint va npx @arethetypeswrong/cli --pack . natijasini o'qing.

Yechim

src/index.ts:

ts
export function somgaYoz(n: number): string {
  const butun = Math.round(n).toString();
  return `${butun.replace(/\B(?=(\d{3})+(?!\d))/g, " ")} so'm`;
}

console.log(somgaYoz(1190315)); // 1 190 315 so'm

console.log faqat shu darsda tekshirish uchun — haqiqiy kutubxona faylida bo'lmaydi (yon ta'sirsiz import, CJS va ESM birga).

package.json ning muhim qismi:

json
{
  "name": "@login/somchi",
  "version": "0.1.0",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
  "files": ["dist"],
  "publishConfig": { "access": "public" },
  "scripts": {
    "build": "tsc -p tsconfig.build.json",
    "prepack": "npm run build"
  }
}

npm pack → login-somchi-0.1.0.tgz, ichida dist/index.js, dist/index.d.ts va package.json. Boshqa papkada npm i ../somchi/login-somchi-0.1.0.tgz va:

bash
node -e 'import("@login/somchi").then((m) => console.log(
  m.somgaYoz(5000)))'

Kutilgan natija: 5 000 so'm. publint — All good!; attw esa valyuta dagidek node10 va node16 (from CJS) ustunlarida ogohlantiradi (sababi — «Are The Types Wrong?» bo'limida).

4-mashq: CLI qadami

«CLI qadami» bo'limidagi oltita qadamni bajaring va natijani solishtiring: 17 fayl, 100.00 USD = 1 190 315.00 UZS, 9 ta eksport, public access.

Yechim

Natija mos kelmasa, eng ko'p sabab — sinovni valyuta papkasining o'zida qilish yoki npm pack dan keyin nomni o'zgartirish (arxiv eski nom bilan qoladi). Har o'zgarishdan keyin arxivni qayta yig'ing va boshqa papkada qayta o'rnating. .tgz faylni commit qilmang.

12. Real ishda

  • Ichki paketlar. Kompaniyalar umumiy kodni (UI komponentlar, API klient, ESLint sozlamasi) ichki registrga yoki GitHub Packages'ga scope bilan nashr qiladi: @kompaniya/ui. Jarayon aynan shu: build → pack → publish.
  • CI orqali nashr. Professional loyihalarda hech kim o'z kompyuteridan npm publish qilmaydi — teg qo'yiladi, GitHub Actions trusted publishing bilan nashr qiladi. CI/CD'ni keyingi qismlarda chuqur o'rganamiz.
  • Intervyu savollari: ".d.ts nima va kim yaratadi?", "npm pack nega kerak?", "Xato versiyani nashr qilsangiz nima qilasiz?" (javob — deprecate va yangi patch, unpublish emas).
  • Ochiq kod hissasi. O'zbek tilidagi kichik foydali paket (sana formatlash, telefon raqami tekshiruvi, lotin-kirill o'girish) — portfolio uchun kuchli dalil: kodingizni boshqalar ishlatadi.

Xulosa

  • npm'ga JS chiqariladi: node_modules ichidagi .ts ni Node bajarmaydi (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING).
  • tsc -p tsconfig.build.json → dist/: .js, .d.ts (tiplar), .map; prepack har arxivdan oldin build qiladi.
  • npm pack + boshqa papkaga npm i ../x.tgz — nashrdan oldingi eng halol sinov (17 fayl, 10.1 kB, 1 paket).
  • Scope (@login/valyuta) nom to'qnashuvini yo'qotadi; birinchi nashr --access public yoki publishConfig.
  • Haqiqiy nashr — 2FA yoki trusted publishing (OIDC, tokensiz, provenance bilan); xato versiya — npm deprecate.
  • publint va attw nashrdan oldin exports/types xatolarini ushlaydi; ogohlantirishni o'qib, ongli qaror qiling.

Keyingi dars: fs: uch API shakli — valyuta diskka yozishni o'rganadi: sync, callback va promise shakllari, ENOENT va kesh fayli.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
npm paket nashr qilish: build, .d.ts, npm pack va scope bilan — IlmHamroh