এই পর্বে যা শিখবেন
- 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 থেকে নেওয়া, শুধু লম্বা অংশ ছাঁটা।
- create
create-viteকাঠামো - install
node_modulespackage - dev
:5173server - browser
GET /index.html
create-vite v9.3.3 ◇ Scaffolding project in ~/bazarghar-web... └ Done. Now run: cd bazarghar-web npm install npm run dev
added 28 packages, and audited 29 packages in 32s 9 packages are looking for funding found 0 vulnerabilities
VITE v8.3.5 ready in 172 ms ➜ Local: http://127.0.0.1:5173/
<script type="module" src="/@vite/client"></script>
…
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
// ফাইল .tsx, কিন্তু উত্তর আসে JavaScript হয়ে import "/src/index.css"; import App from "/src/App.tsx"; // react আসে আগে থেকে প্রস্তুত করা ফাইল থেকে /node_modules/.vite/deps/react.js
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
- ধাপ ১ — কাঠামো।
npm create vite@latestআসলেcreate-vitepackage নামিয়ে চালায়। এটি টেমপ্লেট থেকে ফাইল কপি করে। এখনো কোনোnode_modulesনেই, React-ও বসেনি। - ধাপ ২ — package আনা।
npm installনতুন project-এ ২৮টি package বসাল (audit গুনল ২৯, কারণ project নিজেও একটি)। সঙ্গে তৈরি হলোpackage-lock.json. - ধাপ ৩ — dev server.
npm run dev১৭২ ms-এ তৈরি। এত দ্রুত, কারণ dev server আগে পুরো অ্যাপ জোড়া দেয় না; চাহিদা অনুযায়ী ফাইল তৈরি করে। - ধাপ ৪ — প্রথম অনুরোধ। Browser
/চাইল। Viteindex.html-এ নিজের দুটি script ঢুকিয়ে দিল। এগুলো কোড বদলের খবর আনে। পাতায় এখনো শুধু খালিdiv#rootআছে। - ধাপ ৫ — ফাইল অনুবাদ। Browser
main.tsxচাইলে Vite সেটি JavaScript-এ অনুবাদ করে পাঠায়। ভেতরের প্রতিটিimportআবার একটি করে অনুরোধ হয়। Browser নিজেই এখানে module জোড়া দিচ্ছে। - ধাপ ৬ — প্রথম পাতা।
createRootখালিdiv#root-এর ভেতরে React-এর UI বসাল। পর্দায় টেমপ্লেটের পাতা এলো। এটিই পর্ব ৩-এর CSR: HTML প্রায় খালি, UI বানায় browser-এর JavaScript.
কোন ফাইলের কী কাজ
টেমপ্লেট থেকে ১৮টি ফাইল এসেছে। মুখস্থ নয়, শুধু জেনে রাখুন কোন সমস্যায় কোথায় যাবেন।
| ফাইল | কাজ | কখন খুলবেন |
|---|---|---|
index.html | অ্যাপের প্রবেশপথ; Vite এখান থেকেই শুরু করে | Title, meta, font বদলাতে |
src/main.tsx | React-কে #root-এ বসায় | Provider বা router জুড়তে |
src/App.tsx | প্রথম component | এখান থেকেই কাজ শুরু |
src/index.css, App.css | Style | সাজসজ্জায় |
src/assets/ | কোড থেকে import করা ছবি; build-এ নাম বদলায় | Component-এর ছবিতে |
public/ | যেমন আছে তেমন কপি হয় | favicon, robots.txt-এ |
vite.config.ts | Vite-এর নিয়ম ও plugin | Proxy, alias যোগ করতে |
tsconfig*.json | TypeScript-এর নিয়ম; app আর node অংশ আলাদা | পর্ব ৬-এ |
.oxlintrc.json | Lint-এর নিয়ম (অংশ ৬ দেখুন) | Lint বদলাতে |
.gitignore | কী version control-এ যাবে না: node_modules, dist, *.local | নতুন গোপন ফাইল এলে |
package.json | Project-এর পরিচয়, script আর dependency | প্রায়ই |
৪ · dev, build আর preview — তিন মোড, বাস্তব সংখ্যা
চায়ের দোকানে চা বানানোর সময় আর পার্সেল বাঁধার সময় কাজের ধরন আলাদা। সফটওয়্যারেও তাই।
| কমান্ড | কী করে | ভুল ধারণা |
|---|---|---|
npm run dev | ফাইল চাহিদামতো অনুবাদ; HMR দিয়ে save করলেই পাতা বদলায় | এটি production server নয় |
npm run build | tsc -b দিয়ে type যাচাই, তারপর vite build | Build শেষ মানে বাগ নেই, তা নয় |
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নিজে থেকেই পথে যুক্ত হয়, তাইviteglobal ভাবে বসাতে হয় না।
dependencies বনাম devDependencies: প্রথমটি অ্যাপ চলতে লাগে, দ্বিতীয়টি শুধু বানাতে বা পরীক্ষা করতে। Server-এ এর সরাসরি ফল আছে: npm ci --omit=dev ESLint-এর মতো টুল বাদ দিয়ে হালকা install করে। Frontend-এ পার্থক্যটি কিছুটা নিয়মের ব্যাপার, কারণ bundle-এ শুধু সেই কোডই ঢোকে যা import হয়েছে।
npm install ভেতরে কী করে
- পড়া
package.jsonফর্দ - গাছ
ideal treeহিসাব - আনা
tarballযাচাই - বসানো
node_modulesগুদাম - লেখা
lockfileমেমো
package.json react: ^19.3.1
package-lock.json নেই (নতুন project)
react ^19.3.1 → চলবে >=19.3.1 <20.0.0
নতুনতম যা মেলে → 19.3.1
react-এর নিজের dependency-ও একইভাবে…
resolved .../react/-/react-19.3.1.tgz integrity sha512-QNhWdt7nrgVWWQG58… ফাইলের hash মিললে তবেই গ্রহণ
node_modules/react/ node_modules/vite/ node_modules/.bin/vite ← npm run dev এটিই খোঁজে added 28 packages
"node_modules/react": {
"version": "19.3.1",
"resolved": "https://registry.npmjs.org/…",
"integrity": "sha512-…"
}
found 0 vulnerabilities
- ধাপ ১ — ফর্দ পড়া। npm
package.jsonপড়ে। Lockfile থাকলে সেটিও পড়ে; মেমো আছে মানে বাজারে নতুন করে দরদাম লাগে না। - ধাপ ২ — গাছ বানানো। প্রতিটি package-এর নিজের dependency আছে। npm পুরো গাছের হিসাব করে: কোন range-এ কোন version. আগে থেকে lockfile থাকলে সেখানকার version-ই বহাল থাকে, যদি range-এর সঙ্গে মেলে।
- ধাপ ৩ — আনা ও যাচাই। প্রতিটি package একটি সংকুচিত ফাইল (tarball). npm আগে নিজের cache দেখে, না পেলে registry থেকে আনে। Integrity hash না মিললে বাতিল। ডাকঘরে সিল ভাঙা পার্সেল ফিরিয়ে দেওয়ার মতো।
- ধাপ ৪ — গুদামে সাজানো। ফাইল
node_modules-এ খোলা হয়, যতটা সম্ভব একই স্তরে। চালানো যায় এমন টুলের সংযোগ বসে.bin-এ। Package-এ install script থাকলে সেটিও এখানে চলে, তাই এটি নিরাপত্তারও ধাপ। - ধাপ ৫ — মেমো লেখা। ফলাফল
package-lock.json-এ ওঠে, শেষে audit-এর সারাংশ দেখায়। এই নতুন project-এ: ২৮টি package, ০টি vulnerability.
Semver range — কোন version চলবে
Semver মানে MAJOR.MINOR.PATCH নিয়মের নম্বর। Range-এর সিদ্ধান্তটি ধাপে ধাপে দেখুন।
| প্রার্থী version | |
| Caret range | |
| Caret-এর রায় | |
| Tilde range | |
| Tilde-এর রায় |
- 19.3.0: নিচের সীমার নিচে।
^আর~দুটিই বাতিল করে, কারণ দুটিরই শুরু 19.3.1 থেকে। - 19.3.1: হুবহু নিচের সীমা। দুটিই নেয়।
- 19.3.9: শুধু PATCH বাড়ল, মানে বাগ সংশোধন। দুটিই নেয়।
- 19.4.0: MINOR বাড়ল।
^নেয় (উপরের সীমা 20.0.0), কিন্তু~নেয় না (উপরের সীমা 19.4.0, যা বাইরে)। মূল পার্থক্য এখানেই। - 20.0.0: MAJOR বদল মানে ভেঙে যাওয়ার মতো পরিবর্তন হতে পারে। কোনো range নেয় না। এটি আপনাকে নিজে বেছে নিতে হয়।
- 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 নামিয়ে শুরু, বা CI | npm 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-passwordexport 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
/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)
| i | |
| total | |
| items[i].qty |
- Breakpoint বসল।
sb(7)বলে “লাইন ৭-এ থামুন”। প্রোগ্রাম এখনো লুপে ঢোকেনি। - প্রথম থামা।
i= 0,total= 0.exec items[i]দেখাল{ name: 'চাল', price: 80, qty: 2 }. এই লাইনে যোগ হবে 80 × 2 = 160 হওয়ার কথা। - দ্বিতীয় থামা।
i= 1, কিন্তুtotalমাত্র 80, 160 নয়! অর্থাৎqtyগুণ হয়নি। বাগ ধরা পড়ল। সমাধান:items[i].price * items[i].qty. - শেষ ফল। প্রোগ্রাম ছাপল
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 recognized | Shell ফোল্ডারের নামের &-কে কমান্ডের অংশ ভাবে | নাম বদলান; project রাখুন D:\projects\bazarghar-এর মতো পথে |
EADDRINUSE | Port আগে থেকে ব্যস্ত | netstat -ano | findstr :3000, তারপর taskkill /PID <pid> /F |
running scripts is disabled | PowerShell-এর execution policy npm.ps1 আটকায় | Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, বা Command Prompt |
'node' is not recognized | PATH-এ Node নেই, বা terminal পুরোনো | Terminal আবার খুলুন; না হলে installer-এর PATH অপশন দেখুন |
EPERM বা EBUSY | ফাইল অন্য প্রোগ্রাম ধরে আছে: চলতি dev server, antivirus, OneDrive | Server বন্ধ করুন, 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-app | React দল ২০২৫ সালে নতুন অ্যাপের জন্য এটি deprecated করেছে | react.dev দেখুন |
.eslintrc.json বানান | ESLint 10-এ eslint.config.* লাগে | নিজে চালান |
process.env.REACT_APP_X | Vite-এ import.meta.env.VITE_X | Vite 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-কে সেটআপ-সমস্যা দেখানোর সময় নিচের কাঠামো ব্যবহার করুন। শেষ দুটি শর্ত সবচেয়ে কাজের।
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. ধারণা বুঝলে নতুন টুল শিখতে কয়েক ঘণ্টা লাগে, মাস নয়।
অনুশীলন
প্রথমে নিজে চেষ্টা করুন। প্রথমটি কমান্ডের, দ্বিতীয়টি হিসাবের।
-
নিজের বাজারঘর: ছোট ইংরেজি পথের একটি ফোল্ডারে Vite-এর React TypeScript project বানান।
npm run buildচালিয়ে JavaScript ফাইলের আকার লিখুন। তারপরsrc/App.tsx-এর লেখা একটু বদলে আবার build করুন। কোন দুটি জিনিস বদলাল?আপনার সংখ্যা আপনার version-এর ওপর নির্ভর করবে, তাই এই পাতার সঙ্গে না মিললেও চিন্তা নেই। বদলাবে ফাইলের আকার (সামান্য), আর
index-….js-এর hash. CSS না বদলালে CSS ফাইলের নাম একই থাকার কথা। Browser তাই শুধু নতুন JavaScript নামাবে, CSS-এর cache কাজে লাগবে। Hash-ভিত্তিক নামের উপকার এখানেই। -
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-এর পুরো কোড।
-
ফলাফল অনুমান করুন:
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 আর গাছ বদলেছে। - (১) 2.0.0: lockfile-এর version range-এর সঙ্গে মেলে, তাই বহাল। আউটপুট ছিল
-
নকশা সমালোচনা: একজন ফ্রিল্যান্সারের 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 syncnode_modules-এ ঝামেলা করে। ছোট পথে সরান।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমনতুন Vite project-কে তৈরি থেকে যাচাই পর্যন্ত সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- 🏗️
npm create vite@latestদিয়ে কাঠামো বানানো - 📦
npm installদিয়ে package আনা - ⚡
npm run devচালিয়ে কাজ করা - 🔍
npm run lintদিয়ে ভুল খোঁজা - 🧱
npm run buildদিয়েdist/বানানো - 👀
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-এর পরে কী হবে?
abcbundle-এ ঢুকবে,DB_PASSWORDclient-এ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 নেই
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Node-এর LTS নিন;
dev,build,previewতিনটির কাজ আলাদা। package.jsonহলো ইচ্ছা, lockfile হলো বাস্তব; lockfile commit করুন, CI-তেnpm ci.^MINOR পর্যন্ত,~PATCH পর্যন্ত নেয়; 0.x-এ^আরও সাবধানী।VITE_মানে প্রকাশ্য। Secret শুধু server-এ;dist/-এ grep করে যাচাই করুন।- Error আগে পড়ুন।
--forceআরnpm audit fix --forceশেষ উপায়, প্রথম নয়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৬ · TypeScript ফুল-স্ট্যাকের জন্য — type, interface, generic আর ভাগ করা typeপরবর্তী পর্বClient আর server-এ একই type ব্যবহার।
- ফুল-স্ট্যাক ওয়েব ফ্রেমওয়ার্ক · কোর্স হোম৯৩টি পর্বপুরো কোর্সের রোডম্যাপ।
- npm, Vite, ESLint আর Prettier — JavaScript-এর টুলবক্সভিত্তিBundler, node_modules আর semver-এর গোড়ার ধারণা।
- ES moduleভিত্তি
importআরexportকীভাবে কাজ করে। - Supply chain securityগভীরে যানDependency-র ঝুঁকি আর প্রতিরক্ষা।