সরাসরি পর্বে যান
পর্ব ০৫ · ৯৩-এর মধ্যে · মডিউল ১

কাজের পরিবেশ — Node, npm, Vite, ESLint, Prettier আর project-এর গঠন

Dev Environment — Node, npm, Vite, ESLint, Prettier and Project Structure

Taught in Bangla, this lesson sets up a real working environment: choosing a Node LTS and managing versions, creating a React and TypeScript project with npm create vite, dev, build and preview with real numbers, package.json, semver and the lockfile, ESLint and Prettier catching a real bug, .env files and why VITE_ values become public, the Bazarghar client, server and workspace layout, VS Code debugging and common Windows problems.

এই পর্বে যা শিখবেন

  • Node-এর LTS version বেছে নেওয়া আর একাধিক version সামলানো
  • Vite দিয়ে React TypeScript project বানানো, আর প্রতিটি তৈরি ফাইলের কাজ বোঝা
  • Build আউটপুটের সংখ্যা পড়া: bundle-এর আকার, gzip আর download সময়
  • Dependency, semver range, lockfile, npm ci আর npm audit নিয়ে সিদ্ধান্ত নেওয়া
  • ESLint আর Prettier বসানো, একটি আসল ভুল ধরে ঠিক করা
  • “বাজারঘর”-এর client ও server ফোল্ডার, workspace আর debugging সাজানো

১ · কাজের পরিবেশ কেন আগে গোছাতে হয়

একটি রেস্তোরাঁর রান্নাঘর ভাবুন। রান্না শুরুর আগে বাবুর্চি চুলা জ্বালান, মসলা হাতের কাছে রাখেন, ছুরি ধার দেন। এই গোছানোকে কেউ রান্না বলে না, কিন্তু এটি না হলে দুপুরের ভিড়ে সব ভেঙে পড়ে। সফটওয়্যারে এই গোছানো ব্যবস্থাটির নাম কাজের পরিবেশ (development environment).

গত চারটি পর্বে আপনি “বাজারঘর”-এর মানচিত্র দেখেছেন। এই পর্বে প্রথমবার আসল ফাইল তৈরি হবে। এখানকার প্রতিটি আউটপুট একটি সত্যিকারের run থেকে নেওয়া। যেখানে কিছু ভাঙল, সেটিও লুকানো হয়নি, কারণ আপনিও ঠিক সেখানেই আটকাবেন।

টুলরান্নাঘরে যাআসল কাজলেখার সময়ের version
Node.jsচুলাBrowser-এর বাইরে JavaScript চালায়24.15.0
npmবাজারের ফর্দ ও ডেলিভারিPackage আনে, হিসাব রাখে11.12.1
Viteরান্না ও প্যাকিংDev server চালায়, build বানায়8.3.5
TypeScriptরেসিপির মাপ মেলানোType মিলিয়ে দেখে6.0.3 (কারণ অংশ ৬-এ)
ESLintস্বাদ পরীক্ষকসন্দেহজনক কোড ধরে10.14.0
Prettierথালা সাজানোকোডের চেহারা এক রকম করে3.9.10

JavaScript course-এর npm, Vite, ESLint আর Prettier পর্বে bundler, node_modules আর semver-এর ভিত্তি আছে; আর ES module পর্বে import বোঝানো হয়েছে। এখানে সেগুলো আবার শেখানো হবে না। আমরা সেই জ্ঞান একটি আসল ফুল-স্ট্যাক project-এ লাগাব।

২ · Node-এর version — LTS বেছে নিন, একাধিক version সামলান

প্রথম সিদ্ধান্ত হলো Node-এর কোন version বসাবেন। Node-এর দুই ধরনের প্রকাশ থাকে: নতুন বৈশিষ্ট্যের ধারা, আর LTS (Long-Term Support), যা অনেক দিন নিরাপত্তা আপডেট পায়। কাজের project-এ LTS নিন। nodejs.org-এর “previous releases” পাতায় ১ নভেম্বর ২০২৬ তারিখে v26, v24 আর v22 LTS হিসেবে আছে, v20 ইতিমধ্যে EOL (End of Life, আর আপডেট আসে না)। এই তালিকা বদলায়, তাই নতুন project শুরুর সময় পাতাটি দেখে নিন।

টুলেরও নিজের চাহিদা থাকে। Vite কী চায়, সেটি মুখস্থ না করে সরাসরি জিজ্ঞেস করা যায়:

$ node -v
v24.15.0
$ npm -v
11.12.1
$ npm view vite engines
{ node: '^20.19.0 || >=22.12.0' }

সত্যিকারের run · Windows 10, Node 24.15.0, npm 11.12.1

আপনি যদি পুরোনো project-এ Node 18 আর নতুন project-এ Node 24 চান, তখন লাগে একটি version manager. এটি একই কম্পিউটারে কয়েকটি Node পাশাপাশি রাখে। Linux আর macOS-এ প্রচলিত nvm; Windows-এর জন্য আছে আলাদা একটি project, nvm-windows, যার কমান্ড মিললেও আচরণ হুবহু এক নয়। fnm আর Volta-ও ব্যবহৃত হয়।

# উদাহরণ — এই পর্বের machine-এ nvm বসানো ছিল না, তাই এটি চালানো হয়নি
# Linux / macOS (nvm)
nvm install --lts
nvm use --lts
echo "24" > .nvmrc      # project-এর version লিখে রাখা
nvm use                # .nvmrc পড়ে সেই version নেয়

# Windows (nvm-windows) — আগের Node installer সরিয়ে বসানোই নিরাপদ
nvm install lts
nvm use 24.15.0

মোবাইল ডেটায় কাজ করলে হিসাব রাখুন। এই run-এ প্রথম npm install নিয়েছিল ৩২ সেকেন্ড, আর ESLint-সহ পুরো node_modules হয়েছিল 148 MB. একটি নতুন project-এর আগে Wi-Fi থাকলে ভালো। npm একবার নামানো package নিজের cache-এ রাখে, তাই পরের install অনেক কম ডেটা খরচ করে।

৩ · প্রথম project — npm create থেকে প্রথম পাতা

এবার “বাজারঘর”-এর দোকানের সামনের অংশ, মানে frontend, শুরু করি। Scaffold মানে কাজের প্রাথমিক কাঠামো, যেমন বাড়ি বানানোর আগে বাঁশের ভারা বাঁধা।

npm create vite@latest bazarghar-web -- --template react-ts --no-interactive
cd bazarghar-web
npm install
npm run dev

মাঝের -- খেয়াল করুন। এর পরের অংশ npm নিজে পড়ে না, সোজা create-vite টুলের হাতে দেয়। প্রশ্নোত্তরের ধাপ চাইলে --no-interactive বাদ দিলেই হবে। চারটি কমান্ডের ভেতরে কী ঘটে, ধাপে ধাপে দেখুন। এখানকার প্রতিটি লেখা আসল run থেকে নেওয়া, শুধু লম্বা অংশ ছাঁটা।

  1. createcreate-viteকাঠামো
  2. installnode_modulespackage
  3. dev:5173server
  4. browserGET /index.html
Terminalটেমপ্লেট কপি হলো
create-vite v9.3.3
◇  Scaffolding project in ~/bazarghar-web...
└  Done. Now run:
  cd bazarghar-web
  npm install
  npm run dev
Terminalpackage.json পড়ে package আনা
added 28 packages, and audited 29 packages in 32s
9 packages are looking for funding
found 0 vulnerabilities
TerminalBundle ছাড়াই server চালু
  VITE v8.3.5  ready in 172 ms
  ➜  Local:   http://127.0.0.1:5173/
GET /200 text/html
<script type="module" src="/@vite/client"></script>
…
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
GET /src/main.tsx200 text/javascript
// ফাইল .tsx, কিন্তু উত্তর আসে JavaScript হয়ে
import "/src/index.css";
import App from "/src/App.tsx";
// react আসে আগে থেকে প্রস্তুত করা ফাইল থেকে
/node_modules/.vite/deps/react.js
src/main.tsxReact ঘর দখল করল
createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)
  1. ধাপ ১ — কাঠামো। npm create vite@latest আসলে create-vite package নামিয়ে চালায়। এটি টেমপ্লেট থেকে ফাইল কপি করে। এখনো কোনো node_modules নেই, React-ও বসেনি।
  2. ধাপ ২ — package আনা। npm install নতুন project-এ ২৮টি package বসাল (audit গুনল ২৯, কারণ project নিজেও একটি)। সঙ্গে তৈরি হলো package-lock.json.
  3. ধাপ ৩ — dev server. npm run dev ১৭২ ms-এ তৈরি। এত দ্রুত, কারণ dev server আগে পুরো অ্যাপ জোড়া দেয় না; চাহিদা অনুযায়ী ফাইল তৈরি করে।
  4. ধাপ ৪ — প্রথম অনুরোধ। Browser / চাইল। Vite index.html-এ নিজের দুটি script ঢুকিয়ে দিল। এগুলো কোড বদলের খবর আনে। পাতায় এখনো শুধু খালি div#root আছে।
  5. ধাপ ৫ — ফাইল অনুবাদ। Browser main.tsx চাইলে Vite সেটি JavaScript-এ অনুবাদ করে পাঠায়। ভেতরের প্রতিটি import আবার একটি করে অনুরোধ হয়। Browser নিজেই এখানে module জোড়া দিচ্ছে।
  6. ধাপ ৬ — প্রথম পাতা। createRoot খালি div#root-এর ভেতরে React-এর UI বসাল। পর্দায় টেমপ্লেটের পাতা এলো। এটিই পর্ব ৩-এর CSR: HTML প্রায় খালি, UI বানায় browser-এর JavaScript.

কোন ফাইলের কী কাজ

টেমপ্লেট থেকে ১৮টি ফাইল এসেছে। মুখস্থ নয়, শুধু জেনে রাখুন কোন সমস্যায় কোথায় যাবেন।

ফাইলকাজকখন খুলবেন
index.htmlঅ্যাপের প্রবেশপথ; Vite এখান থেকেই শুরু করেTitle, meta, font বদলাতে
src/main.tsxReact-কে #root-এ বসায়Provider বা router জুড়তে
src/App.tsxপ্রথম componentএখান থেকেই কাজ শুরু
src/index.css, App.cssStyleসাজসজ্জায়
src/assets/কোড থেকে import করা ছবি; build-এ নাম বদলায়Component-এর ছবিতে
public/যেমন আছে তেমন কপি হয়favicon, robots.txt-এ
vite.config.tsVite-এর নিয়ম ও pluginProxy, alias যোগ করতে
tsconfig*.jsonTypeScript-এর নিয়ম; app আর node অংশ আলাদাপর্ব ৬-এ
.oxlintrc.jsonLint-এর নিয়ম (অংশ ৬ দেখুন)Lint বদলাতে
.gitignoreকী version control-এ যাবে না: node_modules, dist, *.localনতুন গোপন ফাইল এলে
package.jsonProject-এর পরিচয়, script আর dependencyপ্রায়ই

৪ · dev, build আর preview — তিন মোড, বাস্তব সংখ্যা

চায়ের দোকানে চা বানানোর সময় আর পার্সেল বাঁধার সময় কাজের ধরন আলাদা। সফটওয়্যারেও তাই।

কমান্ডকী করেভুল ধারণা
npm run devফাইল চাহিদামতো অনুবাদ; HMR দিয়ে save করলেই পাতা বদলায়এটি production server নয়
npm run buildtsc -b দিয়ে type যাচাই, তারপর vite buildBuild শেষ মানে বাগ নেই, তা নয়
npm run previewতৈরি dist/ স্থানীয়ভাবে চালিয়ে দেখায়এটিও কেবল নিজের যাচাইয়ের জন্য
$ npm run build

> bazarghar-web@0.0.0 build
> tsc -b && vite build

vite v8.3.5 building client environment for production...
transforming...
✓ 20 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                   0.46 kB │ gzip:  0.30 kB
dist/assets/react-CHdo91hT.svg    4.12 kB │ gzip:  2.06 kB
dist/assets/vite-BF8QNONU.svg     8.70 kB │ gzip:  1.60 kB
dist/assets/hero-CLDdwZDr.png    13.05 kB
dist/assets/index-D64VDMd1.css    4.10 kB │ gzip:  1.47 kB
dist/assets/index-GpEN3EET.js   222.44 kB │ gzip: 69.28 kB

✓ built in 101ms

সত্যিকারের run · Vite 8.3.5, React 19.3.1 · একটি স্থানীয় run-এর সংখ্যা, সাধারণ ফল নয়

এই আউটপুট পড়তে জানা একটি আসল দক্ষতা। ফাইলের নামের GpEN3EET অংশটি বিষয়বস্তু থেকে তৈরি hash. কোড বদলালে নামও বদলায়, তাই browser পুরোনো cache নিয়ে বিভ্রান্ত হয় না। একটু পরে আমরা কোড বদলালে নাম সত্যিই বদলে যাওয়া দেখব।

হিসাব

একটি প্রায় খালি অ্যাপের JavaScript 222.44 kB, gzip-এ 69.28 kB. সংকোচনের অনুপাত 69.28 ÷ 222.44 ≈ 0.311, মানে ফাইল প্রায় ৬৯% ছোট হলো।

ধরে নিন ইন্টারনেটের গতি 1 Mbps (অনুমান)। 69.28 kB = 69.28 × 8 = 554.24 kilobit. সময় = 554.24 ÷ 1000 ≈ 0.55 সেকেন্ড. gzip না থাকলে 222.44 × 8 ÷ 1000 ≈ 1.78 সেকেন্ড. এটি শুধু তারের ভেতর দিয়ে আসার সময়; DNS, TLS আর JavaScript চালানোর সময় এতে ধরা নেই।

আর ফোন gzip খুলে পুরো 222.44 kB-ই parse করে। তাই সস্তা ফোনে JavaScript-এর খরচ download-এর চেয়েও বেশি হতে পারে। এই বিষয়ে পুরো আলোচনা আছে পর্ব ৭৯ (Build আর bundle)-এ।

$ npm run preview
  ➜  Local:   http://127.0.0.1:4173/

GET / → 200 text/html
<script type="module" crossorigin src="/assets/index-GpEN3EET.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D64VDMd1.css">

সত্যিকারের run · build-এর পরে

Dev আর preview-এর HTML মিলিয়ে দেখুন। Dev-এ ছিল /src/main.tsx, এখানে একটি মাত্র hash-ওয়ালা ফাইল। Dev-এ চললেই শেষ নয়; পাঠানোর আগে build আর preview চালান, কারণ দুটি পথ আলাদা।

একটি বিষয় পরিষ্কার করে নিই। dist/ ফোল্ডারে শুধু সাধারণ HTML, CSS আর JavaScript ফাইল আছে। এদের চালাতে Node লাগে না; যেকোনো static hosting থেকেই পরিবেশন করা যায়। তাই এই ফোল্ডারে API বা database-এর কোনো কাজ চলে না। সেই কাজের জন্য আলাদা server লাগবে, যা অংশ ৮-এ সাজানো হবে। কোথায় চালাবেন, সেই আলোচনা পর্ব ৮২-তে।

৫ · package.json, semver আর lockfile — হিসাবের খাতা

মুদি দোকানের কথা ভাবুন। ফর্দে লেখা “এক কেজি মিনিকেট চাল, যেকোনো ভালো ব্র্যান্ড”। এটি package.json. আর মেমোতে লেখা “অমুক ব্র্যান্ড, লট ২৭, ৮০ টাকা”। এটি lockfile. ফর্দ আপনার ইচ্ছা, মেমো যা সত্যিই এসেছে।

{
  "name": "bazarghar-web",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "oxlint",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.3.1",
    "react-dom": "^19.3.1"
  },
  "devDependencies": {
    "@types/node": "^24.19.2",
    "@types/react": "^19.3.0",
    "@types/react-dom": "^19.3.0",
    "@vitejs/plugin-react": "^6.1.2",
    "oxlint": "^1.89.0",
    "typescript": "~7.0.2",
    "vite": "^8.3.5"
  }
}
  • private: true: ভুল করে npm-এ প্রকাশ হওয়া আটকায়।
  • type: "module": এই project-এর .js ফাইল ES module হিসেবে পড়া হবে।
  • scripts: npm run dev এই তালিকা থেকে কমান্ড নেয়। node_modules/.bin নিজে থেকেই পথে যুক্ত হয়, তাই vite global ভাবে বসাতে হয় না।

dependencies বনাম devDependencies: প্রথমটি অ্যাপ চলতে লাগে, দ্বিতীয়টি শুধু বানাতে বা পরীক্ষা করতে। Server-এ এর সরাসরি ফল আছে: npm ci --omit=dev ESLint-এর মতো টুল বাদ দিয়ে হালকা install করে। Frontend-এ পার্থক্যটি কিছুটা নিয়মের ব্যাপার, কারণ bundle-এ শুধু সেই কোডই ঢোকে যা import হয়েছে।

npm install ভেতরে কী করে

  1. পড়াpackage.jsonফর্দ
  2. গাছideal treeহিসাব
  3. আনাtarballযাচাই
  4. বসানোnode_modulesগুদাম
  5. লেখাlockfileমেমো
পড়াইচ্ছা আর আগের মেমো
package.json       react: ^19.3.1
package-lock.json  নেই (নতুন project)
Registry-কে প্রশ্নRange মিলিয়ে version ঠিক করা
react ^19.3.1 → চলবে >=19.3.1 <20.0.0
নতুনতম যা মেলে → 19.3.1
react-এর নিজের dependency-ও একইভাবে…
Downloadআগে cache, পরে registry
resolved  .../react/-/react-19.3.1.tgz
integrity sha512-QNhWdt7nrgVWWQG58…
ফাইলের hash মিললে তবেই গ্রহণ
node_modulesযতটা সম্ভব সমতল
node_modules/react/
node_modules/vite/
node_modules/.bin/vite   ← npm run dev এটিই খোঁজে
added 28 packages
package-lock.jsonআসলে যা বসল
"node_modules/react": {
  "version": "19.3.1",
  "resolved": "https://registry.npmjs.org/…",
  "integrity": "sha512-…"
}
found 0 vulnerabilities
  1. ধাপ ১ — ফর্দ পড়া। npm package.json পড়ে। Lockfile থাকলে সেটিও পড়ে; মেমো আছে মানে বাজারে নতুন করে দরদাম লাগে না।
  2. ধাপ ২ — গাছ বানানো। প্রতিটি package-এর নিজের dependency আছে। npm পুরো গাছের হিসাব করে: কোন range-এ কোন version. আগে থেকে lockfile থাকলে সেখানকার version-ই বহাল থাকে, যদি range-এর সঙ্গে মেলে।
  3. ধাপ ৩ — আনা ও যাচাই। প্রতিটি package একটি সংকুচিত ফাইল (tarball). npm আগে নিজের cache দেখে, না পেলে registry থেকে আনে। Integrity hash না মিললে বাতিল। ডাকঘরে সিল ভাঙা পার্সেল ফিরিয়ে দেওয়ার মতো।
  4. ধাপ ৪ — গুদামে সাজানো। ফাইল node_modules-এ খোলা হয়, যতটা সম্ভব একই স্তরে। চালানো যায় এমন টুলের সংযোগ বসে .bin-এ। Package-এ install script থাকলে সেটিও এখানে চলে, তাই এটি নিরাপত্তারও ধাপ।
  5. ধাপ ৫ — মেমো লেখা। ফলাফল package-lock.json-এ ওঠে, শেষে audit-এর সারাংশ দেখায়। এই নতুন project-এ: ২৮টি package, ০টি vulnerability.

Semver range — কোন version চলবে

Semver মানে MAJOR.MINOR.PATCH নিয়মের নম্বর। Range-এর সিদ্ধান্তটি ধাপে ধাপে দেখুন।

নতুন version এলো, দুই range কী বলে
প্রার্থী version
Caret range
Caret-এর রায়
Tilde range
Tilde-এর রায়
  1. 19.3.0: নিচের সীমার নিচে। ^ আর ~ দুটিই বাতিল করে, কারণ দুটিরই শুরু 19.3.1 থেকে।
  2. 19.3.1: হুবহু নিচের সীমা। দুটিই নেয়।
  3. 19.3.9: শুধু PATCH বাড়ল, মানে বাগ সংশোধন। দুটিই নেয়।
  4. 19.4.0: MINOR বাড়ল। ^ নেয় (উপরের সীমা 20.0.0), কিন্তু ~ নেয় না (উপরের সীমা 19.4.0, যা বাইরে)। মূল পার্থক্য এখানেই।
  5. 20.0.0: MAJOR বদল মানে ভেঙে যাওয়ার মতো পরিবর্তন হতে পারে। কোনো range নেয় না। এটি আপনাকে নিজে বেছে নিতে হয়।
  6. 0.9.0, range ^0.8.2: 0.x ধারায় ^ সাবধানী হয়; উপরের সীমা 0.9.0, তাই এটি বাদ। প্রথম অশূন্য অঙ্কটিই বদলাতে দেওয়া হয় না।

এবার একটি ছোট package.json parse করে একই নিয়ম কোডে চালিয়ে দেখুন। আসল npm-এর নিজস্ব semver library আরও অনেক কিছু সামলায়; এটি শুধু ^ আর ~-এর হিসাব।

const pkg = JSON.parse(`{
  "name": "bazarghar-web",
  "dependencies": { "react": "^19.3.1", "bazar-ui": "^0.8.2" },
  "devDependencies": { "typescript": "~6.0.2" }
}`);
const registry = {
  react: ["19.3.0", "19.3.1", "19.4.0", "20.0.0"],
  "bazar-ui": ["0.8.1", "0.8.2", "0.8.9", "0.9.0"],
  typescript: ["6.0.1", "6.0.3", "6.1.0", "7.0.2"],
};
const num = (v) => v.split(".").map(Number);
function cmp(a, b) {
  for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] - b[i];
  return 0;
}
function upper(range) {
  const [major, minor, patch] = num(range.slice(1));
  if (range[0] === "~") return [major, minor + 1, 0];
  if (major > 0) return [major + 1, 0, 0];
  if (minor > 0) return [0, minor + 1, 0];
  return [0, 0, patch + 1];
}
function matches(range, version) {
  const x = num(version);
  return cmp(x, num(range.slice(1))) >= 0 && cmp(x, upper(range)) < 0;
}
const all = { ...pkg.dependencies, ...pkg.devDependencies };
for (const [name, range] of Object.entries(all)) {
  const ok = registry[name].filter((v) => matches(range, v));
  console.log(`${name} ${range}  =>  >=${range.slice(1)} <${upper(range).join(".")}`);
  for (const v of registry[name]) {
    console.log(`   ${v.padEnd(7)} ${matches(range, v) ? "yes" : "no"}`);
  }
  console.log(`   install picks: ${ok.at(-1)}`);
}

আউটপুটের মূল তিন লাইন: react ^19.3.1 => >=19.3.1 <20.0.0, bazar-ui ^0.8.2 => >=0.8.2 <0.9.0, typescript ~6.0.2 => >=6.0.2 <6.1.0. আর নির্বাচিত version যথাক্রমে install picks: 19.4.0, 0.8.9, 6.0.3. bazar-ui একটি কাল্পনিক package; 0.x ধারায় ^ কত সাবধানী, সেটি দেখাতে রাখা। পুরো কৌশল upper() ফাংশনে: উপরের সীমা ঠিক হলে বাকিটা শুধু তুলনা।

Lockfile কেন commit করবেন

রাফি মার্চে project বানিয়েছে, মিতু সেপ্টেম্বরে যোগ দিয়েছে। মাঝে নতুন version এসেছে। নিচের খেলনা data-তে দুজনের গাছ মিলিয়ে দেখুন।

// toy registry: what is published on two dates
const registry = {
  march: { "bazar-ui": ["1.2.0", "1.2.5"], "taka-format": ["2.0.0"] },
  september: { "bazar-ui": ["1.2.0", "1.2.5", "1.4.0"], "taka-format": ["2.0.0", "2.1.0"] },
};
const ranges = { "bazar-ui": "^1.2.0", "taka-format": "^2.0.0" };

// no lockfile: take the newest published version (all fit the range here)
function resolveFresh(month) {
  const tree = {};
  for (const name of Object.keys(ranges)) tree[name] = registry[month][name].at(-1);
  return tree;
}
// with a lockfile: take exactly what is written, if it still exists
function installFromLock(lock, month) {
  const tree = {};
  for (const [name, version] of Object.entries(lock)) {
    if (!registry[month][name].includes(version)) throw new Error(`${name}@${version} missing`);
    tree[name] = version;
  }
  return tree;
}
const show = (who, tree) => console.log(who.padEnd(26), JSON.stringify(tree));

const lock = resolveFresh("march");
show("Rafi, march (writes lock)", lock);
show("Mitu, september, no lock", resolveFresh("september"));
show("Mitu, september, with lock", installFromLock(lock, "september"));
const same = JSON.stringify(lock) === JSON.stringify(installFromLock(lock, "september"));
console.log("same tree as Rafi with lock:", same);
console.log("same tree as Rafi without lock:", JSON.stringify(lock) === JSON.stringify(resolveFresh("september")));

Lock ছাড়া মিতু পায় {"bazar-ui":"1.4.0","taka-format":"2.1.0"}, আর lock থাকলে {"bazar-ui":"1.2.5","taka-format":"2.0.0"}. শেষ দুই লাইনে same tree as Rafi with lock: true আর same tree as Rafi without lock: false. Range একই থাকলেও সময়ের সঙ্গে ফল বদলাতে পারে। “আমার কম্পিউটারে তো চলে” সমস্যার একটি বড় উৎস এটিই।

আসল টুলে একই আচরণ পরখ করা হয়েছে। Package ms-এর registry-তে 2.1.3 আছে, কিন্তু lockfile-এ 2.0.0 লেখা, আর range ^2.0.0:

$ npm install         → ms@2.0.0   (lockfile বহাল)
$ npm ci              → ms@2.0.0
$ npm update          → ms@2.1.3   (range-এর ভেতরে নতুনতম)
package.json-এ তখনো:  "ms": "^2.0.0"

সত্যিকারের run · npm 11.12.1 · লাইনগুলো সংক্ষেপ করে সাজানো

npm ci হলো স্বয়ংক্রিয় ব্যবস্থার (CI) জন্য কড়া সংস্করণ। npm-এর docs অনুযায়ী এটি lockfile বাধ্যতামূলক রাখে, node_modules মুছে শুরু করে, আর package.json বা lockfile কখনো লেখে না। দুটির অমিল হলে থেমে যায়। আমরা ইচ্ছা করে অমিল বানালাম:

$ npm pkg set dependencies.react="^18.0.0"
$ npm ci
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.
npm error Invalid: lock file's react@19.3.1 does not satisfy react@18.3.1

সত্যিকারের run · সংক্ষেপিত

পরিস্থিতিকমান্ড
নতুন package যোগnpm install zod
Build টুল যোগnpm install -D vitest
সহকর্মীর project নামিয়ে শুরু, বা CInpm ci
Range-এর ভেতরে আপডেটnpm update, তারপর test
পুরোনো package-এর তালিকা দেখাnpm outdated

৬ · ESLint আর Prettier — একটি আসল ভাঙন ও একটি আসল বাগ

Linter অর্থ খোঁজে: “এই কোডে বাগ থাকতে পারে।” Formatter চেহারা ঠিক করে: space, quote, লাইন ভাঙা। প্রুফরিডার আর লে-আউট শিল্পীর মতো দুটি আলাদা কাজ।

প্রথম চমক: নতুন Vite টেমপ্লেটে ESLint নেই। এর lint script চালায় Oxlint, একটি Rust-এ লেখা দ্রুত linter. অনেক পুরোনো টিউটোরিয়াল আর AI এখনো eslint.config.js থাকার কথা বলে। টেমপ্লেট বদলায়, তাই নিজের ফোল্ডারে যা আছে সেটিই সত্য। এই কোর্সে আমরা ESLint নিচ্ছি, কারণ এর plugin জগৎ বিশাল আর React Hook-এর নিয়ম পর্ব ১৩-১৪-এ কাজে লাগবে। Oxlint বেছে নেওয়াও একটি যুক্তিসঙ্গত সিদ্ধান্ত।

ভাঙন: ERESOLVE

ESLint বসাতে গিয়েই থামতে হলো:

$ npm install -D eslint @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-config-prettier globals prettier
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: bazarghar-web@0.0.0
npm error Found: typescript@7.0.2
npm error node_modules/typescript
npm error   dev typescript@"~7.0.2" from the root project
npm error
npm error Could not resolve dependency:
npm error peer typescript@">=4.8.4 <6.1.0" from typescript-eslint@8.72.1
npm error node_modules/typescript-eslint
npm error   dev typescript-eslint@"*" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution.

সত্যিকারের run · নভেম্বর ২০২৬

পড়লে পুরোটাই পরিষ্কার। Peer dependency মানে “আমি চলব, যদি আপনার project-এ এই package-এর এই version থাকে।” typescript-eslint চায় TypeScript 6.1-এর নিচে, টেমপ্লেট দিয়েছে 7.0.2. Error মেসেজ নিজেই --force-এর কথা বলে, কিন্তু একই বাক্যে “incorrect (and potentially broken)”-ও বলে। ঠিক পথ হলো দুই দিকের চাহিদা মেলানো:

$ npm install -D typescript@~6.0
$ npm install -D eslint @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-config-prettier globals prettier
$ npm ls --depth=0
+-- typescript-eslint@8.72.1
+-- typescript@6.0.3
$ npm run build
✓ built in 93ms

সত্যিকারের run · সংক্ষেপিত · bundle-এর আকার TypeScript 7-এর run-এর সঙ্গে হুবহু এক

Peer dependency-র এই দ্বন্দ্ব দেখতে ভয়ের, কিন্তু আসলে এটি একটি উপকারী থামা। npm install-এর সময়ই জানিয়ে দিল, নইলে হয়তো lint চালানোর সময় অদ্ভুত error আসত, আর কারণ খুঁজতে অনেক সময় লাগত। টেমপ্লেটের সব কিছু নতুনতম হলেও সেগুলো আপনার যোগ করা টুলের সঙ্গে মিলবে, এমন কোনো নিশ্চয়তা নেই।

আপনি পড়ার সময় এই range বদলে যেতে পারে। সিদ্ধান্তের আগে একবার দেখে নিন: npm view typescript-eslint peerDependencies. শিক্ষাটি version-এর নয়, পদ্ধতির: error পড়ুন, কে কী চায় বের করুন, তারপর মেলান।

নিয়মের ফাইল

ESLint 9 থেকে ডিফল্ট কনফিগ হলো flat config, একটি eslint.config.js ফাইল। ESLint 10.14-এ শুধু পুরোনো .eslintrc.json রেখে চালিয়ে দেখা হয়েছে; সে বলেছে ESLint couldn't find an eslint.config.* file.

import js from '@eslint/js'
import prettier from 'eslint-config-prettier'
import reactHooks from 'eslint-plugin-react-hooks'
import { defineConfig, globalIgnores } from 'eslint/config'
import globals from 'globals'
import tseslint from 'typescript-eslint'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
      reactHooks.configs.flat.recommended,
      prettier, // সবার শেষে: চেহারার নিয়মগুলো বন্ধ করে
    ],
    languageOptions: { globals: globals.browser },
  },
])
{
  "semi": false,
  "singleQuote": true,
  "endOfLine": "auto"
}
npm pkg set scripts.lint="eslint ."
npm pkg set scripts.format="prettier --write src"
npm pkg set scripts.format:check="prettier --check src"
npm uninstall oxlint

আসল বাগ: পুরোনো দাম

“বাজারঘর”-এর একটি component পণ্যের দাম আনে। এটি compile হয়, পাতাও ঠিক দেখায়। কিন্তু ব্যবহারকারী অন্য পণ্যে গেলে দাম আগের পণ্যেরই থেকে যায়। useEffect-এর বিস্তারিত পর্ব ১৩-এ আসবে; এখন শুধু জানুন, শেষের [] মানে কাজটি মাত্র একবার চলবে।

import { useEffect, useState } from 'react'

export function PriceTag({ productId }: { productId: number }) {
  const [price, setPrice] = useState<number | null>(null)
  useEffect(() => {
      fetch(`/api/products/${productId}`)
        .then(res => res.json())
        .then(data => setPrice(data.price))
  }, [])
  let label = price ?? "..."
  return <span>৳ {label}</span>
}
$ npm run lint

src/PriceTag.tsx
   9:6  warning  React Hook useEffect has a missing dependency: 'productId'. Either include it or remove the dependency array  react-hooks/exhaustive-deps
  10:7  error    'label' is never reassigned. Use 'const' instead  prefer-const

✖ 2 problems (1 error, 1 warning)
  1 error and 0 warnings potentially fixable with the `--fix` option.

$ npm run format:check
[warn] src/PriceTag.tsx
[warn] Code style issues found in the above file. Run Prettier with --write to fix.

সত্যিকারের run · ESLint 10.14.0, Prettier 3.9.10

সতর্কবার্তাটি পড়ুন: লাইন ৯, productId তালিকায় নেই। এটিই সেই পুরোনো দামের বাগ। মজার ব্যাপার, আসল বাগটি warning, আর শুধু স্টাইল-ধরনের prefer-const হলো error. তাই শব্দ দেখে গুরুত্ব বিচার করবেন না; warning-ও পড়ুন। দুই লাইন ঠিক করে Prettier চালাই:

  }, [productId])             // আগে: []
  const label = price ?? '...' // আগে: let, আর ডাবল কোট

$ npm run lint                (কোনো আউটপুট নেই, exit code 0)
$ npm run format
src/App.tsx 38ms (unchanged)
src/PriceTag.tsx 8ms
$ npm run format:check
All matched files use Prettier code style!

সত্যিকারের run · সংক্ষেপিত

npm audit — ১২টি moderate, এখন কী করবেন

ESLint যোগ করার পরে install বলল 12 moderate severity vulnerabilities. নতুনরা এখানে ঘাবড়ে যান। npm audit আপনার গাছ মিলিয়ে দেখে জানা সমস্যার তালিকার সঙ্গে। রিপোর্টটি পড়ি:

$ npm audit
minimatch  <11.0.1
Severity: moderate
minimatch has potential denial of service via globparts amplification
fix available via `npm audit fix --force`
Will install eslint@4.0.0, which is a breaking change
…
12 moderate severity vulnerabilities

$ npm audit --omit=dev
found 0 vulnerabilities

সত্যিকারের run · নভেম্বর ২০২৬ · সংক্ষেপিত · পরে এই ফল বদলাতে পারে

লাল লাইনটি দেখুন। --force আপনার ESLint 10 নামিয়ে এনে বসাতে চাইছে 4.0.0, ফলে পুরো নতুন কনফিগই ভাঙবে। আর ১২টি সংখ্যা ১২টি আলাদা বিপদ নয়: একটি উৎস, minimatch, বাকিগুলো তার ওপর নির্ভরশীল বলে গোনা হয়েছে। সব dev টুলে; --omit=dev-এ শূন্য। সিদ্ধান্তের ধারা এমন:

  • সমস্যাটি কোন package-এ? dependencies-এ, না শুধু dev টুলে?
  • আক্রমণের পথ কী? এখানে অবিশ্বস্ত ইনপুট কি সত্যিই সেই কোডে পৌঁছায়?
  • নিরাপদ সমাধান আছে? থাকলে npm audit fix (force ছাড়া), অথবা upstream-এর নতুন version-এর অপেক্ষা।
  • Production dependency-তে high বা critical হলে বিষয়টি জরুরি। তখনই ঠিক করুন।

গভীর আলোচনা আছে Supply chain security পর্বে, আর পর্ব ৫০-এর নিরাপত্তা তালিকায় এটি আবার আসবে।

৭ · .env ফাইল আর VITE_ — দোকানের সাইনবোর্ডে সিন্দুকের চাবি নয়

.env ফাইল কোডের বাইরে config রাখে: API-র ঠিকানা, feature-এর সুইচ। Vite চারটি নাম চেনে: .env, .env.local, .env.[mode] আর .env.[mode].local. নির্দিষ্ট mode-এর ফাইল সাধারণ ফাইলের ওপরে অগ্রাধিকার পায়, আর .local ফাইল version control-এ যায় না। ফাইল বদলালে dev server আবার চালু করতে হয়।

নিয়ম: শুধু VITE_ দিয়ে শুরু হওয়া নাম কোড থেকে পড়া যায়, import.meta.env দিয়ে। অনেকে ভাবেন prefix মানে সুরক্ষা। উল্টো। এই prefix মানে “এটি browser-এ পাঠানো যাবে”। পরীক্ষা করে দেখি (মানগুলো ভুয়া):

VITE_API_URL=http://127.0.0.1:3000
VITE_PAYMENT_SECRET=example-secret-LEAK
DB_PASSWORD=example-db-password
export const apiUrl = import.meta.env.VITE_API_URL
export const leaked = import.meta.env.VITE_PAYMENT_SECRET
export const dbPass = import.meta.env.DB_PASSWORD
console.log(apiUrl, leaked, dbPass, import.meta.env.MODE)
$ npm run build
dist/assets/index-mVoF8jVC.js   222.52 kB │ gzip: 69.34 kB

$ grep -l 'example-secret-LEAK' dist/assets/*.js | wc -l
1
$ grep -l 'example-db-password' dist/assets/*.js | wc -l
0

bundle-এর ভেতরের অংশ:
console.log(`http://127.0.0.1:3000`,`example-secret-LEAK`,void 0,`production`)

সত্যিকারের run · Vite 8.3.5

ফলাফল স্পষ্ট। VITE_PAYMENT_SECRET-এর মান সাধারণ লেখা হিসেবে JavaScript ফাইলে বসে গেছে। যে কেউ পাতা খুলে দেখতে পারবেন। DB_PASSWORD হয়ে গেছে void 0, মানে undefined. আর দেখুন, কোড বদলাতেই ফাইলের নাম GpEN3EET থেকে mVoF8jVC হয়েছে।

Vite-এর docs সরাসরি বলে, VITE_* মানে API key-এর মতো গোপন তথ্য রাখা যাবে না। Frontend-এর সব কিছু প্রকাশ্য ধরে নিন। Payment secret বা database password থাকবে শুধু server-এ। Browser server-কে ডাকবে, server গোপন key ব্যবহার করবে। একটি .env.example ফাইলে শুধু নামগুলো রাখুন, মান ছাড়া; আসল .env কখনো ভাগ করবেন না। পুরো আলোচনা পর্ব ৭৮-এ।

৮ · “বাজারঘর”-এর গঠন — client, server আর workspace

রেস্তোরাঁয় ওয়েটার আর রান্নাঘর আলাদা, কিন্তু একই বাড়িতে। “বাজারঘর”-ও তাই। পুরো কোর্সে আমরা এই গঠন ধরে এগোব: client/-এ React, server/-এ Node API. দুটি আলাদা package.json, কারণ প্রয়োজন আলাদা। নিচে একটি কাঠামো চালিয়ে দেখুন।

cd "$(mktemp -d)"
mkdir -p bazarghar/client/src bazarghar/client/public
mkdir -p bazarghar/server/src bazarghar/shared
cd bazarghar
touch package.json package-lock.json .gitignore
touch client/package.json client/vite.config.ts client/index.html
touch client/.env.example client/.env.local
touch client/src/main.tsx client/src/App.tsx client/public/favicon.svg
touch server/package.json server/.env server/src/index.ts
touch shared/package.json shared/index.ts

echo "--- tree ---"
find . -mindepth 1 | LC_ALL=C sort | sed -e 's|^\./||' -e 's|[^/]*/|   |g'

printf '%s\n' node_modules dist '.env' '*.local' > .gitignore
echo "--- must never be shared ---"
find . -type f \( -name '.env' -o -name '*.local' \) | LC_ALL=C sort
echo "--- files: $(find . -type f | wc -l), package.json files: $(find . -name package.json | wc -l) ---"

শেষ লাইনে আসে --- files: 16, package.json files: 4 ---: root, client, server আর shared, চারটি package.json. “must never be shared” অংশে দুটি ফাইল: ./client/.env.local আর ./server/.env. লক্ষ করুন, package-lock.json আছে একটি, শুধু root-এ। .gitignore ঠিক এই ফাইলগুলো আটকাতেই লেখা। আরও জানতে দেখুন ignore ফাইলের নিয়ম.

Workspace: এক ছাদের নিচে কয়েকটি package

Monorepo মানে একই repository-তে কয়েকটি project. npm-এর workspaces তাদের জোড়া দেয়। আসল সুবিধা shared/: একই কোড client আর server দুই জায়গায় চলে। ছোট একটি সত্যিকারের উদাহরণ:

{
  "name": "bazarghar",
  "private": true,
  "workspaces": ["client", "server", "shared"],
  "scripts": {
    "dev:client": "npm run dev -w client",
    "dev:server": "npm run dev -w server",
    "build": "npm run build --workspaces --if-present"
  }
}
export function formatTaka(amount) {
  return `৳${amount.toLocaleString('en-IN')}`
}
import { createServer } from 'node:http'
import { formatTaka } from '@bazarghar/shared'

const server = createServer((req, res) => {
  res.setHeader('content-type', 'application/json')
  res.end(JSON.stringify({ path: req.url, price: formatTaka(125000) }))
})
server.listen(3000, '127.0.0.1', () => {
  console.log('server: http://127.0.0.1:3000')
})
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [react()],
  server: {
    proxy: { '/api': 'http://127.0.0.1:3000' },
  },
})
$ npm install
$ npm ls --depth=0
bazarghar@ ~/bazarghar
+-- @bazarghar/client@0.0.0 -> .\client
| +-- @bazarghar/shared@0.1.0 deduped -> .\shared
| +-- react@19.3.1
| `-- vite@8.3.5  … আরও
+-- @bazarghar/server@0.1.0 -> .\server
| `-- @bazarghar/shared@0.1.0 deduped -> .\shared
`-- @bazarghar/shared@0.1.0 -> .\shared

lockfile: ১টি · node_modules ফোল্ডার: ১টি (root-এ)

GET http://127.0.0.1:5173/api/products/7 → 200  (client-এর dev port-এ)
{"path":"/api/products/7","price":"৳1,25,000"}

সত্যিকারের run · সংক্ষেপিত · দুই server শুধু 127.0.0.1-এ চলেছে

-> .\shared তীরটি বলছে, npm package কপি করেনি; একটি সংযোগ (symlink) বানিয়েছে। shared/-এ কিছু বদলালে দুই দিকেই সঙ্গে সঙ্গে পাওয়া যায়। আর শেষ লাইনে দাম এসেছে লাখের কমা-সহ, ৳1,25,000, সেটি en-IN locale-এর ফল।

“বাজারঘর”-এর কাজের সময়ের গঠন

Browser → Vite dev server → (/api proxy) → Node API

বাজারঘর-এর client, server, shared গঠন ব্রাউজার client/ server/ shared/ root: bazarghar/ 127.0.0.1:5173 Vite dev server port 5173 React Node API port 3000 গোপন key এখানে /api proxy formatTaka, ভাগ করা কোড একটি lockfile · একটি node_modules import import
ছবি ৫.১ — Dev-এ browser শুধু 5173 চেনে; /api অনুরোধ Vite পাঠিয়ে দেয় 3000-এ, তাই আলাদা CORS সমস্যায় পড়তে হয় না।

দুই ফোল্ডার, না workspace? ভাগ করা কোড না থাকলে দুটি আলাদা ফোল্ডারই যথেষ্ট; root-এ কিছু লাগে না। ভাগ করা type বা validation এলে workspace লাভজনক। পর্ব ৬-এ ভাগ করা type আর পর্ব ২১-এ দুই দিকের validation-এ এটি কাজে লাগবে। এর চেয়ে বড় কাঠামোর জন্য Turborepo বা Nx জাতীয় টুল আছে, এখন দরকার নেই।

pnpm-এর নোট: npm-এর বিকল্প। Package একটি সাধারণ ভাণ্ডারে রেখে সংযোগ দিয়ে জোড়ে, আর ঘোষণা না করা package ব্যবহার করতে দেয় না। একই project-এ pnpm 12.16.1 চালিয়ে পেলাম Packages: +161, lockfile pnpm-lock.yaml. এক project-এ একটিই package manager রাখুন, দুই রকম lockfile মিশাবেন না।

৯ · VS Code, debugging আর Windows-এর সাধারণ সমস্যা

VS Code

দরকারি extension মাত্র কয়েকটি: ESLint, Prettier, আর একটি error এক লাইনে দেখানোর extension (যেমন Error Lens) চাইলে। পরে Prisma বা Tailwind-এর extension যোগ হবে। বেশি extension মানে ধীর editor. দলের জন্য সুপারিশ .vscode/extensions.json-এ রাখা যায়; টেমপ্লেটের .gitignore-ও এই একটি ফাইল ছাড় দিয়েছে।

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }
}

Debugging — console.log-এর পরের ধাপ

Browser-এর কোডের জন্য DevTools (F12). Console-এ error, Network-এ প্রতিটি অনুরোধের status ও সময়, Sources-এ breakpoint. Dev-এ source map-এর কারণে আপনি অনুবাদ করা কোড নয়, নিজের .tsx দেখেন। React-এর জন্য আলাদা React DevTools extension আছে।

Server-এর কোডের জন্য Node-এর inspector. নিচের হিসাবে বাগ আছে: চাল ৮০ টাকা × ২ + ডাল ১২০ টাকা = ২৮০ টাকা হওয়ার কথা, কিন্তু প্রোগ্রাম বলে total 200. এটি একটি আসল debugger session.

1const items = [2  { name: 'চাল', price: 80, qty: 2 },3  { name: 'ডাল', price: 120, qty: 1 },4]5let total = 06for (let i = 0; i < items.length; i++) {7  total += items[i].price8}9console.log('total', total)
Debugger-এ দেখা মান
i
total
items[i].qty
  1. Breakpoint বসল। sb(7) বলে “লাইন ৭-এ থামুন”। প্রোগ্রাম এখনো লুপে ঢোকেনি।
  2. প্রথম থামা। i = 0, total = 0. exec items[i] দেখাল { name: 'চাল', price: 80, qty: 2 }. এই লাইনে যোগ হবে 80 × 2 = 160 হওয়ার কথা।
  3. দ্বিতীয় থামা। i = 1, কিন্তু total মাত্র 80, 160 নয়! অর্থাৎ qty গুণ হয়নি। বাগ ধরা পড়ল। সমাধান: items[i].price * items[i].qty.
  4. শেষ ফল। প্রোগ্রাম ছাপল total 200, মানে 80 + 120. গুণ করলে হতো 160 + 120 = 280.

চারটি কমান্ড দিয়েই শুরু করা যায়:

node inspect cart.js                 # terminal-এই debugger
node --inspect index.js              # চলতে থাকবে, DevTools যুক্ত হবে
node --inspect-brk index.js          # প্রথম লাইনেই থেমে অপেক্ষা
# Chrome-এ chrome://inspect খুলে "inspect" চাপুন
$ node --inspect=127.0.0.1:9229 wait.js
Debugger listening on ws://127.0.0.1:9229/2c711c26-1322-4cbc-b262-7a941959512a
For help, see: https://nodejs.org/en/docs/inspector

সত্যিকারের run · Node 24.15.0

Inspector-কে 127.0.0.1-এর বাইরে খুলবেন না। এই port-এ যুক্ত হতে পারলে যে কেউ আপনার process-এ কোড চালাতে পারবেন। VS Code-এ JavaScript Debug Terminal খুলে কমান্ড চালালে debugger নিজে থেকে যুক্ত হয়।

Windows-এ যেখানে আটকান

আমাদের অনেক পাঠকের ল্যাপটপে Windows. নিচের প্রথম দুটি সমস্যা আমরা এই run-এই পেয়েছি।

ফোল্ডারের নাম: "R&D shop"
$ npm run build
'D' is not recognized as an internal or external command,
operable program or batch file.
Error: Cannot find module '…\typescript\bin\tsc'

একই server দুবার চালালে
Error: listen EADDRINUSE: address already in use 127.0.0.1:3000

Vite নিজে পরের port নেয়, খেয়াল না করলে বিভ্রান্তি হয়
Port 5173 is in use, trying another one...
  ➜  Local:   http://127.0.0.1:5174/

সত্যিকারের run · Windows 10 · &-ওয়ালা ফোল্ডারে npm ci সফল, build ব্যর্থ

যা দেখবেনকারণসমাধান
'D' is not recognizedShell ফোল্ডারের নামের &-কে কমান্ডের অংশ ভাবেনাম বদলান; project রাখুন D:\projects\bazarghar-এর মতো পথে
EADDRINUSEPort আগে থেকে ব্যস্তnetstat -ano | findstr :3000, তারপর taskkill /PID <pid> /F
running scripts is disabledPowerShell-এর execution policy npm.ps1 আটকায়Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, বা Command Prompt
'node' is not recognizedPATH-এ Node নেই, বা terminal পুরোনোTerminal আবার খুলুন; না হলে installer-এর PATH অপশন দেখুন
EPERM বা EBUSYফাইল অন্য প্রোগ্রাম ধরে আছে: চলতি dev server, antivirus, OneDriveServer বন্ধ করুন, project OneDrive-এর বাইরে রাখুন, Administrator হিসেবে চালাবেন না
অস্বাভাবিক লম্বা পথের errorগভীর node_modules, পুরোনো path সীমাছোট পথে project রাখুন

শেষ চারটি সারি পরিচিত সমস্যা, এই run-এ দেখা নয়। স্পেস-ওয়ালা ফোল্ডার আর বাংলা নামের ফোল্ডার (বাজার ঘর) দুটোতেই build সফল হয়েছে, তবে সেটি একটি মাত্র পরীক্ষা। সবার জন্য নিরাপদ অভ্যাস হলো ছোট, ইংরেজি, চিহ্ন ছাড়া পথ। লাইন শেষের অক্ষরের (CRLF ও LF) কারণে Prettier সব ফাইলে অভিযোগ করলে "endOfLine": "auto" কাজে লাগে, যেটি আমরা ওপরে রেখেছি।

আরও গভীরে: Vite 8 (মার্চ ২০২৬) থেকে dev আর build দুই জায়গায় একই Rust-ভিত্তিক bundler Rolldown কাজ করে; আগে esbuild আর Rollup দুটি আলাদা টুল ছিল। TypeScript 7-এর নতুন compiler আর ESLint plugin-এর দূরত্ব এই পর্বের ERESOLVE-এর মতো ঘটনা তৈরি করে: টুলের গোড়া বদলালে তার ওপর দাঁড়ানো জগৎ একসঙ্গে এগোয় না। আর npm-এর flat node_modules কাঠামো “phantom dependency” তৈরি করতে পারে, মানে ঘোষণা না করা package-ও import করা যায়; pnpm-এর কড়াকড়ি এটি ঠেকাতেই।

পরীক্ষা ও ইন্টারভিউতে:

  • npm install আর npm ci-এর পার্থক্য? প্রথমটি lockfile বদলাতে পারে; দ্বিতীয়টি lockfile হুবহু মানে, অমিলে থামে, node_modules মুছে শুরু করে।
  • ^1.2.3 আর ~1.2.3? >=1.2.3 <2.0.0 বনাম >=1.2.3 <1.3.0.
  • Lockfile commit করেন কেন? সবাই ও CI যেন একই গাছ পায়।
  • VITE_ prefix-এ secret রাখা যায়? না, মান bundle-এ ঢুকে সবার কাছে যায়।
  • Linter ও formatter-এর পার্থক্য? Linter সন্দেহজনক যুক্তি ধরে, formatter শুধু চেহারা বদলায়।

১০ · AI-এর যুগে কাজের পরিবেশ

সেটআপের কাজে AI সবচেয়ে বেশি ভুল করে, কারণ এখানে সবকিছু দ্রুত বদলায়। এই পর্বেই দেখলেন: টেমপ্লেটে ESLint নেই, TypeScript-এর major version-এ ভাঙন, পুরোনো config ফাইল চলে না। AI-এর শেখা তথ্য অনেক সময় এর চেয়ে পুরোনো। AI-কে আপনার ফোল্ডারের সত্য জানান, স্মৃতির ওপর ছেড়ে দেবেন না।

AI যা বলতে পারেবাস্তবতাযাচাই
npx create-react-appReact দল ২০২৫ সালে নতুন অ্যাপের জন্য এটি deprecated করেছেreact.dev দেখুন
.eslintrc.json বানানESLint 10-এ eslint.config.* লাগেনিজে চালান
process.env.REACT_APP_XVite-এ import.meta.env.VITE_XVite docs
“--force দিন” বা “--legacy-peer-deps”দ্বন্দ্ব লুকায়, সমাধান করে নাnpm view … peerDependencies
“npm audit fix --force চালান”এখানে ESLint 4.0.0 বসাতে চেয়েছিলআগে রিপোর্ট পড়ুন
অচেনা package-এর নামনাম বানানো হতে পারে, বা সেই নামে ক্ষতিকর package থাকতে পারেnpm view <name>, repository, প্রকাশের তারিখ
VITE_-তে API key রাখুনBundle-এ ফাঁস হয়dist/-এ grep করুন
Error লুকাতে eslint-disableবাগ থেকেই যায়Diff পড়ুন

AI-কে সেটআপ-সমস্যা দেখানোর সময় নিচের কাঠামো ব্যবহার করুন। শেষ দুটি শর্ত সবচেয়ে কাজের।

আমার পরিবেশ: Windows 10, Node 24.15.0, npm 11.12.1. আমার package.json: [এখানে পেস্ট করুন] আমি এই কমান্ড চালিয়েছি: [কমান্ড] পুরো error: [error, কোনো password বা key থাকলে আগে মুছে দিন] ১. সহজ বাংলায় বলো কোন package কোন version চাইছে, আর দ্বন্দ্ব কোথায়। ২. কোন কমান্ড দিয়ে আমি তোমার দাবি নিজে যাচাই করতে পারি, সেটি দাও। ৩. --force, --legacy-peer-deps বা eslint-disable ছাড়া সমাধান দাও। অন্য পথ না থাকলে ঝুঁকি বলো। ৪. কোনো নতুন package প্রস্তাব করলে কেন দরকার বলো, আর সেটি না নিলে কী হতো বলো।

AI-এর সেটআপ হাতে পেলে — যাচাইয়ের চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১Lockfile না থাকলে কী এমন ক্ষতি হতো? এটি কেন একসময় ছিল না, আর এখন কেন অপরিহার্য?

Semver একটি প্রতিশ্রুতি, নিশ্চয়তা নয়। নিয়মটি সাধারণভাবে Tom Preston-Werner-এর লেখা Semantic Versioning নথির সঙ্গে যুক্ত। এতে বলা হয়, MINOR আর PATCH বদলে পুরোনো ব্যবহার ভাঙবে না। কিন্তু একজন মানুষ নম্বরটি বসান, আর মানুষ ভুল করেন। একটি “ছোট” patch-ও কারও বিশেষ ব্যবহার ভেঙে দিতে পারে।

আগের দিনের npm-এ শুধু range থাকত। আজ যে গাছ বসল, কাল সেটি আলাদা হতে পারত। ২০১৬ সালে Yarn এসে lockfile-কে সামনে আনে, আর ২০১৭ সালে npm 5-এ package-lock.json ডিফল্ট হয়। একই বছরগুলোতে আরও একটি শিক্ষা আসে। ২০১৬ সালে left-pad নামের এগারো লাইনের মতো ছোট একটি package npm থেকে সরিয়ে নেওয়ায় বহু project-এর build ভেঙে পড়ে, পরে npm সেটি ফিরিয়ে আনে। বোঝা গেল, আপনার সরাসরি ২০টি dependency-র নিচে শত শত অচেনা package থাকে, যাদের ওপর আপনার নিয়ন্ত্রণ নেই।

Lockfile এখানে তিনটি কাজ করে। প্রথমত, পুনরুৎপাদন: আজকের build ছয় মাস পরেও একই গাছ পায়। দ্বিতীয়ত, integrity hash দিয়ে নিশ্চিত করে যে ফাইলটি লেখা হওয়ার সময়ের ফাইলই। তৃতীয়ত, diff-এ দেখা যায় কোন গভীর package বদলাল, ফলে code review সম্ভব হয়।

তবে lockfile চিরকাল পুরোনো রাখাও ঝুঁকি, কারণ নিরাপত্তা সংশোধন আসে না। তাই নিয়মিত npm update, test আর সচেতন আপডেট দরকার। আর আপনি যদি অন্যের জন্য library প্রকাশ করেন, মনে রাখুন আপনার lockfile ব্যবহারকারীর কাছে যায় না; তাঁর গাছ ঠিক হয় তাঁর project-এ। তবু নিজের উন্নয়ন ও CI-এর জন্য সেখানেও lockfile রাখা ভালো।

মূল উপলব্ধি: Range বলে আপনি কী মেনে নিতে রাজি, lockfile বলে আসলে কী ঘটেছে। নির্ভরযোগ্য সফটওয়্যারে দুটিই লাগে।

প্র ০২npm install করলে আপনি আসলে কাকে বিশ্বাস করছেন? npm audit শূন্য দেখালেই কি নিরাপদ?

npm install মানে অপরিচিত মানুষের কোড আপনার কম্পিউটারে নামানো, এবং কিছু ক্ষেত্রে সঙ্গে সঙ্গে চালানো। Package-এ postinstall script থাকলে সেটি install-এর সময়ই চলে, অ্যাপ চালু করার আগেই। সে আপনার ফাইল আর .env পড়তে পারে।

ইতিহাসে কয়েকটি ঘটনা এটি দেখিয়েছে। ২০১৮ সালে event-stream package-এর দায়িত্ব একজন অপরিচিত ব্যক্তির হাতে যায়, আর একটি dependency-তে cryptocurrency wallet লক্ষ্য করে লুকানো কোড ঢোকে। ২০২১ সালে ua-parser-js-এর প্রকাশ-অ্যাকাউন্ট হাতছাড়া হয়ে ক্ষতিকর version ছড়ায়। ২০২২ সালে colors আর faker-এর রক্ষণকারী নিজেই ইচ্ছা করে সেগুলো নষ্ট করেন। ২০২৫ সালে phishing-এর মাধ্যমে জনপ্রিয় কিছু package-এ আক্রমণের খবর আসে। প্রতিটি ঘটনার খুঁটিনাটি মূল প্রতিবেদনে দেখে নেওয়াই ভালো।

এখন audit-এর সীমা বুঝুন। npm audit জানা ও রিপোর্ট হওয়া সমস্যা মেলায়। নতুন, এখনো অজানা ক্ষতিকর কোড সে ধরবে না। উল্টো দিকে, এই পর্বের ১২টি moderate সতর্কতার সব একটি উৎস থেকে, আর সব dev টুলে। তাই শূন্য মানে সম্পূর্ণ নিরাপদ নয়, আর ১২ মানে আগুন লেগেছে তাও নয়।

বাস্তব অভ্যাস: কম dependency রাখা; নতুন package-এর repository আর প্রকাশের ইতিহাস দেখা; CI-তে npm ci; দরকারে --ignore-scripts; npm account-এ দুই ধাপের যাচাই। এক লাইনের কাজের জন্য একটি package নেওয়ার আগে ভাবুন, সেটি নিজে লেখা কি সস্তা নয়? আর নামের বানান ভালো করে মিলিয়ে নিন, কারণ জনপ্রিয় package-এর কাছাকাছি নামে ক্ষতিকর package রাখার কৌশলও প্রচলিত। মনে রাখবেন, ফাঁসের সন্দেহ হলে শুধু package সরালেই হয় না; যে key সেই কম্পিউটারে ছিল, সেগুলোও বদলাতে হয়।

মূল উপলব্ধি: প্রতিটি dependency একটি বিশ্বাসের সিদ্ধান্ত। Audit একটি সহায়ক সংকেত, নিরাপত্তার সনদ নয়।

প্র ০৩Vite-এর dev server ১৭২ ms-এ চালু হলো, পুরোনো বড় project-এ কেন মিনিট লাগত? তাহলে build কি পুরোপুরি বাদ দেওয়া যায়?

পুরোনো পথে bundler আগে পুরো অ্যাপ পড়ে একটি ফাইলে জুড়ত, তারপর server দেখাত। অ্যাপ বড় হলে অপেক্ষাও বাড়ত। একটি ফাইল বদলালেও অনেকটা কাজ আবার করতে হতো। Webpack-এর মতো টুল এই সমস্যাগুলো সামলেছে বহু বছর ধরে, কারণ তখন browser-এ native module ভালোভাবে চলত না।

Browser-এ ES module ব্যাপকভাবে চালু হওয়ার পরে একটি ভিন্ন চিন্তা সম্ভব হলো। Evan You ২০২০ সালে Vite শুরু করেন। মূল ধারণা: dev-এ জোড়া দেওয়ার কাজ browser করুক। আমরা অংশ ৩-এ দেখেছি, browser /src/main.tsx চাইলে Vite শুধু সেটিই অনুবাদ করে। তাই চালু হতে সময় অ্যাপের আকারের ওপর ততটা নির্ভর করে না। node_modules-এর ভারী package আগে থেকে একবার প্রস্তুত করা হয়, যা আউটপুটে .vite/deps হিসেবে দেখেছেন।

তবে build বাদ দেওয়া যায় না। আসল ব্যবহারকারীর কাছে শত শত আলাদা ফাইল পাঠালে শত শত অনুরোধ হয়, যা ধীর নেটওয়ার্কে কষ্টদায়ক। Build ফাইল জোড়ে, অব্যবহৃত কোড ফেলে, ছোট করে, আর hash-ওয়ালা নাম দেয়। এই পর্বে ২০টি module মিলে একটি JavaScript ফাইল হয়েছে।

একসময় Vite-এর dev আর build-এ দুটি আলাদা টুল ছিল, esbuild আর Rollup. এতে কখনো dev-এ এক আচরণ, build-এ আরেক আচরণ দেখা যেত। Vite 8 (২০২৬)-এ দুই জায়গায় Rolldown এসেছে। তবু dev আর build-এর পথ পুরোপুরি এক নয়, তাই preview চালিয়ে দেখা এখনো জরুরি। ১৭২ ms এবং ১০১ ms এই ছোট project-এর একটি স্থানীয় পরিমাপ, সাধারণ নিয়ম নয়।

মূল উপলব্ধি: দুই মোডের লক্ষ্য আলাদা। Dev বাঁচায় ডেভেলপারের সময়, build বাঁচায় ব্যবহারকারীর সময়।

প্র ০৪Monorepo নাকি আলাদা repository? ছোট দলের জন্য কোনটি ঠিক?

এই বিতর্কে সবার জন্য একটি উত্তর নেই, আর অভিজ্ঞ মানুষরাও ভিন্ন মত রাখেন।

এক repository-র পক্ষে: client আর server-এর পরিবর্তন একটি commit-এ যায়। API-তে নতুন field যোগ আর UI-তে তার ব্যবহার একসঙ্গে review হয়। ভাগ করা type আর validation সহজ। একই lint, test আর lockfile. “বাজারঘর”-এর মতো ২–৫ জনের দলে এটি খুব কাজের। formatTaka-র উদাহরণে দেখেছেন, একটি ফাংশন দুই দিকে একবারই লিখতে হয়েছে।

এক repository-র দাম: CI ঠিকমতো না সাজালে ছোট পরিবর্তনেও সব কিছু চলে। সব package-এ একই version-এর চাপ পড়ে; এই পর্বে একটি lockfile ছিল, ফলে একটি dependency-র দ্বন্দ্ব পুরো project-কে থামাতে পারে। দল খুব বড় হলে ডেভেলপমেন্ট টুলেও বিনিয়োগ লাগে।

আলাদা repository-র পক্ষে: মালিকানা পরিষ্কার, deploy স্বাধীন, প্রবেশাধিকার আলাদা। দুটি ভিন্ন দল বা বাইরের ঠিকাদার কাজ করলে এটি মানায়। দাম হলো, ভাগ করা কোড আলাদা package হিসেবে প্রকাশ করতে হয়, আর API-র সমন্বিত পরিবর্তন কয়েকটি ধাপে ভাগ হয়।

একটি জরুরি পার্থক্য মনে রাখুন: monorepo আর monolith এক জিনিস নয়। পর্ব ৪-এ দেখেছেন, monolith হলো deploy-এর একক। আপনি এক repository থেকে আলাদা service deploy করতে পারেন, আবার আলাদা repository-র কোড মিলিয়ে একটি অ্যাপও বানাতে পারেন।

শুরুর সিদ্ধান্ত: ভাগ করা কোড না থাকলে সাধারণ দুই ফোল্ডার। ভাগ করা কোড এলে npm workspaces. এক ডজন package আর ধীর CI হলে তবেই Turborepo বা Nx জাতীয় টুল। সমস্যা আসার আগে জটিলতা কিনবেন না।

মূল উপলব্ধি: Repository-র সীমা নির্ধারণ করে কে একসঙ্গে পরিবর্তন করবে। তাই সিদ্ধান্তটি প্রযুক্তির যতটা, দলের গঠনেরও ততটা।

প্র ০৫টেমপ্লেটে ESLint-এর জায়গায় Oxlint, TypeScript-এ নতুন compiler — এত দ্রুত বদলানো টুলের জগতে কীভাবে সিদ্ধান্ত নেবেন?

JavaScript টুলের ইতিহাস ঘন ঘন প্রজন্ম বদলের ইতিহাস। Nicholas Zakas ২০১৩ সালে ESLint শুরু করেন, যার বড় শক্তি ছিল plugin দিয়ে নিয়ম যোগ করা। TypeScript-এর জন্য একসময় আলাদা TSLint ছিল, যা পরে ESLint-এর পক্ষে বন্ধ হয়। ২০১৭ সালের দিকে James Long-এর Prettier আরেকটি ধারণা জনপ্রিয় করে: চেহারা নিয়ে দলের তর্ক বন্ধ করতে একটি মতপ্রবণ টুল কোড নতুন করে ছাপিয়ে দেবে। বেশি অপশন না রাখাই ছিল এর নকশা।

গত কয়েক বছরে একটি নতুন ধারা এসেছে: JavaScript-এ লেখা টুলগুলো Rust বা Go-এর মতো ভাষায় নতুন করে লেখা। Rolldown, Oxlint, Biome, আর TypeScript 7-এর নতুন compiler এই ধারার উদাহরণ। সুবিধা গতি। দাম হলো পুরোনো plugin জগতের সঙ্গে অমিল, যা আমরা ERESOLVE-এ সরাসরি দেখেছি: TypeScript 7 প্রকাশিত, কিন্তু typescript-eslint-এর ঘোষিত range তখনো 6.1-এর নিচে।

তাহলে সিদ্ধান্ত কীভাবে নেবেন? কয়েকটি প্রশ্ন করুন। আমার যে নিয়ম দরকার, সেটি নতুন টুলে আছে কি? দলের বাকিরা এটি চালাতে পারবেন কি? ভুল প্রমাণ হলে ফিরতে কত খরচ? আসল ধীরগতি কি lint-এই, নাকি অন্য কোথাও? ছোট project-এ lint এক সেকেন্ডে শেষ হলে গতির লাভ সামান্য।

আবার টুল বদলের ভয়ে একেবারে থেমে থাকাও ভুল। পুরোনো টুল নিরাপত্তা আপডেট হারায়, যেমন Node-এর EOL version. একটি মাঝের পথ: LTS ও স্থিতিশীল version নিন, তবে একদিনের নতুন major-এ সঙ্গে সঙ্গে ঝাঁপ দেবেন না, নতুন project-এ ছোট পরীক্ষা করুন। এই কোর্সে আমরা TypeScript 6.0-এ থাকলাম ঠিক এই কারণে। ESLint-এর পথ খুললে আবার পরীক্ষা করে দেখা হবে।

মূল উপলব্ধি: নির্দিষ্ট টুলের নাম পুরোনো হবে। থেকে যাবে ধারণা: linter, formatter, lockfile, build. ধারণা বুঝলে নতুন টুল শিখতে কয়েক ঘণ্টা লাগে, মাস নয়।

অনুশীলন

প্রথমে নিজে চেষ্টা করুন। প্রথমটি কমান্ডের, দ্বিতীয়টি হিসাবের।

  1. নিজের বাজারঘর: ছোট ইংরেজি পথের একটি ফোল্ডারে Vite-এর React TypeScript project বানান। npm run build চালিয়ে JavaScript ফাইলের আকার লিখুন। তারপর src/App.tsx-এর লেখা একটু বদলে আবার build করুন। কোন দুটি জিনিস বদলাল?

    আপনার সংখ্যা আপনার version-এর ওপর নির্ভর করবে, তাই এই পাতার সঙ্গে না মিললেও চিন্তা নেই। বদলাবে ফাইলের আকার (সামান্য), আর index-….js-এর hash. CSS না বদলালে CSS ফাইলের নাম একই থাকার কথা। Browser তাই শুধু নতুন JavaScript নামাবে, CSS-এর cache কাজে লাগবে। Hash-ভিত্তিক নামের উপকার এখানেই।

  2. Bundle-এর হিসাব: একটি build-এ JavaScript 400 kB, gzip-এ 120 kB. (ক) সংকোচনের অনুপাত আর সাশ্রয় শতকরা কত? (খ) 2 Mbps গতিতে (অনুমান) gzip করা ফাইল আসতে কত সময়? (গ) 10 Mbps গতিতে? kB = 1000 byte ধরুন, অন্যান্য সময় বাদ দিন।

    (ক) 120 ÷ 400 = 0.30; সাশ্রয় ৭০%.

    (খ) 120 kB = 120 × 8 = 960 kilobit = 0.96 Mbit. সময় = 0.96 ÷ 2 = 0.48 সেকেন্ড.

    (গ) 0.96 ÷ 10 = 0.096 সেকেন্ড.

    গতি ৫ গুণ হলে এই সময় ৫ ভাগের ১ হয়। কিন্তু ফোনে parse আর চালানোর সময় ইন্টারনেট বাড়ালেও কমে না, কারণ সেখানে কাজ করে 400 kB-এর পুরো কোড।

  3. ফলাফল অনুমান করুন: package.json-এ "ms": "^2.0.0", lockfile-এ ms@2.0.0, আর registry-র নতুনতম 2.x হলো 2.1.3. পরপর (১) npm install, (২) npm ci, (৩) npm update চালানো হলো। প্রতিটির পরে node_modules-এ কোন version, আর শেষে package.json-এ কী লেখা থাকবে?

    এটি সত্যিকারের run-এ যাচাই করা হয়েছে (npm 11.12.1).

    • (১) 2.0.0: lockfile-এর version range-এর সঙ্গে মেলে, তাই বহাল। আউটপুট ছিল up to date.
    • (২) 2.0.0: lockfile হুবহু মানে।
    • (৩) 2.1.3: range-এর ভেতরে নতুনতম, আর lockfile-ও আপডেট হয়।

    শেষে package.json-এ তখনো "ms": "^2.0.0". এই run-এ npm update শুধু lockfile আর গাছ বদলেছে।

  4. নকশা সমালোচনা: একজন ফ্রিল্যান্সারের project-এ দেখা গেল: lockfile-কে .gitignore-এ রাখা; client/.env-এ VITE_DB_PASSWORD; dependencies-এ eslint আর vite; server-এ deploy-এর সময় npm install --force; Node 18; project আছে C:\Users\Rafi\OneDrive\Desktop\R&D\-এ। অন্তত পাঁচটি সমস্যা ও সমাধান লিখুন।
    • Lockfile ignore: সবার গাছ আলাদা হবে। Lockfile commit করুন।
    • VITE_DB_PASSWORD: ব্যবহার হলে password bundle-এ ফাঁস হবে, আর database-এর password frontend-এ থাকারই কথা নয়। Server-এ সরান, আর password বদলে ফেলুন, কারণ এটি ইতিমধ্যে ফাঁস ধরে নেওয়া উচিত।
    • eslint, vite ভুল জায়গায়: devDependencies-এ নিন।
    • npm install --force: অপ্রত্যাশিত গাছ, দ্বন্দ্ব লুকানো। Deploy-তে npm ci ব্যবহার করুন, আর দ্বন্দ্বের আসল সমাধান করুন।
    • Node 18: EOL, আর বর্তমান Vite-এর চাহিদা পূরণ করে না। LTS নিন, .nvmrc রাখুন।
    • পথ: & script ভাঙে, OneDrive sync node_modules-এ ঝামেলা করে। ছোট পথে সরান।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমনতুন Vite project-কে তৈরি থেকে যাচাই পর্যন্ত সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 🏗️ npm create vite@latest দিয়ে কাঠামো বানানো
  2. 📦 npm install দিয়ে package আনা
  3. ⚡ npm run dev চালিয়ে কাজ করা
  4. 🔍 npm run lint দিয়ে ভুল খোঁজা
  5. 🧱 npm run build দিয়ে dist/ বানানো
  6. 👀 npm run preview দিয়ে তৈরি ফাইল দেখা

package.json-এ range ^1.4.2. নিচের কোন version এই range-এ পড়ে?

  • 1.4.1
  • 1.9.0
  • 2.0.0
  • 0.9.9

CI-তে npm ci চালাতেই EUSAGE error এলো: package.json আর lockfile মিলছে না। সঠিক কাজ কোনটি?

  • CI-তে npm install বসিয়ে দেওয়া
  • Lockfile মুছে আবার push করা
  • নিজের কম্পিউটারে npm install চালিয়ে আপডেট হওয়া lockfile যাচাই করে commit করা
  • --legacy-peer-deps যোগ করা

Vite project-এর .env-এ আছে VITE_KEY=abc আর DB_PASSWORD=xyz. দুটিই client কোডে import.meta.env দিয়ে পড়া হলো। Production build-এর পরে কী হবে?

  • abc bundle-এ ঢুকবে, DB_PASSWORD client-এ undefined হবে
  • দুটিই bundle-এ ঢুকবে
  • দুটিই এনক্রিপ্ট হয়ে bundle-এ যাবে
  • কোনোটিই পাওয়া যাবে না

একটি build-এ JavaScript 300 kB, gzip-এ 90 kB. 3 Mbps গতি ধরে (অন্য সময় বাদ, kB = 1000 byte) gzip করা ফাইল আসতে কত সময়?

  • 30 সেকেন্ড
  • 0.8 সেকেন্ড
  • 0.03 সেকেন্ড
  • 0.24 সেকেন্ড

npm install করতে গিয়ে ERESOLVE এলো: একটি plugin peer হিসেবে typescript@<6.1.0 চায়, কিন্তু project-এ 7.0.2. প্রথম ভালো পদক্ষেপ কোনটি?

  • --force দিয়ে চালানো
  • কে কী চায় পড়ে compatible version বেছে নেওয়া
  • node_modules মুছে আবার চেষ্টা করা
  • Node আবার install করা

Windows-এ R&D shop ফোল্ডারে npm run build করলে আসে 'D' is not recognized as an internal or external command. কারণ কী?

  • Node install করা নেই
  • Port ব্যস্ত
  • ফোল্ডারের নামের & চিহ্নকে shell কমান্ড আলাদা করার চিহ্ন ভেবেছে
  • Lockfile নেই

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. Node-এর LTS নিন; dev, build, preview তিনটির কাজ আলাদা।
  2. package.json হলো ইচ্ছা, lockfile হলো বাস্তব; lockfile commit করুন, CI-তে npm ci.
  3. ^ MINOR পর্যন্ত, ~ PATCH পর্যন্ত নেয়; 0.x-এ ^ আরও সাবধানী।
  4. VITE_ মানে প্রকাশ্য। Secret শুধু server-এ; dist/-এ grep করে যাচাই করুন।
  5. Error আগে পড়ুন। --force আর npm audit fix --force শেষ উপায়, প্রথম নয়।

পরের পর্বে: পরিবেশ তৈরি। পর্ব ০৬-এ TypeScript-কে কাজে লাগাব: type, interface, generic, আর shared/ দিয়ে client ও server-এ ভাগ করা type.

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান