Chuyên mục

Nodejs

Nodejs tutolrial

23 bài viết
Main Field trong Node.js: Chìa Khóa Mở Cửa Dự Án Của Bạn!
18/03/2026

Main Field trong Node.js: Chìa Khóa Mở Cửa Dự Án Của Bạn!

Chào các "dev-er" Gen Z, các bạn có bao giờ thắc mắc khi cài một cái thư viện Node.js từ npm về, làm sao Node.js nó biết phải chạy file nào đầu tiên không? Hay khi các bạn viết thư viện của riêng mình, làm sao để người khác require() phát là chạy được ngay? Đừng lo, hôm nay Creyt sẽ "giải mã" cho các bạn một "vị tướng" thầm lặng nhưng cực kỳ quyền lực trong thế giới Node.js: main field trong file package.json. 1. main field là gì và để làm gì? "Main field" trong package.json giống như cái "ảnh đại diện" của project bạn trên Instagram vậy. Nó là cái điểm chạm đầu tiên, cái entry point (điểm vào) chính thức mà Node.js (hay bất kỳ ai require() hoặc import thư viện của bạn) sẽ tìm đến để bắt đầu "câu chuyện" code của bạn. Nói một cách hàn lâm hơn theo kiểu Harvard, main field là một metadata descriptor trong package.json chỉ định module entry point cho package của bạn. Khi một module khác thực hiện lệnh require('your-package-name'), Node.js sẽ tra cứu file package.json của your-package-name, và nếu tìm thấy main field, nó sẽ tải file được chỉ định bởi field này. Nếu không có main field, Node.js sẽ mặc định tìm file index.js trong thư mục gốc của package. Đây là một phần cốt lõi của module resolution algorithm của Node.js. Để làm gì ư? Đơn giản là để Node.js biết phải "khởi động" từ đâu khi có ai đó muốn dùng code của bạn. Nó như "tấm bản đồ" chỉ đường đến kho báu chính của project vậy. 2. Code Ví Dụ Minh Họa Rõ Ràng Giả sử bạn có một thư viện "CreytUtils" chuyên cung cấp các hàm tiện ích. Bước 1: Tạo cấu trúc project mkdir CreytUtils cd CreytUtils npm init -y mkdir lib touch index.js touch lib/math.js Bước 2: Cập nhật package.json File package.json của bạn sau khi npm init -y sẽ trông như này: { "name": "creytutils", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } Ở đây, "main": "index.js" chính là thứ chúng ta đang nói đến. Nó bảo Node.js rằng, "Ê, nếu ai đó require('creytutils') thì mày chạy file index.js này nhé!". Nhưng chúng ta muốn file chính của mình nằm trong lib/index.js (hoặc index.js trực tiếp ở root). Nếu file chính của bạn là index.js ở thư mục gốc, thì "main": "index.js" là đúng. Nếu bạn muốn file chính nằm sâu hơn, ví dụ lib/app.js, bạn sẽ thay đổi: { "name": "creytutils", "version": "1.0.0", "description": "A utility library by Creyt", "main": "lib/app.js", <--- Thay đổi ở đây "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "Creyt", "license": "ISC" } Bước 3: Viết Code cho các file lib/math.js (một module con) // lib/math.js function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } module.exports = { add, subtract }; index.js (hoặc lib/app.js nếu bạn đổi main) // index.js (hoặc lib/app.js) const math = require('./lib/math'); // Hoặc './math' nếu math.js cùng cấp function greet(name) { return `Hello, ${name}! Welcome to CreytUtils.`; } module.exports = { greet, math }; Bước 4: Sử dụng thư viện của bạn Giả sử bạn tạo một file test.js bên ngoài thư mục CreytUtils (hoặc trong một project khác). // test.js const creytUtils = require('./CreytUtils'); // Hoặc require('creytutils') nếu đã publish lên npm console.log(creytUtils.greet('Gen Z Dev')); // Output: Hello, Gen Z Dev! Welcome to CreytUtils. console.log(creytUtils.math.add(5, 3)); // Output: 8 Thấy chưa, Node.js đã tự động tìm đến index.js (hoặc lib/app.js) nhờ vào main field! 3. Mẹo (Best Practices) để ghi nhớ và dùng thực tế Luôn luôn định nghĩa main: Đừng để Node.js phải đoán mò. Hãy chỉ rõ ràng "đây là cửa chính nhà tao". Nó giúp code của bạn dễ hiểu và dễ bảo trì hơn rất nhiều. Tên file rõ ràng: Thường thì là index.js, app.js, hoặc server.js cho các ứng dụng. Tên file nên phản ánh vai trò của nó. Giữ file main sạch sẽ: File được chỉ định bởi main nên tập trung vào việc export các chức năng chính của thư viện hoặc khởi tạo ứng dụng. Hạn chế logic phức tạp không liên quan trực tiếp đến việc "mở cửa" project. exports field cho tương lai: Đối với các thư viện hiện đại hơn, đặc biệt là khi bạn muốn hỗ trợ cả CommonJS (CJS) và ES Modules (ESM), hoặc muốn định nghĩa nhiều entry point (ví dụ: require('my-lib/utils')), hãy tìm hiểu về exports field. Nó mạnh mẽ và linh hoạt hơn main rất nhiều, nhưng main vẫn là "cửa chính" cơ bản nhất. 4. Ứng dụng thực tế Hầu như mọi thư viện Node.js mà bạn cài từ npm đều sử dụng main (hoặc exports) field. Ví dụ: Express.js: Khi bạn const express = require('express');, Node.js sẽ tìm đến main field trong package.json của Express để biết file nào chứa đối tượng express cần export. Lodash: Tương tự, require('lodash') sẽ dẫn bạn đến file entry point của Lodash. Các ứng dụng backend Node.js: Khi bạn build một API, file app.js hoặc server.js của bạn thường là điểm khởi đầu chính. Mặc dù bạn không require chính project của mình, nhưng nếu bạn đóng gói nó thành một module con hoặc muốn người khác dùng, main field sẽ rất quan trọng. 5. Thử nghiệm và Nên dùng cho case nào? Thử nghiệm: Hãy thử tạo một project nhỏ, đặt main field trỏ đến một file không tồn tại, hoặc một file rỗng. Sau đó thử require project đó từ một file khác. Bạn sẽ thấy Node.js báo lỗi hoặc trả về undefined, minh chứng cho việc main field quan trọng thế nào trong việc định vị code. Nên dùng cho case nào? Module/Thư viện đơn giản: Khi project của bạn chỉ có một điểm vào chính, và bạn muốn mọi người chỉ cần require('your-module') là có thể dùng được ngay. Tương thích ngược: main field đã tồn tại từ rất lâu và được hỗ trợ rộng rãi trong hệ sinh thái Node.js/npm. Nếu bạn không có nhu cầu phức tạp về module resolution, main là lựa chọn an toàn và dễ hiểu nhất. Điểm khởi đầu cho các ứng dụng: Mặc dù không trực tiếp require chính mình, việc định nghĩa main giúp các công cụ build, các môi trường CI/CD hoặc các dịch vụ hosting (như Heroku, Vercel) dễ dàng xác định file nào là file khởi động chính của ứng dụng của bạn. Tóm lại, main field là một "người gác cổng" quan trọng, đảm bảo rằng Node.js luôn tìm thấy đúng "cánh cửa" để vào project của bạn. Đừng bao giờ quên nó nhé các "dev-er" Gen Z! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

0 Đọc tiếp
Scripts Field trong Node.js: Phím tắt quyền năng cho Dev Gen Z
18/03/2026

Scripts Field trong Node.js: Phím tắt quyền năng cho Dev Gen Z

Chào các "thợ code" Gen Z! Hôm nay, Creyt sẽ "bung lụa" một khái niệm tuy nhỏ mà có võ, giúp anh em "nhàn tênh" trong công cuộc phát triển ứng dụng Node.js: scripts field trong file package.json. 1. "Scripts Field" là gì mà "chill" thế? "Scripts field" trong package.json giống như cái "menu phím tắt" hay "macro" cá nhân của bạn trong thế giới Node.js vậy. Tưởng tượng bạn có một loạt thao tác lặp đi lặp lại: chạy app, test code, build dự án, hay thậm chí là "đẩy" lên server. Thay vì phải gõ những dòng lệnh dài ngoằng, phức tạp vào Terminal mỗi lần, bạn chỉ cần "tạo một cái tên" ngắn gọn cho chuỗi lệnh đó trong scripts. Khi cần, bạn chỉ việc gọi npm run <tên_script_của_bạn> là "phép thuật" sẽ tự động diễn ra. Nó giống như việc bạn tạo một preset filter "so deep" trên Instagram ấy, bấm một cái là ảnh đẹp ngay, không cần căn chỉnh từng thông số nữa. "Scripts field" giúp bạn: "lười một cách thông minh", tiết kiệm thời gian, và quan trọng nhất là "chuẩn hóa" quy trình làm việc cho cả team. 2. "Phép thuật" Scripts Field hoạt động ra sao? (Code Ví Dụ) Để "thử nghiệm" cái sự "chill" này, chúng ta sẽ tạo một dự án Node.js nhỏ xinh. Đầu tiên, hãy khởi tạo một dự án: npm init -y Sau đó, mở file package.json lên. Bạn sẽ thấy một cấu trúc cơ bản. Giờ, chúng ta sẽ thêm hoặc chỉnh sửa mục "scripts" như sau: { "name": "creyts-genz-app", "version": "1.0.0", "description": "Ứng dụng demo scripts field của thầy Creyt", "main": "index.js", "scripts": { "start": "node index.js", "dev": "nodemon index.js", "test": "echo \"Chưa có test nào cả, code chạy là được!\" && exit 1", "build": "echo \"Ứng dụng này không cần build phức tạp!\"", "lint": "eslint .", "hello": "echo 'Hello Gen Z từ thầy Creyt!'" }, "keywords": [], "author": "Creyt", "license": "ISC", "dependencies": { "express": "^4.17.1" }, "devDependencies": { "nodemon": "^2.0.7", "eslint": "^7.2.0" } } Để script "dev" hoạt động, bạn cần cài nodemon: npm install nodemon eslint --save-dev Và đây là file index.js đơn giản của chúng ta: // index.js const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello Gen Z! Ứng dụng Node.js của Creyt đã chạy!'); }); app.listen(port, () => { console.log(`Server chạy trên http://localhost:${port}`); }); Giờ thì "triển" thôi! Mở Terminal và thử các lệnh: npm start: Để chạy ứng dụng một lần. npm run dev: Để chạy ứng dụng với nodemon, mỗi khi bạn thay đổi code, server sẽ tự động restart. npm run hello: Để thấy dòng chữ "Hello Gen Z từ thầy Creyt!". Anh em thấy không? Đỡ phải gõ node index.js hay nodemon index.js dài dòng. "Phím tắt" chính hiệu! 3. Mẹo "hack" Scripts Field cho dev "pro" (Best Practices) Creyt có vài "chiêu" nhỏ để anh em dùng scripts field "max ping": Tên gọi "chuẩn chỉnh": Luôn dùng các tên script phổ biến như start, test, build, dev (hoặc serve). Điều này giúp người khác (và chính bạn sau này) dễ dàng hiểu được mục đích của script mà không cần đọc code. "Xích" các lệnh lại với nhau: Dùng && để chạy các lệnh tuần tự (lệnh sau chỉ chạy khi lệnh trước thành công) hoặc & để chạy song song (cẩn thận với cái này, đôi khi cần wait-on hoặc các tool khác để đảm bảo thứ tự). "scripts": { "predeploy": "npm run build && npm run test", "deploy": "some-deploy-command", "dev:backend": "nodemon src/server.js", "dev:frontend": "webpack-dev-server --mode development", "dev": "npm run dev:backend & npm run dev:frontend" } "Pre" và "Post" script: npm có một tính năng cực "ảo diệu" là pre<script-name> và post<script-name>. Ví dụ, nếu bạn có script "test", bạn có thể định nghĩa "pretest" để chạy trước "test" (ví dụ: lint code) và "posttest" để chạy sau (ví dụ: dọn dẹp). Tự động hóa ở level cao! "scripts": { "pretest": "npm run lint", "test": "jest --coverage", "posttest": "echo 'Test completed!'" } Biến môi trường "đa nền tảng": Nếu bạn cần đặt biến môi trường (ví dụ: NODE_ENV=production), hãy dùng cross-env để đảm bảo nó hoạt động trên cả Windows, macOS và Linux. Cài đặt: npm install cross-env --save-dev. "scripts": { "start:prod": "cross-env NODE_ENV=production node index.js" } "Đơn giản là nhất": Nếu script quá dài hoặc phức tạp, hãy tách nó ra thành một file .js hoặc .sh riêng và gọi file đó từ scripts field. Giúp code gọn gàng, dễ đọc. 4. Góc nhìn "học thuật Harvard" (nhưng vẫn dễ hiểu tuyệt đối) Từ góc độ "học thuật" mà nói, scripts field không chỉ là một tiện ích "thường thường bậc trung" mà nó còn là một lớp trừu tượng (abstraction layer) mạnh mẽ. Nó giúp chúng ta "đóng gói" những lệnh dòng lệnh phức tạp, dễ quên thành những "tên gọi" dễ nhớ, dễ quản lý. Điều này không chỉ chuẩn hóa quy trình làm việc trong một dự án mà còn giảm thiểu gánh nặng nhận thức (cognitive load) cho các developer. Thay vì phải nhớ webpack --config webpack.prod.js --mode production, họ chỉ cần biết npm run build. Nó giống như việc bạn dùng một chiếc điều khiển từ xa để bật TV thay vì phải chạy ra tận nơi bấm nút vậy – tiện lợi và hiệu quả hơn rất nhiều. Một điểm cực kỳ quan trọng khác là cách npm run xử lý các binaries cục bộ. Khi bạn cài đặt một package như nodemon hay jest dưới dạng devDependencies, các file thực thi (binaries) của chúng sẽ nằm trong thư mục node_modules/.bin. Khi bạn chạy npm run <script>, npm sẽ tự động thêm node_modules/.bin vào biến môi trường PATH tạm thời cho script đó. Điều này có nghĩa là bạn có thể gọi nodemon hoặc jest trực tiếp trong script mà không cần phải gõ node_modules/.bin/nodemon dài dòng. Đây là một cơ chế "ngầm" nhưng cực kỳ thông minh của npm! 5. "Scripts Field" đã "chinh phục" những "ông lớn" nào? (Ứng dụng thực tế) Hầu hết mọi dự án Node.js "đứng đắn" ngày nay đều khai thác scripts field: Các Framework/Thư viện lớn: Từ Express.js, NestJS đến Next.js, Nuxt.js đều dùng scripts để định nghĩa các lệnh dev, build, start cho người dùng. Bạn chỉ cần npm run dev là có môi trường phát triển đầy đủ. Dự án Microservices: Trong kiến trúc microservices, mỗi service thường là một dự án Node.js độc lập. scripts giúp chuẩn hóa việc khởi động, kiểm thử và build từng service. Website/Web Apps: Bất kỳ trang web nào dùng Node.js làm backend (hoặc fullstack) đều dùng scripts để chạy server, compile assets frontend (nếu có), chạy migration database, v.v. Công cụ CI/CD: Các hệ thống tích hợp liên tục/triển khai liên tục như GitHub Actions, GitLab CI, Jenkins, CircleCI đều dựa vào npm run test hoặc npm run build để tự động kiểm tra code, build ứng dụng và triển khai khi có thay đổi. 6. Khi nào "Scripts Field" là "cứu tinh" của bạn? (Thử nghiệm và Hướng dẫn dùng) "Scripts field" nên được dùng trong mọi trường hợp bạn muốn tự động hóa một tác vụ liên quan đến dự án Node.js của mình: Phát triển cục bộ (Local Development): "Phải có" cho các lệnh như npm run dev để khởi động server với các tính năng như hot-reloading, watch mode. Giúp bạn tập trung vào code hơn là vào việc quản lý Terminal. Kiểm thử (Testing): npm run test là tiêu chuẩn vàng để chạy tất cả các bộ test (unit, integration, end-to-end). Rất quan trọng để đảm bảo chất lượng code. Xây dựng (Building): Khi bạn có các bước biên dịch code (ví dụ: dùng Babel để chuyển đổi ES6+, dùng Webpack để đóng gói frontend assets), npm run build sẽ gom tất cả các bước đó lại thành một lệnh duy nhất. Triển khai (Deployment): Tự động hóa các bước triển khai lên server. Ví dụ: npm run deploy có thể chạy các lệnh build, nén file, SSH vào server và copy code lên đó. Kiểm tra chất lượng code (Linting/Formatting): Chạy npm run lint để kiểm tra lỗi cú pháp, style code với ESLint hoặc Prettier. Tạo file/Database Migration: Dùng scripts để chạy các lệnh tạo file boilerplate, hoặc chạy các script migration database để cập nhật cấu trúc database. Lời khuyên từ Creyt: Hãy coi scripts field như một phần không thể thiếu của dự án. Nó không chỉ giúp bạn "nhàn hơn" mà còn giúp dự án của bạn "chuyên nghiệp hơn", dễ bảo trì và dễ dàng cho người mới tham gia. Đừng ngại "đầu tư" thời gian để định nghĩa các script một cách rõ ràng và hiệu quả nhé! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

1 Đọc tiếp
DevDependencies: Phụ Tùng 'Hậu Trường' Của Dân Dev Node.js
18/03/2026

DevDependencies: Phụ Tùng 'Hậu Trường' Của Dân Dev Node.js

Chào các Gen Z, hôm nay anh Creyt sẽ giải mã một khái niệm mà nhiều khi các em cứ nghĩ nó là 'phụ tùng' nhưng thực ra nó lại là 'xương sống' cho quá trình phát triển của chúng ta: devDependencies trong Node.js. Hãy hình dung thế này: Em đang làm một bộ phim bom tấn, đúng không? dependencies (những gói thư viện nằm trong field dependencies): Đó là dàn diễn viên chính, đạo diễn, kịch bản, máy quay, ánh sáng... Tóm lại, những thứ BẮT BUỘC phải có mặt trong bản phim cuối cùng để khán giả xem và trầm trồ. Thiếu một trong số đó, phim không ra phim. devDependencies (những gói thư viện nằm trong field devDependencies): Còn đây là đội hậu cần siêu đẳng của em: từ anh chị make-up, stylist, đội catering (lo cơm nước), cho đến anh đạo cụ, chuyên gia dựng phông xanh, hay thậm chí là mấy anh chị trợ lý đạo diễn. Họ cực kỳ quan trọng để quá trình quay phim diễn ra suôn sẻ, nhưng khi bộ phim hoàn thành và ra rạp, khán giả có thấy xe chở cơm hay hộp phấn của diễn viên trên màn hình không? KHÔNG! Công việc của họ là hỗ trợ cho quá trình SẢN XUẤT, chứ không phải là một phần của SẢN PHẨM CUỐI CÙNG. Vậy devDependencies chính là những công cụ, thư viện mà chúng ta chỉ cần dùng trong quá trình phát triển và kiểm thử dự án Node.js của mình. Khi sản phẩm đã "đóng gói" xong xuôi để chạy thật, chúng ta không cần chúng nữa. devDependencies Là Gì? Tại Sao Lại Quan Trọng? Từ góc độ học thuật mà nói, devDependencies là một trường (field) trong file package.json của một dự án Node.js, được quản lý bởi npm (Node Package Manager) hoặc yarn. Nó chứa danh sách các gói (packages) mà ứng dụng của bạn cần để: Phát triển (Development): Ví dụ như các công cụ biên dịch (transpilers) như Babel để chuyển đổi code ES6+ sang ES5, hoặc các server phát triển (development servers) như webpack-dev-server. Kiểm thử (Testing): Các framework kiểm thử như Jest, Mocha, Chai, hay các thư viện hỗ trợ kiểm thử như Supertest. Xây dựng (Building/Bundling): Các công cụ đóng gói (bundlers) như Webpack, Rollup, hoặc các task runner như Gulp. Linter/Formatter: Các công cụ kiểm tra chất lượng code như ESLint, Prettier. Mục tiêu chính của việc phân biệt dependencies và devDependencies là để tối ưu hóa kích thước gói ứng dụng khi triển khai (deployment). Khi bạn cài đặt các gói cho môi trường sản phẩm (production environment) bằng lệnh npm install --production (hoặc npm ci --production), npm sẽ chỉ cài đặt các gói trong dependencies, bỏ qua devDependencies. Điều này giúp giảm đáng kể dung lượng của ứng dụng, tăng tốc độ cài đặt và giảm rủi ro bảo mật không cần thiết từ các gói chỉ dùng cho phát triển. Code Ví Dụ Minh Họa Rõ Ràng Nói suông thì khó hình dung, mình cùng xem ví dụ thực tế nhé. Giả sử em có một file package.json như sau: { "name": "my-awesome-app", "version": "1.0.0", "description": "A simple Node.js application", "main": "index.js", "scripts": { "start": "node index.js", "test": "jest", "build": "webpack" }, "dependencies": { "express": "^4.17.1", "mongoose": "^6.0.12" }, "devDependencies": { "jest": "^27.3.1", "webpack": "^5.61.0", "webpack-cli": "^4.9.1", "eslint": "^8.0.1", "prettier": "^2.4.1" } } Ở đây: express và mongoose là dependencies vì chúng là thư viện cần thiết để ứng dụng chạy khi đã triển khai. jest (để chạy test), webpack và webpack-cli (để đóng gói code), eslint và prettier (để kiểm tra và định dạng code) là devDependencies. Chúng ta chỉ cần chúng khi đang code, test, hoặc build dự án, chứ không phải khi ứng dụng đã chạy trên server sản phẩm. Cách cài đặt: Để cài đặt một dependency (ví dụ: axios): npm install axios # hoặc npm i axios Lệnh này sẽ tự động thêm axios vào trường dependencies trong package.json. Để cài đặt một devDependency (ví dụ: nodemon - một công cụ giúp tự động khởi động lại server khi code thay đổi): npm install nodemon --save-dev # hoặc npm i nodemon -D Lệnh này sẽ thêm nodemon vào trường devDependencies trong package.json. Mẹo Hay và Best Practices Cho devDependencies Để nhớ và dùng devDependencies hiệu quả, anh Creyt có vài mẹo nhỏ cho các em: Quy tắc 'Deployment Test': Hãy tự hỏi: 'Liệu ứng dụng của mình có chạy được trên server sản phẩm nếu thiếu gói này không?' Nếu câu trả lời là CÓ (vẫn chạy được, chỉ là quá trình phát triển/kiểm thử khó hơn), thì đó là devDependency. Nếu KHÔNG (ứng dụng lỗi ngay lập tức), thì đó là dependency. Giảm thiểu 'Gánh nặng': Luôn cố gắng giữ devDependencies tách biệt. Điều này không chỉ giúp giảm kích thước gói ứng dụng mà còn giảm thiểu rủi ro về lỗ hổng bảo mật từ các thư viện không cần thiết trên môi trường sản phẩm. Sử dụng npm ci cho CI/CD: Trong các hệ thống Tích hợp Liên tục/Triển khai Liên tục (CI/CD), hãy dùng npm ci thay vì npm install. npm ci đảm bảo rằng bạn cài đặt chính xác các phiên bản đã được ghi trong package-lock.json, giúp quá trình build ổn định và đáng tin cậy hơn, đặc biệt hữu ích khi chỉ cài đặt dependencies trên môi trường sản xuất. Đồng bộ team: Đảm bảo toàn bộ team dev hiểu rõ và tuân thủ quy tắc phân loại này. Tránh tình trạng người này cài -D, người kia quên, dẫn đến package.json lộn xộn. Ứng Dụng Thực Tế và Case Sử Dụng Hầu hết các dự án Node.js lớn nhỏ, từ các framework web như Express.js, NestJS cho đến các công cụ dựng frontend như Create React App, Next.js, hay các thư viện như Lodash, React, đều sử dụng triệt để devDependencies. Create React App (CRA): Khi bạn tạo một dự án React bằng CRA, bạn sẽ thấy rất nhiều devDependencies như react-scripts, eslint, babel-jest, webpack (ẩn đi) – tất cả đều là công cụ để giúp bạn phát triển và build ứng dụng React, chứ bản thân chúng không chạy trực tiếp trong ứng dụng cuối cùng của người dùng. Các dự án mã nguồn mở trên GitHub: Em cứ thử vào bất kỳ dự án Node.js nào có package.json trên GitHub, lướt xuống phần devDependencies mà xem. Em sẽ thấy một 'khu vườn' đầy đủ các công cụ test, linter, builder mà họ dùng để duy trì chất lượng code. Ví dụ, dự án Vue.js hay React cũng có một danh sách devDependencies rất dài để phục vụ quá trình phát triển nội bộ. Anh Creyt đã từng chứng kiến không ít dự án, đặc biệt là các dự án 'mì ăn liền' hoặc của các dev mới, nhét tất cả mọi thứ vào dependencies. Hậu quả là gì? Kích thước gói ứng dụng phình to: Một dự án nhỏ chỉ vài chục MB có thể biến thành vài trăm MB chỉ vì kéo theo cả đống công cụ test, linter không cần thiết. Thời gian cài đặt lâu hơn: Mỗi lần deploy, server phải tải về và cài đặt cả những gói không dùng đến. Rủi ro bảo mật: Càng nhiều gói, càng nhiều 'cửa ngõ' tiềm năng cho các lỗ hổng bảo mật, dù là gói chỉ dùng cho dev. Vậy nên dùng devDependencies cho các case nào? Công cụ kiểm thử: Jest, Mocha, Cypress, Supertest... Công cụ biên dịch/chuyển đổi: Babel (cùng với các preset và plugin), TypeScript compiler (tsc). Công cụ đóng gói/xây dựng: Webpack, Rollup, Parcel, Gulp, Grunt. Công cụ kiểm tra chất lượng code/định dạng: ESLint, Prettier, Stylelint. Công cụ server phát triển: nodemon, webpack-dev-server. Thư viện hỗ trợ phát triển/debug: debug (nếu chỉ dùng cho dev), chokidar (nếu chỉ dùng để watch file trong dev). Tóm lại, devDependencies không phải là 'phụ' mà là 'trợ lý đắc lực' giúp quá trình phát triển của em mượt mà hơn, đồng thời giữ cho sản phẩm cuối cùng của em 'thon gọn' và an toàn hơn. Hãy dùng chúng một cách thông minh, các Gen Z nhé! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

1 Đọc tiếp
Dependencies Field: 'Nguyên Liệu' Của Mọi App Node.js!
18/03/2026

Dependencies Field: 'Nguyên Liệu' Của Mọi App Node.js!

'Dependencies Field': Cái "Danh Sách Nguyên Liệu" Của Mọi Dự Án Node.js Hôm nay thầy Creyt sẽ giải mã một khái niệm mà các bạn Gen Z thường gặp nhưng có thể chưa thực sự hiểu sâu: cái dependencies field trong package.json của Node.js. Nghe thì có vẻ hàn lâm, nhưng thực ra nó là một "chiếc giỏ đi chợ" cực kỳ quan trọng cho dự án của bạn đấy! 1. 'Dependencies Field' Là Gì Mà Quan Trọng Thế? Thử tưởng tượng bạn đang muốn làm một món "đặc sản" Node.js siêu phức tạp, ví dụ như một REST API đỉnh cao hay một web app real-time. Bạn có tự tay đi trồng lúa, chăn nuôi, hay tự chế tạo từng con chip để làm ra cái máy tính chạy app không? Tất nhiên là không rồi! Chúng ta "đứng trên vai người khổng lồ" bằng cách sử dụng các thư viện, framework có sẵn. Cái dependencies field trong file package.json chính là "danh sách nguyên liệu và công cụ" mà dự án của bạn cần để hoạt động. Nó là một đối tượng JSON liệt kê tên các package (thư viện, module) và phiên bản cụ thể của chúng mà code của bạn "phụ thuộc" vào để chạy được. Nó giống như bạn đưa cho "siêu đầu bếp" npm một cái menu, và npm sẽ tự động đi thu thập đầy đủ mọi thứ cần thiết cho món ăn của bạn. Mục đích cốt lõi: Đảm bảo tính nhất quán: Khi bạn chia sẻ dự án với đồng đội, hay thậm chí là chính bạn sau này, chỉ cần gõ lệnh npm install là mọi thứ sẽ được cài đặt đúng phiên bản, tránh xa cái nỗi ám ảnh "chạy trên máy tao thì được, máy mày thì tạch!". Quản lý dễ dàng: Thay vì phải nhớ từng thư viện và phiên bản, package.json làm hết việc đó cho bạn. Tái sử dụng code: Bạn không cần phải "phát minh lại bánh xe" mỗi lần, mà có thể tận dụng hàng ngàn package chất lượng cao từ cộng đồng Node.js. 2. Code Ví Dụ Minh Hoạ "Sương Sương" Giờ thì chúng ta hãy xem một ví dụ thực tế. Giả sử bạn đang xây một ứng dụng web đơn giản với Express.js: package.json: { "name": "my-awesome-app", "version": "1.0.0", "description": "A simple Node.js web application", "main": "index.js", "scripts": { "start": "node index.js" }, "keywords": [], "author": "Creyt The Master", "license": "MIT", "dependencies": { "express": "^4.18.2", "lodash": "^4.17.21" }, "devDependencies": { "nodemon": "^3.0.1" } } Trong ví dụ trên, express và lodash là hai "nguyên liệu chính" mà ứng dụng của bạn cần để chạy. Chúng được liệt kê trong dependencies. index.js (Sử dụng Express và Lodash): const express = require('express'); const _ = require('lodash'); // Import lodash const app = express(); const port = 3000; // Ví dụ sử dụng lodash const numbers = [1, 2, 3, 4, 5]; const sum = _.sum(numbers); app.get('/', (req, res) => { res.send(`Hello from my awesome app! The sum of numbers is: ${sum}`); }); app.listen(port, () => { console.log(`App listening at http://localhost:${port}`); }); Khi bạn chạy npm install trong thư mục dự án này, npm sẽ tự động tải express và lodash (cùng với các dependencies con của chúng) vào thư mục node_modules. 3. Mẹo Vặt & Best Practices Từ Thầy Creyt (Để Trở Thành "Đệ Tử Cứng") Để không "tạch" giữa đường và trở thành một dev Node.js "có gu", hãy ghi nhớ những mẹo này: dependencies vs devDependencies: dependencies: Đây là những "nguyên liệu sống còn" để ứng dụng của bạn hoạt động trong môi trường production (khi app đã "lên sóng"). Ví dụ: express, react, axios, mongoose. devDependencies: Là "công cụ làm bếp" chỉ cần khi bạn đang phát triển hoặc test. Chúng không cần thiết khi ứng dụng đã được deploy. Ví dụ: nodemon (để tự động restart server), jest (để test), webpack (để build code), eslint (để kiểm tra cú pháp). Mẹo cài đặt: Để cài một package vào dependencies, bạn chỉ cần npm install <package-name>. Để cài vào devDependencies, dùng npm install <package-name> --save-dev hoặc npm install <package-name> -D. Hiểu Rõ Ký Hiệu Phiên Bản (Semantic Versioning - SemVer): Các con số X.Y.Z (Major.Minor.Patch) không phải để "làm đẹp" đâu nhé. Chúng là "ngôn ngữ" để quản lý phiên bản: X (Major): Thay đổi lớn, có thể phá vỡ API (breaking changes). Cần cẩn trọng khi update. Y (Minor): Thêm tính năng mới, nhưng vẫn tương thích ngược. Z (Patch): Vá lỗi, sửa bug, vẫn tương thích ngược. ^ (Caret): "Cho tôi bản mới nhất trong cùng Major version!" Ví dụ ^4.18.2 có nghĩa là 4.18.2 hoặc bất kỳ phiên bản 4.x.x nào miễn là x và y lớn hơn 18 và 2 hoặc lớn hơn. Nó sẽ cài 4.19.0, 4.20.5, nhưng không cài 5.0.0. ~ (Tilde): "Chỉ cần bản vá lỗi mới nhất thôi!" Ví dụ ~4.18.2 có nghĩa là 4.18.2 hoặc bất kỳ phiên bản 4.18.x nào (ví dụ 4.18.3), nhưng không phải 4.19.0. Mẹo: Đối với dependencies, thường dùng ^ để nhận các bản cập nhật tính năng mới miễn là không phá vỡ API chính. Đối với các thư viện nhạy cảm, bạn có thể khóa chặt phiên bản (4.18.2 không có ký hiệu) để đảm bảo tính ổn định tuyệt đối. package-lock.json: "Người Ghi Sổ Trung Thành" Đây là một file tự động được npm tạo ra. Nó không chỉ ghi lại các dependencies trực tiếp mà còn ghi lại chính xác phiên bản của tất cả các package con (nested dependencies) và cả URL tải về của chúng. Tầm quan trọng: Nó đảm bảo rằng mọi người trong nhóm hoặc trên môi trường deploy đều cài đặt chính xác cùng một bộ package và phiên bản, bất kể package.json có ký hiệu ^ hay ~ đi chăng nữa. Luôn luôn commit file này vào Git! peerDependencies (Nâng cao một chút): Đây là trường hợp package của bạn "mong muốn" một phiên bản cụ thể của một package khác từ phía người dùng, nhưng không tự cài đặt nó. Ví dụ: một plugin React sẽ khai báo react là peerDependency để đảm bảo nó chạy đúng với phiên bản React mà ứng dụng gốc đang dùng. Nó giống như "yêu cầu" người dùng phải có sẵn một loại "nguyên liệu đặc biệt" trước khi dùng món ăn của bạn vậy. 4. Ứng Dụng Thực Tế & Khi Nào Nên Dùng "Dependencies field" là trái tim của mọi dự án Node.js. Bạn sẽ thấy nó ở khắp mọi nơi: React/Next.js Apps: react, react-dom, next sẽ nằm trong dependencies. Express APIs: express, cors, body-parser là những cái tên quen thuộc. Angular/Vue.js Projects: Mặc dù không phải Node.js trực tiếp, nhưng các công cụ build và thư viện của chúng cũng được quản lý qua package.json và dependencies. Microservices, Serverless Functions: Bất kỳ module Node.js nào đều cần nó để quản lý các package mà chúng phụ thuộc. Khi nào nên dùng dependencies và devDependencies: Dùng dependencies khi: Package đó là một phần không thể thiếu để ứng dụng của bạn chạy đúng logic kinh doanh và cung cấp giá trị cho người dùng cuối. Ví dụ: thư viện database, router, middleware xác thực. Dùng devDependencies khi: Package đó chỉ hỗ trợ bạn trong quá trình phát triển, kiểm thử, hoặc tối ưu hóa code, và không cần thiết khi code đã được biên dịch hoặc triển khai lên môi trường production. Ví dụ: công cụ linting, test runner, bundler, server tự động reload. Hiểu và quản lý tốt dependencies không chỉ giúp dự án của bạn ổn định mà còn thể hiện sự chuyên nghiệp của một lập trình viên "cứng cựa". Hãy "nắm trọn" nó như cách bạn nắm trọn trái tim crush vậy! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

35 Đọc tiếp
package.json: CMND của dự án Node.js mà Gen Z cần biết!
18/03/2026

package.json: CMND của dự án Node.js mà Gen Z cần biết!

package.json: CMND của dự án Node.js mà Gen Z cần biết? Chào các "dev-tí-hon" tương lai của kỷ nguyên số! Giảng viên Creyt đây, hôm nay chúng ta sẽ cùng "mổ xẻ" một tệp tin mà các bạn sẽ gặp đi gặp lại như crush cũ trong mọi dự án Node.js: package.json. Nghe tên có vẻ "hàn lâm" đúng không? Nhưng thực ra, nó chính là cái "CMND" hay "Hồ sơ cá nhân" của dự án bạn đấy! Tưởng tượng thế này: Mỗi khi bạn tạo một dự án Node.js, nó cũng giống như bạn sinh ra một "đứa con tinh thần" vậy. Và package.json chính là cái giấy khai sinh, là lý lịch trích ngang, là "TikTok bio" của đứa con đó. Nó chứa tất tần tật thông tin quan trọng: tên dự án, phiên bản, mô tả, tác giả, và quan trọng nhất là "những người bạn" (dependencies) mà dự án cần để hoạt động. Vậy, package.json để làm gì? Nó có ba nhiệm vụ chính, mà nếu thiếu thì dự án của bạn sẽ "lạc trôi" như không có sóng WiFi: Thông tin dự án (Metadata): Lưu trữ tên, phiên bản, mô tả, từ khóa, tác giả... giúp người khác (và chính bạn sau này) dễ dàng hiểu về dự án. Quản lý phụ thuộc (Dependency Management): Đây là "trái tim" của package.json. Nó liệt kê tất cả các thư viện, gói (packages) mà dự án của bạn cần để chạy. Khi bạn chia sẻ dự án, người khác chỉ cần file này và chạy npm install là có đủ "đồ chơi" mà không cần phải tải từng cái một. Cứ như một "playlist" nhạc tự động tải về vậy! Tập lệnh chạy (Scripts): Đây là nơi bạn định nghĩa các lệnh tắt để chạy dự án, kiểm thử, build sản phẩm... Nó giống như "cheat sheet" giúp bạn thực hiện các tác vụ phức tạp chỉ bằng một vài cú pháp đơn giản. "Start", "build", "test" – tất cả đều nằm gọn ở đây. Phẫu thuật một em package.json (Code Ví Dụ minh hoạ) Giờ thì, chúng ta sẽ cùng "phẫu thuật" một file package.json để xem bên trong nó có gì nhé. Để tạo một file package.json cơ bản, bạn chỉ cần mở terminal trong thư mục dự án và gõ: npm init -y. Lệnh -y sẽ tự động chấp nhận các giá trị mặc định. { "name": "project-creyt-demo", "version": "1.0.0", "description": "Đây là dự án demo về package.json của giảng viên Creyt", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1", "dev": "nodemon index.js" }, "keywords": [ "nodejs", "package.json", "demo", "creyt" ], "author": "Giang vien Creyt", "license": "ISC", "dependencies": { "express": "^4.18.2", "mongoose": "^7.6.3" }, "devDependencies": { "nodemon": "^3.0.1" } } Hãy cùng "giải mã" từng trường một: name: Tên dự án. Nên là tên duy nhất, viết thường, không dấu, không khoảng trắng (dùng dấu gạch ngang - hoặc gạch dưới _). version: Phiên bản hiện tại của dự án. Theo chuẩn Semantic Versioning (SemVer) MAJOR.MINOR.PATCH. MAJOR: Thay đổi lớn, không tương thích ngược. MINOR: Thêm tính năng mới, tương thích ngược. PATCH: Sửa lỗi nhỏ, tương thích ngược. description: Mô tả ngắn gọn về dự án. Giúp người khác dễ hình dung. main: File chính của dự án, thường là điểm khởi đầu khi chạy ứng dụng. scripts: Nơi chứa các lệnh tắt bạn có thể chạy bằng npm run <tên_script>. Ví dụ: npm run start hoặc npm run dev. Các script như start, test có thể chạy trực tiếp bằng npm start, npm test mà không cần run. keywords: Các từ khóa liên quan đến dự án, giúp dễ tìm kiếm hơn. author: Tên tác giả. license: Giấy phép sử dụng mã nguồn. ISC là một trong những giấy phép phổ biến, khá tự do. dependencies: Đây là danh sách các gói (packages) mà dự án của bạn cần để chạy trong môi trường sản phẩm (production). Ví dụ: express (framework web), mongoose (ORM cho MongoDB). Khi bạn cài đặt bằng npm install <tên_package>, nó sẽ tự động thêm vào đây. devDependencies: Danh sách các gói chỉ cần thiết cho quá trình phát triển (development), ví dụ như các công cụ kiểm thử, linter, hoặc nodemon (giúp tự động khởi động lại server khi có thay đổi). Khi deploy lên production, thường không cần những gói này để tiết kiệm dung lượng. Bí kíp sống còn từ Creyt (Best Practices) Để trở thành một dev xịn xò, không chỉ biết dùng mà còn phải dùng cho "đúng bài", đúng không nào? Dưới đây là vài mẹo xương máu từ Creyt: Đặt tên dự án (name): Hãy đặt tên thật chuẩn, duy nhất và dễ nhớ. Tránh trùng với các package phổ biến trên npm. Và nhớ là luôn luôn viết thường, dùng dấu gạch ngang nhé. Quản lý phiên bản (version): Luôn tuân thủ SemVer. Việc tăng phiên bản đúng cách giúp người dùng dự án của bạn biết được mức độ thay đổi và rủi ro khi nâng cấp. Tối ưu scripts: Đừng ngại tạo các script riêng cho các tác vụ lặp đi lặp lại. Ví dụ: npm run build:prod để build bản production, npm run lint để kiểm tra lỗi cú pháp. Nó giúp quy trình làm việc của bạn mượt mà hơn rất nhiều. Phân biệt dependencies và devDependencies rõ ràng: Điều này cực kỳ quan trọng. dependencies là "linh hồn" của ứng dụng, còn devDependencies là "công cụ hỗ trợ" bạn code. Việc phân biệt giúp giảm kích thước gói cài đặt khi deploy lên môi trường production, tiết kiệm tài nguyên. npm install <package> (mặc định vào dependencies) npm install <package> --save-dev (hoặc -D) (vào devDependencies) Luôn commit package.json và package-lock.json: package.json chỉ định các gói và phiên bản tối thiểu/tối đa (ví dụ: ^4.18.2 nghĩa là phiên bản 4.18.2 trở lên nhưng dưới 5.0.0). package-lock.json (hoặc yarn.lock nếu dùng Yarn) ghi lại chính xác phiên bản của từng gói và các gói phụ thuộc của chúng tại thời điểm cài đặt. Nó đảm bảo mọi người trong team và môi trường deploy đều dùng cùng một bộ thư viện với phiên bản y hệt nhau, tránh lỗi "nó chạy trên máy tôi mà!". Đây là "nhật ký hành trình" chi tiết nhất của dự án bạn. Ai đang dùng package.json? (Ví dụ thực tế) Hầu như MỌI dự án Node.js, từ nhỏ đến lớn, đều sử dụng package.json. Các Framework Frontend: React (với Create React App), Angular, Vue.js – tất cả đều dùng package.json để quản lý các thư viện như react, react-dom, angular/core, vue và định nghĩa các script như start (chạy dev server), build (tạo bản production), test (chạy unit tests). Các Framework Backend: Express.js, NestJS, Koa.js – dùng để quản lý express, mongoose, sequelize, axios và các script để khởi động server, chạy migrations database. Các công cụ dòng lệnh (CLI tools): Ngay cả các công cụ bạn cài đặt toàn cầu như create-react-app, vue-cli cũng là các package Node.js có package.json của riêng chúng. Ví dụ cụ thể: Một dự án React tạo bằng create-react-app sẽ có package.json với các scripts như: "start": "react-scripts start" "build": "react-scripts build" "test": "react-scripts test" Và trong dependencies sẽ có react, react-dom, react-scripts. Khi bạn chạy npm start, nó thực chất đang chạy script react-scripts start đã được định nghĩa trong package.json đó. Creyt đã từng "sống sót" thế nào với package.json (Thử nghiệm & Hướng dẫn sử dụng) Hồi Creyt mới vào nghề, chưa có package.json hay npm phổ biến như bây giờ đâu. Mấy cái thư viện toàn phải tải tay, nhét vào thư mục lib, xong rồi còn phải nhớ phiên bản nào tương thích với cái gì. Nghe thôi đã thấy "toát mồ hôi hột" rồi đúng không? Cứ mỗi lần chuyển dự án hay có dev mới vào là lại "hú hồn chim én" vì thiếu thư viện hoặc lỗi phiên bản. package.json ra đời như một vị cứu tinh, biến cái mớ hỗn độn đó thành một quy trình khoa học, chuẩn chỉnh. Khi nào nên dùng package.json? Mọi dự án Node.js/JavaScript: Dù là backend với Express, frontend với React/Vue, hay một script nhỏ chạy độc lập – cứ có Node.js là phải có package.json. Khi bạn muốn chia sẻ dự án: Để người khác có thể dễ dàng cài đặt và chạy mà không cần hỏi bạn "cần cài những gì vậy anh/chị?". Khi làm việc nhóm: Đảm bảo mọi người trong team đều có một môi trường phát triển nhất quán. Để tự động hóa tác vụ: Các script trong package.json là cánh tay phải đắc lực cho CI/CD (Continuous Integration/Continuous Deployment). Tóm lại, package.json không chỉ là một file cấu hình đơn thuần, nó là "bộ não" và "hồ sơ" của dự án Node.js của bạn. Nắm vững nó không chỉ giúp bạn code mượt mà hơn mà còn thể hiện sự chuyên nghiệp của một developer thực thụ. Hãy dùng nó như một người bạn thân, bạn sẽ thấy cuộc đời dev dễ thở hơn nhiều đấy! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

41 Đọc tiếp
Yarn: Siêu Trợ Lý JavaScript Khiến Dev Gen Z Phải 'Flex'
18/03/2026

Yarn: Siêu Trợ Lý JavaScript Khiến Dev Gen Z Phải 'Flex'

Chào các em, Creyt đây! Hôm nay chúng ta sẽ 'deep dive' vào một nhân vật không thể thiếu trong thế giới Node.js và JavaScript hiện đại: Yarn (Package Manager). Nghe cái tên thì cứ tưởng là sợi len hay gì đó, nhưng tin thầy đi, đây là một 'siêu trợ lý' cực kỳ đắc lực, giúp dự án của mấy đứa luôn 'mượt mà' và 'chất như nước cất'. 1. Yarn là gì mà Gen Z phải mê? Tưởng tượng thế này, dự án JavaScript của mấy đứa giống như một bữa tiệc code lớn, và mỗi thư viện (library) hay module là một món ăn ngon hoặc một dụng cụ đặc biệt cần có. Nếu không có ai quản lý, mọi thứ sẽ loạn xị ngầu, thiếu cái này thừa cái kia, đúng không? Đó là lúc Yarn bước vào sân khấu. Yarn, viết tắt của 'Yet Another Resource Negotiator' (đúng là dân IT đặt tên lúc nào cũng 'nghệ' vậy đó), là một package manager (trình quản lý gói) được Facebook tạo ra. Nhiệm vụ chính của nó là giúp mấy đứa dễ dàng thêm, xóa, cập nhật các thư viện JavaScript mà dự án của mấy đứa cần. Nó ra đời để khắc phục một số 'drama' mà 'người tiền nhiệm' là npm (Node Package Manager) gặp phải, đặc biệt là về tốc độ và sự ổn định. Nói cách khác, Yarn là 'người quản gia' chuyên nghiệp, đảm bảo mọi 'nguyên liệu' (dependencies) cho dự án của mấy đứa luôn đầy đủ, đúng phiên bản, và được sắp xếp gọn gàng. Nó giúp mấy đứa tập trung vào việc code 'xịn xò' chứ không phải đau đầu vì 'đồ nghề' lộn xộn. 2. Code Ví Dụ Minh Họa: Từ A đến Z với Yarn Để bắt đầu với Yarn, mấy đứa cần cài đặt Node.js trước (nếu chưa có). Sau đó, cài Yarn toàn cục (globally) bằng npm (irony nhỉ, nhưng chỉ lần đầu thôi): npm install -g yarn Giờ thì, hãy cùng 'triển' một dự án nhỏ để thấy sức mạnh của Yarn nhé: Bước 1: Khởi tạo dự án (Init Project) Giống như việc tạo một 'ngôi nhà' mới cho code của mấy đứa. Lệnh này sẽ tạo ra file package.json – bản 'lý lịch trích ngang' của dự án. mkdir my-yarn-project cd my-yarn-project yarn init # Hoặc để nhanh hơn, dùng: # yarn init -y Sau khi chạy yarn init, mấy đứa sẽ được hỏi một vài thông tin về dự án. package.json của mấy đứa sẽ trông tương tự thế này: { "name": "my-yarn-project", "version": "1.0.0", "main": "index.js", "license": "MIT" } Bước 2: Thêm thư viện (Add a Package) Giờ muốn thêm một thư viện 'hot hit' như lodash vào dự án? Đơn giản như ăn kẹo: yarn add lodash Yarn sẽ tải lodash về, thêm nó vào mục dependencies trong package.json, và quan trọng hơn là tạo ra file yarn.lock. File này giống như một bản 'kế hoạch chi tiết' ghi lại chính xác phiên bản của mọi thư viện và các thư viện con của chúng. Đảm bảo mọi dev trong team đều dùng đúng một phiên bản, không sợ 'ai đó' cài lệch version gây bug. // package.json (sau khi thêm lodash) { "name": "my-yarn-project", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "lodash": "^4.17.21" } } Bước 3: Cài đặt tất cả thư viện (Install Dependencies) Khi mấy đứa 'clone' một dự án từ GitHub về, hoặc làm việc trong team, mấy đứa chỉ cần chạy lệnh này để Yarn tự động tải tất cả các thư viện cần thiết dựa trên package.json và yarn.lock: yarn install Lệnh này sẽ đọc file yarn.lock và cài đặt chính xác các phiên bản đã được ghi lại. Điều này cực kỳ quan trọng để đảm bảo môi trường phát triển của mọi người là nhất quán. Bước 4: Xóa thư viện (Remove a Package) Không dùng lodash nữa? 'Tiễn' nó đi một cách lịch sự: yarn remove lodash Bước 5: Cập nhật thư viện (Upgrade Packages) Muốn 'lên đời' cho các thư viện để hưởng tính năng mới hoặc vá lỗi bảo mật? yarn upgrade # Hoặc để cập nhật một package cụ thể: # yarn upgrade lodash Bước 6: Chạy script (Run Scripts) Trong package.json, mấy đứa có thể định nghĩa các script tùy chỉnh để tự động hóa công việc (ví dụ: chạy server dev, build dự án). Yarn giúp chạy chúng một cách dễ dàng: // package.json { "name": "my-yarn-project", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "lodash": "^4.17.21" }, "scripts": { "start": "node index.js", "test": "echo \"No tests specified\" && exit 0" } } Để chạy script start: yarn start 3. Mẹo 'Hack' Năng Suất với Yarn (Best Practices) Là một dev 'có gu', mấy đứa nên nắm vài 'tip' sau để dùng Yarn sao cho 'chuẩn bài': Luôn commit yarn.lock vào Git: Đây là 'hợp đồng' đảm bảo mọi thành viên trong team, hay cả CI/CD pipeline, đều cài đặt chính xác cùng một phiên bản của tất cả các dependency. Đừng bao giờ bỏ qua nó trong .gitignore nhé! Hiểu dependencies vs devDependencies: dependencies: Là những thư viện cần thiết để ứng dụng của mấy đứa chạy trong môi trường production (ví dụ: React, Express). devDependencies: Là những thư viện chỉ cần trong quá trình phát triển (ví dụ: Babel, Webpack, Jest để test). Dùng yarn add <package> để thêm vào dependencies. Dùng yarn add <package> --dev (hoặc -D) để thêm vào devDependencies. Kiểm tra phiên bản cũ: Dùng yarn outdated để xem những thư viện nào đã có phiên bản mới hơn. Giúp mấy đứa luôn 'bắt trend' và vá lỗi kịp thời. Dọn dẹp cache: Thỉnh thoảng, Yarn lưu trữ các gói đã tải về trong cache để cài đặt nhanh hơn. Nếu gặp vấn đề hoặc muốn giải phóng dung lượng, có thể dọn dẹp: yarn cache clean Workspaces (cho dân 'pro'): Nếu mấy đứa làm việc với các dự án lớn, có nhiều package con trong cùng một repo (monorepo), Yarn Workspaces là 'vũ khí' lợi hại giúp quản lý chúng một cách hiệu quả. Nó cho phép một yarn.lock duy nhất cho toàn bộ monorepo, giúp đồng bộ phiên bản và tối ưu cài đặt. 4. Góc Nhìn Học Thuật (Harvard Style, Dễ Hiểu Thôi!) Từ góc độ kỹ thuật sâu hơn, sự ra đời của Yarn không chỉ là việc tạo ra một công cụ mới, mà là một phản ứng tự nhiên trước những thách thức cố hữu trong việc quản lý hệ thống phần mềm phức tạp. Tại sao các package manager lại quan trọng đến vậy? Tính xác định (Determinism): Yếu tố then chốt mà yarn.lock mang lại. Trong một môi trường phát triển phần mềm hiện đại, việc đảm bảo rằng một dự án có thể được xây dựng và chạy một cách nhất quán trên mọi máy tính, mọi môi trường (phát triển, thử nghiệm, sản xuất) là cực kỳ quan trọng. yarn.lock đóng vai trò là một 'bản kê khai' chi tiết, cố định phiên bản của tất cả các dependency, bao gồm cả các dependency lồng nhau (transitive dependencies). Điều này loại bỏ 'hiệu ứng domino' khi một dependency nhỏ thay đổi phiên bản gây ra lỗi không mong muốn ở các phần khác của hệ thống. Hiệu suất (Performance): Yarn đã tối ưu hóa quá trình cài đặt bằng cách thực hiện các thao tác song song (parallel operations) và sử dụng cơ chế caching hiệu quả. Thay vì tải từng gói một cách tuần tự, Yarn có thể tải nhiều gói cùng lúc. Cơ chế cache cục bộ cho phép Yarn không cần tải lại các gói đã có, giúp tăng tốc độ cài đặt đáng kể, đặc biệt khi làm việc offline hoặc với các dự án có nhiều dependency. Tính toàn vẹn và bảo mật (Integrity & Security): Yarn sử dụng checksum (hàm băm) để xác minh tính toàn vẹn của các gói đã tải về. Điều này đảm bảo rằng gói không bị hỏng hoặc bị can thiệp độc hại trong quá trình tải xuống. Một lớp bảo vệ quan trọng chống lại các mối đe dọa tiềm tàng từ các nguồn bên ngoài. Tóm lại, Yarn không chỉ là một công cụ tiện lợi; nó là một giải pháp kỹ thuật được thiết kế để giải quyết các vấn đề phức tạp về tính nhất quán, hiệu suất và độ tin cậy trong quản lý dependency của các dự án JavaScript quy mô lớn. Nó là minh chứng cho việc cộng đồng phát triển luôn tìm cách cải tiến để xây dựng phần mềm tốt hơn, nhanh hơn và an toàn hơn. 5. Dự Án 'Khủng' Nào Đang Dùng Yarn? Mấy đứa cứ yên tâm là Yarn không phải 'hàng test' đâu nhé. Nó được tạo ra bởi Facebook (nay là Meta) và được sử dụng rộng rãi trong nội bộ của họ cho rất nhiều dự án lớn. Ngoài ra, nhiều công ty công nghệ và dự án mã nguồn mở khác cũng đã 'chọn mặt gửi vàng' cho Yarn, ví dụ như: Google: Một số dự án của Google cũng tận dụng Yarn. Airbnb: Nền tảng đặt phòng nổi tiếng này cũng sử dụng Yarn trong stack công nghệ của họ. Microsoft: Một số dự án và công cụ phát triển của Microsoft cũng tích hợp Yarn. Create React App: Công cụ chính thức để khởi tạo dự án React cũng đề xuất và hỗ trợ Yarn. Điều này chứng tỏ Yarn đã được 'kiểm chứng qua lửa' trong các môi trường sản xuất thực tế, nơi mà hiệu suất và sự ổn định là yếu tố sống còn. 6. Khi Nào Nên 'Flex' Yarn? Thử nghiệm của thầy Creyt và kinh nghiệm thực tế cho thấy, Yarn là lựa chọn tuyệt vời cho các trường hợp sau: Dự án mới tinh: Bắt đầu một dự án Node.js hoặc JavaScript mới? Yarn là một lựa chọn hiện đại và tối ưu. Cần sự nhất quán cao: Làm việc trong một team lớn, hoặc dự án có CI/CD pipeline phức tạp, nơi mọi bản build phải giống hệt nhau. yarn.lock sẽ là 'vị cứu tinh'. Ưu tiên tốc độ: Nếu mấy đứa cần cài đặt dependency nhanh chóng, đặc biệt khi làm việc offline hoặc với nhiều dự án khác nhau, cache của Yarn sẽ phát huy tác dụng. Monorepo: Khi dự án của mấy đứa phát triển thành một monorepo với nhiều package con, Yarn Workspaces sẽ giúp quản lý dễ dàng hơn rất nhiều so với việc quản lý từng package.json riêng lẻ. Đang dùng NPM và muốn thử cái mới: Nếu mấy đứa đã quen với NPM nhưng muốn trải nghiệm một công cụ hiện đại hơn với hiệu suất tốt hơn, Yarn rất đáng để thử. Hầu hết các lệnh đều có cú pháp tương tự, nên việc chuyển đổi không quá 'shock' đâu. Tóm lại, Yarn không chỉ là một công cụ quản lý gói; nó là một nền tảng vững chắc giúp mấy đứa xây dựng và duy trì các ứng dụng JavaScript một cách hiệu quả, đáng tin cậy và 'cool ngầu' hơn. Hãy 'add' Yarn vào 'skill set' của mình ngay hôm nay! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

29 Đọc tiếp
npm: Cửa Hàng Ứng Dụng Của Dân Dev!
18/03/2026

npm: Cửa Hàng Ứng Dụng Của Dân Dev!

Chào các 'senior-to-be' của anh Creyt! Hôm nay, chúng ta sẽ bóc tách một khái niệm mà nếu không có nó, thế giới Node.js của chúng ta sẽ 'toang' như cái deadline không kịp vậy: npm (Node Package Manager). 1. npm là gì và để làm gì? (Giải mã cho Gen Z) Tưởng tượng thế này nhé: mấy đứa muốn làm món lẩu thái chuẩn vị. Thay vì phải tự đi trồng sả, ớt, chanh, mua xương về hầm nước dùng từ con số 0, thì mấy đứa chỉ cần ra siêu thị, mua đúng cái gói gia vị lẩu thái 'full combo' về đổ vào là xong. npm chính là cái 'siêu thị' đó, hoặc nói theo Gen Z là cái 'App Store/CH Play' của dân code vậy. npm là viết tắt của Node Package Manager. Nó là một công cụ giúp mấy đứa quản lý, tải về và chia sẻ các 'gói' code (package/module) do cộng đồng lập trình viên trên toàn thế giới viết sẵn. Nói cách khác, nó là 'người quản gia' lo liệu tất tần tật việc cài đặt, cập nhật, gỡ bỏ các thư viện mà dự án Node.js của mấy đứa cần. Vậy nó để làm gì? Đơn giản là để mấy đứa không phải 'phát minh lại bánh xe' mỗi khi bắt đầu một dự án mới. Thay vì ngồi code lại cái hàm mã hóa phức tạp, cái thư viện gửi email, hay cái framework web từ con số 0, npm giúp mấy đứa 'tái sử dụng' code của người khác. Tiết kiệm thời gian, công sức, và quan trọng là ít bug hơn vì code đó đã được hàng ngàn người dùng và kiểm chứng rồi. 2. Code Ví Dụ Minh Hoạ Rõ Ràng (Thực chiến là đây!) Khi cài đặt Node.js, npm sẽ tự động được cài đặt theo. Mấy đứa có thể kiểm tra phiên bản bằng lệnh: npm -v Giờ thì đi vào các lệnh cơ bản mà mấy đứa sẽ dùng 'như cơm bữa': a. npm init: Khai sinh dự án Đây là bước đầu tiên để 'khai sinh' dự án của mấy đứa. Nó sẽ tạo ra file package.json – giống như chứng minh thư, lý lịch trích ngang của project vậy, chứa thông tin về tên, phiên bản, mô tả, các lệnh script và đặc biệt là danh sách các thư viện mà dự án phụ thuộc. mkdir my-node-app cd my-node-app npm init -y Lệnh -y sẽ tự động chấp nhận các giá trị mặc định, giúp tạo package.json nhanh hơn. Nếu không có -y, npm sẽ hỏi mấy đứa từng thông tin một. File package.json của mấy đứa sẽ trông giống vầy: { "name": "my-node-app", "version": "1.0.0", "description": "Một ứng dụng Node.js siêu cấp pro", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "Creyt", "license": "ISC" } b. npm install <package>: Thêm 'gia vị' cho dự án Khi muốn thêm một 'gia vị' mới vào món ăn (dự án) của mình, ví dụ, mấy đứa muốn làm web API thì cần thư viện Express. Đơn giản là: npm install express Sau lệnh này, mấy đứa sẽ thấy: Một thư mục mới tên là node_modules xuất hiện. Đây là cái 'kho' chứa tất cả gói đã tải về (bao gồm cả Express và các thư viện mà Express phụ thuộc). File package.json của mấy đứa sẽ được cập nhật thêm mục dependencies: { "name": "my-node-app", "version": "1.0.0", "description": "Một ứng dụng Node.js siêu cấp pro", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "Creyt", "license": "ISC", "dependencies": { "express": "^4.18.2" // Thư viện Express đã được thêm vào } } Một file mới tên là package-lock.json cũng sẽ được tạo ra. Đây là 'biên bản ghi nhớ' chính xác phiên bản của từng gói (và các gói phụ thuộc của chúng) tại thời điểm cài đặt. Nó đảm bảo mọi người trong team khi chạy npm install đều dùng cùng một phiên bản thư viện, tránh lỗi 'chạy được trên máy tao mà không chạy được trên máy mày'. c. npm install: 'Đồng bộ' dự án Khi mấy đứa clone một dự án Node.js từ GitHub về, thư mục node_modules thường không được đẩy lên để tiết kiệm dung lượng. Để cài đặt tất cả các thư viện mà dự án cần (dựa trên package.json và package-lock.json), mấy đứa chỉ cần chạy: npm install d. npm uninstall <package>: Loại bỏ 'gia vị' không cần thiết Không thích 'gia vị' này nữa, vứt đi. Lệnh này sẽ gỡ bỏ gói khỏi node_modules và xóa nó khỏi package.json: npm uninstall express e. npm install <package> --save-dev (hoặc -D): 'Gia vị' cho nhà bếp Có những gói chỉ dùng khi mấy đứa đang 'nấu ăn' (phát triển) mà không cần khi 'ăn' (chạy ứng dụng trên production). Ví dụ: nodemon để tự động khởi động lại server mỗi khi có thay đổi code, hoặc các thư viện test như jest. npm install nodemon --save-dev # Hoặc viết tắt: npm install jest -D Các gói này sẽ được thêm vào mục devDependencies trong package.json: { "name": "my-node-app", "version": "1.0.0", "description": "Một ứng dụng Node.js siêu cấp pro", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "Creyt", "license": "ISC", "dependencies": { "express": "^4.18.2" }, "devDependencies": { "nodemon": "^2.0.22" } } 3. Mẹo Hay & Best Practices (Công thức của các 'master chef') Hiểu rõ dependencies và devDependencies: Đừng nhầm lẫn! dependencies là những thứ dự án cần để chạy (ví dụ: Express, React), còn devDependencies là những thứ cần để phát triển (ví dụ: Nodemon, Jest, Webpack, Babel). Việc phân biệt giúp tối ưu kích thước gói deploy và thời gian cài đặt trên môi trường production. Semantic Versioning (SemVer): Cái ^ và ~ trong package.json không phải để làm cảnh đâu nhé. Nó thể hiện cách các bản cập nhật được chấp nhận: ^ (caret): Cho phép cập nhật lên các phiên bản minor và patch mới nhất mà vẫn giữ nguyên phiên bản major. Ví dụ: ^4.18.2 sẽ chấp nhận 4.19.0 hoặc 4.18.5, nhưng không chấp nhận 5.0.0. Đây là mặc định của npm install. ~ (tilde): Chỉ cho phép cập nhật lên các phiên bản patch mới nhất mà vẫn giữ nguyên phiên bản major và minor. Ví dụ: ~4.18.2 sẽ chấp nhận 4.18.5 nhưng không chấp nhận 4.19.0. Hiểu để tránh 'sập tiệm' vì một bản update thư viện không tương thích ngược! npm audit: Giống như kiểm tra an ninh thực phẩm vậy. Lệnh này giúp phát hiện lỗ hổng bảo mật trong các gói mấy đứa đang dùng và đề xuất cách khắc phục. Luôn chạy định kỳ! npm audit ``` npm update: Luôn cập nhật 'gia vị' để có bản mới nhất, vá lỗi và thêm tính năng. Để cập nhật tất cả các gói đã cài đặt: npm update ``` npx: Công cụ này đi kèm với npm từ phiên bản 5.2 trở đi, cho phép mấy đứa chạy các package CLI mà không cần cài đặt toàn cục. Tiện lợi cực kỳ cho các tool dùng một lần như create-react-app hay vue-cli. npx create-react-app my-react-app ``` Lệnh này sẽ tải create-react-app về, chạy nó, và sau đó xóa đi, không làm ô nhiễm môi trường global của mấy đứa. 4. Góc Học Thuật Sâu (Harvard Style, Dễ Hiểu Tuyệt Đối) Về bản chất, npm giải quyết vấn đề 'phụ thuộc' (dependency hell) – một cơn ác mộng trong phát triển phần mềm. Khi mấy đứa cài một gói (ví dụ: Express), gói đó lại có thể phụ thuộc vào gói khác (ví dụ: body-parser), và cứ thế tạo thành một 'cây phụ thuộc' phức tạp. npm có thuật toán thông minh để: Phân giải phụ thuộc (Dependency Resolution): Tìm ra phiên bản phù hợp nhất của mỗi gói để tất cả các phụ thuộc đều được thỏa mãn mà không xung đột. Tối ưu hóa cài đặt (Installation Optimization): Tránh cài đặt trùng lặp các gói nếu chúng được yêu cầu bởi nhiều thư viện khác nhau. Đảm bảo tính nhất quán (Consistency): Với package-lock.json, nó đảm bảo môi trường phát triển của cả team là nhất quán, ai cũng chạy cùng một bộ thư viện với cùng một phiên bản. Đây chính là xương sống của modular programming (lập trình module), nơi chúng ta xây dựng ứng dụng từ những viên gạch nhỏ, độc lập, dễ bảo trì và tái sử dụng. npm không chỉ là một công cụ, nó là một triết lý cho phép cộng đồng cùng nhau xây dựng và chia sẻ kiến thức thông qua code. 5. Ví Dụ Thực Tế Ứng Dụng/Website Đã Ứng Dụng Hầu hết các trang web, ứng dụng hiện đại dùng Node.js đều sống nhờ npm. Mấy đứa có thể kể tên bất kỳ framework/library JavaScript nào phổ biến, và chắc chắn nó đang được quản lý bởi npm: Frontend Frameworks/Libraries: React (Facebook), Angular (Google), Vue.js, Next.js, Nuxt.js, Svelte. Các dự án này đều dùng npm để cài đặt các gói cần thiết và quản lý build scripts. Backend Frameworks: Express.js, NestJS, Koa.js. Đây là xương sống của các API và server-side logic, tất cả đều dựa vào npm để quản lý các module. Build Tools & Bundlers: Webpack, Babel, Gulp, Grunt. Những công cụ này giúp chuyển đổi, tối ưu hóa code JavaScript, CSS, hình ảnh cho môi trường web, và chúng được cài đặt, chạy thông qua npm. Testing Frameworks: Jest, Mocha, Cypress. Dùng để viết và chạy các bài kiểm thử cho ứng dụng, cũng được quản lý bởi npm. Nói chung, nếu mấy đứa đang lướt TikTok, Facebook, xem Netflix, hay dùng các ứng dụng web phức tạp, rất có thể đâu đó trong backend hoặc frontend của chúng có một 'thằng' npm đang làm việc chăm chỉ. 6. Thử Nghiệm Đã Từng & Hướng Dẫn Nên Dùng Cho Case Nào Anh Creyt đã từng chứng kiến cảnh mấy đứa sinh viên mới ra trường tự đi copy-paste từng đoạn code từ Stack Overflow về để giải quyết một vấn đề đơn giản, trong khi chỉ cần một lệnh npm install <package> là xong. Đó là lý do vì sao hiểu và dùng npm là bắt buộc. Nên dùng npm cho các case sau: Bắt đầu một dự án Node.js/JavaScript mới: Luôn luôn npm init đầu tiên để tạo package.json. Thêm thư viện hoặc framework vào dự án: Ví dụ, muốn dùng React, Axios để gọi API, Lodash để xử lý dữ liệu: npm install react axios lodash. Xây dựng công cụ dòng lệnh (CLI tool): Các package như commander, yargs giúp mấy đứa tạo CLI tool chuyên nghiệp, và chúng được quản lý bởi npm. Quản lý các script tự động: File package.json có mục scripts. Mấy đứa có thể định nghĩa các lệnh như npm run start, npm run test, npm run build để tự động hóa các tác vụ lặp đi lặp lại. Khi làm việc nhóm: package-lock.json đảm bảo mọi người trong team có môi trường phát triển giống hệt nhau, tránh lỗi do khác biệt phiên bản thư viện. Tóm lại: Nếu mấy đứa đụng đến JavaScript ngoài trình duyệt, đặc biệt là với Node.js, chắc chắn sẽ đụng đến npm. Nó không chỉ là một công cụ, nó là cả một 'hệ sinh thái' giúp chúng ta build phần mềm nhanh hơn, an toàn hơn, và hiệu quả hơn. Nắm chắc nó, mấy đứa sẽ tự tin 'tung hoành' trong thế giới dev! Chúc mấy đứa code vui vẻ và luôn 'tải' được những gói xịn xò nhất! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

45 Đọc tiếp
Export Statement: Chia Sẻ Code Như Flex TikTok Trong Node.js
18/03/2026

Export Statement: Chia Sẻ Code Như Flex TikTok Trong Node.js

Chào các Gen Z tương lai của làng code! Anh Creyt đây, hôm nay chúng ta sẽ "bóc tách" một khái niệm mà nghe thì tưởng "sờ-oai" nhưng thực ra lại "chill" cực kỳ trong Node.js: export statement. Tưởng tượng thế này, bạn có một video TikTok triệu view, một "bí kíp" làm đẹp hay một "tutorial" chơi game đỉnh cao. Bạn muốn chia sẻ nó với cả thế giới (hoặc ít nhất là với bạn bè thân thiết). Làm sao để họ xem được mà không cần phải "copy-paste" nguyên cái điện thoại của bạn? Chính xác, bạn export (xuất) nó ra! export statement là gì mà "làm mưa làm gió" trong Node.js? Trong thế giới Node.js, export (cùng với require mà chúng ta sẽ nói sau) chính là "cánh cổng thần kỳ" giúp bạn chia sẻ code giữa các file với nhau. Nó giống như việc bạn đóng gói những "tuyệt chiêu" lập trình của mình (có thể là một hàm tính toán, một biến quan trọng, hay cả một class "xịn xò") vào một cái hộp, dán nhãn và để ở nơi mà các file khác có thể đến lấy về dùng. Để làm gì ư? Đơn giản là để codebase của bạn không bị "toxic" vì lộn xộn! Thay vì nhồi nhét tất cả code vào một file duy nhất dài ngoằng như sớ Táo Quân, bạn có thể chia nhỏ chúng ra thành các module (các file riêng biệt) theo chức năng. Mỗi module là một "chuyên gia" trong lĩnh vực của nó: file này lo tính toán, file kia lo xử lý dữ liệu người dùng, file nọ lo kết nối database. Khi cần, bạn chỉ việc "gọi tên" module đó và dùng cái mà nó export ra. Lợi ích "nhãn tiền" của việc này là: Tái sử dụng (Reusability): Viết một lần, dùng nhiều nơi. Như mấy cái filter "hot hit" trên Instagram ấy. Dễ bảo trì (Maintainability): Code ngắn gọn, phân chia rõ ràng giúp bạn dễ dàng sửa lỗi hoặc nâng cấp mà không làm "sập" cả hệ thống. Sắp xếp gọn gàng (Organization): Codebase của bạn sẽ "thơm tho" và "sạch sẽ" như tủ quần áo của một fashionista. Trong Node.js, chúng ta chủ yếu dùng hệ thống module CommonJS với cú pháp module.exports và require(). Code Ví Dụ Minh Hoạ: "Bóc phốt" cách export hoạt động Hãy tưởng tượng bạn đang xây dựng một ứng dụng tính toán "siêu cấp vũ trụ". 1. Export một thứ duy nhất (Single Export): Bạn có một hàm add (cộng) rất "xịn". Bạn muốn chia sẻ nó. File: math.js function add(a, b) { return a + b; } // "Đóng gói" hàm add và bảo Node.js rằng đây là thứ duy nhất mà file này muốn "export" ra ngoài. module.exports = add; File: app.js (file muốn dùng hàm add) // "Gọi tên" file math.js và "lấy" cái mà nó đã "export" ra. const addFunction = require('./math'); const result = addFunction(5, 3); console.log('5 + 3 =', result); // Output: 5 + 3 = 8 Ở đây, module.exports = add; nghĩa là "file math.js này chỉ có một giá trị chính để xuất ra, và đó chính là hàm add." 2. Export nhiều thứ cùng lúc (Multiple Exports - Object): Giờ bạn có thêm hàm subtract (trừ) nữa. Bạn muốn xuất cả hai. File: utils.js function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } // "Đóng gói" cả hai hàm vào một object và "export" object đó. module.exports = { add: add, // Hoặc viết tắt là 'add' (ES6 shorthand property names) subtract: subtract }; // Một cách khác, dùng 'exports' (là một reference tới module.exports): // exports.add = add; // exports.subtract = subtract; // LƯU Ý: Không gán trực tiếp 'exports = ...' vì nó sẽ phá vỡ reference. // Luôn dùng 'module.exports = ...' khi muốn gán một giá trị mới hoàn toàn. File: app.js // "Lấy" các hàm add và subtract từ object đã được export bằng destructuring. const { add, subtract } = require('./utils'); console.log('10 + 4 =', add(10, 4)); // Output: 10 + 4 = 14 console.log('10 - 4 =', subtract(10, 4)); // Output: 10 - 4 = 6 3. Export một Class (Class Export): Bạn đang xây dựng một ứng dụng quản lý người dùng. File: User.js class User { constructor(name, age) { this.name = name; this.age = age; } greet() { return `Hi, I'm ${this.name} and I'm ${this.age} years old.`; } } module.exports = User; File: app.js const User = require('./User'); const user1 = new User('Alice', 25); console.log(user1.greet()); // Output: Hi, I'm Alice and I'm 25 years old. Mẹo vặt của Creyt (Best Practices) để "cày cuốc" hiệu quả: "Keep it Tidy" (Giữ cho nó gọn gàng): Đừng export tràn lan. Chỉ xuất những gì thực sự cần thiết cho các module khác sử dụng. Như bạn chỉ khoe những bức ảnh "xịn" nhất trên Instagram thôi, chứ không phải cả album ảnh chụp màn hình meme đâu. "Name it Right" (Đặt tên chuẩn chỉnh): Tên file module và tên các hàm/biến được export phải rõ ràng, dễ hiểu. Ví dụ, file userController.js nên chứa các hàm xử lý logic liên quan đến người dùng. "Think Small" (Nghĩ nhỏ thôi): Chia nhỏ ứng dụng của bạn thành các module nhỏ, tập trung vào một nhiệm vụ cụ thể. Một module chỉ nên làm một việc, và làm thật tốt (Single Responsibility Principle). Điều này giúp code dễ đọc, dễ kiểm thử và dễ bảo trì hơn rất nhiều. module.exports vs. exports: module.exports là đối tượng thực sự được trả về khi require() một module. Bạn nên dùng nó khi muốn gán một giá trị (hàm, object, class...) duy nhất làm "đầu ra" của module. exports là một biến tham chiếu (reference) tới module.exports. Bạn có thể dùng exports.propertyName = value; để thêm các thuộc tính vào đối tượng được xuất. Tuy nhiên, đừng bao giờ gán exports = someValue; vì nó sẽ phá vỡ tham chiếu và module của bạn sẽ không xuất ra đúng thứ bạn muốn. Cứ nhớ: module.exports là "người chủ", exports là "người giúp việc". Người giúp việc có thể thêm đồ vào nhà (thuộc tính vào object), nhưng không thể đổi chủ nhà được. Góc nhìn Harvard (dễ hiểu tuyệt đối): "Kiến trúc sư" của hệ thống code Từ góc độ học thuật sâu sắc, export statement (cùng với cơ chế module của Node.js) không chỉ là một cú pháp đơn thuần mà còn là nền tảng của kiến trúc phần mềm modular. Nó hiện thực hóa nguyên tắc Separation of Concerns (SoC) – Tách biệt các mối quan tâm. Tức là, mỗi phần của hệ thống chỉ nên chịu trách nhiệm về một khía cạnh cụ thể, giảm thiểu sự phụ thuộc lẫn nhau (low coupling) và tăng tính gắn kết nội bộ (high cohesion). Điều này đặc biệt quan trọng trong các dự án lớn, nơi hàng trăm, hàng ngàn file code cần phải phối hợp nhịp nhàng. Cơ chế module cho phép các nhà phát triển làm việc độc lập trên các phần khác nhau của ứng dụng mà không gây xung đột lớn, đồng thời tạo ra một "thư viện" các thành phần có thể tái sử dụng, đẩy nhanh tốc độ phát triển và cải thiện chất lượng phần mềm. Nó giống như việc xây dựng một thành phố: mỗi đội thợ xây chuyên trách một loại công trình (nhà ở, cầu đường, công viên), và tất cả đều sử dụng chung một kho vật liệu và thiết kế quy hoạch. Lịch sử của JavaScript trên môi trường server (Node.js) đã chứng kiến sự ra đời của CommonJS để giải quyết bài toán module hóa khi mà trình duyệt chưa có cơ chế tương tự. Mặc dù sau này ES Modules (ESM) ra đời và trở thành tiêu chuẩn chung cho cả frontend và backend, CommonJS vẫn là "trái tim" của rất nhiều dự án Node.js hiện có. Ứng dụng thực tế: "Nhà nhà, người người" đều dùng export Bạn có thể thấy export ở khắp mọi nơi trong các ứng dụng/website dùng Node.js: Framework Express.js: Khi bạn định nghĩa các route (đường dẫn API), middleware (các hàm xử lý trước khi request đến route chính) hay controller (logic xử lý request), tất cả đều được export từ các file riêng biệt và require vào file app.js chính. routes/userRoutes.js export các router cho người dùng. controllers/userController.js export các hàm xử lý logic cho người dùng. Các thư viện tiện ích (Utility Libraries): Nếu bạn từng dùng lodash hay các thư viện tương tự, bạn sẽ thấy chúng export ra hàng loạt các hàm hữu ích để bạn dùng. Microservices: Trong kiến trúc microservices, mỗi service nhỏ có thể là một ứng dụng Node.js riêng biệt, và các module bên trong mỗi service sẽ export/require lẫn nhau để hoạt động. Bất kỳ dự án Node.js lớn nào: Từ các backend của mạng xã hội (Facebook, Instagram - dù họ dùng nhiều ngôn ngữ khác nhau nhưng nguyên lý module hóa là tương tự), các nền tảng thương mại điện tử (Amazon, Shopee), đến các ứng dụng chat realtime, game server... tất cả đều dựa vào cơ chế module để tổ chức code. Thử nghiệm và Nên dùng cho case nào? Nên dùng export khi nào? Khi bạn muốn chia sẻ một hàm, biến, class hoặc đối tượng từ một file này sang file khác. Khi bạn muốn tái cấu trúc (refactor) một file code lớn thành nhiều file nhỏ hơn, dễ quản lý hơn. Khi bạn muốn tạo ra các thư viện tiện ích riêng cho dự án của mình. Khi bạn xây dựng API với các tầng logic (routes, controllers, services, models) rõ ràng. Thử nghiệm ngay: Tạo một "hộp công cụ" nhỏ: Viết một file utilities.js chứa các hàm như getRandomNumber(), formatDate(), capitalizeString(). export chúng ra và thử require vào file main.js để sử dụng. Xây dựng một Class và Export: Tạo file Vehicle.js với một class Vehicle có constructor và vài method. export nó ra và trong app.js, require và tạo một vài đối tượng Vehicle. Refactor một file "khổng lồ": Nếu bạn có một file index.js nào đó dài 500 dòng, hãy thử chia nó thành 3-4 file nhỏ hơn dựa trên chức năng, sau đó dùng export/require để kết nối chúng lại. Bạn sẽ thấy codebase của mình "thở phào nhẹ nhõm" ngay! Nhớ nhé các Gen Z, export statement không chỉ là cú pháp, nó là một "superpower" giúp bạn xây dựng những ứng dụng Node.js mạnh mẽ, gọn gàng và dễ dàng mở rộng. Hãy "flex" sức mạnh này trong mọi dự án của mình! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

40 Đọc tiếp
Import Statement Node.js: 'Triệu Hồi Sức Mạnh' cho code Gen Z
18/03/2026

Import Statement Node.js: 'Triệu Hồi Sức Mạnh' cho code Gen Z

Này các 'dev-er' tương lai của Creyt! Hôm nay chúng ta sẽ 'triệu hồi' một khái niệm cực kỳ 'sức mạnh' mà không có nó, code của các bạn sẽ 'nát như tương' – đó chính là import statement trong Node.js. Nghe có vẻ 'hàn lâm' nhưng thực ra nó 'chill' hơn các bạn nghĩ nhiều! 1. import statement là gì mà 'hot' vậy? Tưởng tượng thế này nhé: Các bạn đang làm một project 'khủng long' với hàng trăm, hàng nghìn dòng code. Nếu các bạn cứ viết tất cả mọi thứ vào một file duy nhất thì 'thôi rồi lượm ơi', tìm bug thì 'khóc một dòng sông', nâng cấp thì 'đau tim' luôn. import statement sinh ra để giải cứu chúng ta khỏi cái 'ác mộng' đó. import chính là cái 'chìa khóa thần kỳ' giúp các bạn 'mượn đồ' từ những file khác, những module khác. Thay vì phải tự tay code lại mọi thứ, các bạn chỉ cần 'triệu hồi' những chức năng, những biến mà người khác (hoặc chính bạn ở một file khác) đã viết và export ra. Nó giống như việc các bạn có một team siêu anh hùng, mỗi người chuyên một việc. Khi cần sức mạnh của Thor, bạn chỉ cần 'triệu hồi' Thor chứ không cần tự biến mình thành Thor. Trong Node.js hiện đại, khi nói đến import, chúng ta đang nói về ES Modules (ECMAScript Modules) – chuẩn module mới nhất của JavaScript. Nó giúp code của bạn trở nên: Sạch sẽ hơn: Mỗi file chỉ làm một nhiệm vụ cụ thể. Dễ đọc hơn: Dễ hiểu luồng logic của ứng dụng. Dễ bảo trì hơn: Sửa một phần không ảnh hưởng đến toàn bộ. Dễ tái sử dụng hơn: Viết một lần, dùng muôn nơi. 2. Code Ví Dụ Minh Họa: 'Triệu Hồi' như thế nào? Để dùng import trong Node.js, điều quan trọng đầu tiên là các bạn phải 'bật chế độ' ES Modules cho project của mình. Đơn giản thôi, mở file package.json và thêm dòng này vào: { "name": "my-awesome-project", "version": "1.0.0", "type": "module", "main": "app.js", "scripts": { "start": "node app.js" } } Khi đã có "type": "module", Node.js sẽ hiểu rằng các file .js trong project của bạn sẽ dùng cú pháp ES Modules (import/export) thay vì CommonJS (require/module.exports). Bây giờ, hãy tạo hai file: utils.js (chứa các hàm tiện ích) và app.js (file chính sẽ sử dụng các hàm đó). File: utils.js (File này sẽ 'export' ra các chức năng) // utils.js // Export named: Giống như bạn có nhiều siêu năng lực, và bạn muốn chia sẻ từng cái một export const PI = 3.14159; export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } // Export default: Giống như bạn có một siêu anh hùng chính của team, mặc định ai cũng biết const multiply = (a, b) => a * b; export default multiply; File: app.js (File này sẽ 'import' và sử dụng các chức năng) // app.js // Import named: Gọi đúng tên siêu năng lực bạn cần import { PI, add } from './utils.js'; // Import default: Gọi siêu anh hùng mặc định. Có thể đặt tên tùy ý (ở đây là 'mathMultiply') import mathMultiply from './utils.js'; // Import tất cả các named exports dưới dạng một object: Giống như bạn gọi cả team siêu anh hùng về import * as utils from './utils.js'; console.log('Giá trị của PI:', PI); // Output: Giá trị của PI: 3.14159 console.log('Tổng 5 + 3:', add(5, 3)); // Output: Tổng 5 + 3: 8 console.log('Tích 4 * 6 (default export):', mathMultiply(4, 6)); // Output: Tích 4 * 6 (default export): 24 // Sử dụng các hàm từ import * as utils console.log('Hiệu 10 - 2:', utils.subtract(10, 2)); // Output: Hiệu 10 - 2: 8 console.log('PI từ utils object:', utils.PI); // Output: PI từ utils object: 3.14159 Để chạy app.js, các bạn chỉ cần gõ lệnh: node app.js Và 'boom!', các bạn sẽ thấy kết quả 'ngon lành cành đào' hiện ra trên console. 3. Mẹo (Best Practices) để import 'chuẩn không cần chỉnh' Anh Creyt có vài 'tip & trick' bỏ túi để các bạn 'combat' với import một cách 'pro' nhất: Nhất quán một phong cách: Trong một project, hãy thống nhất dùng import (ES Modules) hoặc require (CommonJS). Đừng 'nửa nạc nửa mỡ' kẻo 'tẩu hỏa nhập ma' đó! Đối với project mới, cứ ES Modules mà 'triển' nhé. Chỉ import những gì cần: Đừng có 'tham lam' import * as xyz nếu bạn chỉ cần một, hai hàm. Việc import cụ thể import { tenHam } from './file.js' giúp code của bạn gọn gàng hơn và quan trọng là giúp các bundler (như Webpack, Vite) thực hiện 'tree-shaking' (loại bỏ code không dùng) hiệu quả hơn, làm cho ứng dụng của bạn 'nhẹ tênh' hơn. Đổi tên khi cần (as): Nếu có hai hàm cùng tên từ hai file khác nhau, hoặc tên hàm hơi dài dòng, hãy dùng as để đổi tên: import { someLongFunctionName as slf } from './module.js'; Sắp xếp import: Để code 'ngăn nắp' như phòng của 'idol', hãy nhóm các import lại: Core modules (ví dụ: import fs from 'node:fs';) Third-party modules (ví dụ: import express from 'express';) Local modules (ví dụ: import { myFunction } from './my-local-file.js';) Tránh 'vòng lặp luẩn quẩn' (Circular Dependencies): Đừng để file A import file B, rồi file B lại import file A. Nó sẽ tạo ra một vòng lặp vô tận và 'sập nguồn' ứng dụng của bạn đó. Nhớ .js ở cuối: Khi import các file local, trong ES Modules, bạn phải chỉ rõ phần mở rộng .js (hoặc .mjs, .mts). Ví dụ: import { func } from './myFile.js'; chứ không phải import { func } from './myFile';. Đây là một điểm khác biệt lớn so với CommonJS. 4. Góc 'Harvard': Vì sao 'Modular Programming' lại quan trọng? Từ góc độ học thuật mà nói, import statement không chỉ là một cú pháp đơn thuần, mà nó là 'xương sống' của Modular Programming (Lập trình mô-đun) – một trong những nguyên tắc thiết kế phần mềm cốt lõi. Hãy nghĩ về một chiếc xe hơi. Nó không phải là một khối kim loại duy nhất, mà là tập hợp của nhiều mô-đun: động cơ, hệ thống phanh, hệ thống điện, v.v. Mỗi mô-đun có một chức năng riêng biệt, được thiết kế độc lập nhưng có thể 'giao tiếp' với các mô-đun khác thông qua các 'giao diện' (API) rõ ràng. Trong lập trình, import cho phép chúng ta: Phân tách mối quan tâm (Separation of Concerns): Mỗi file/module chỉ tập trung vào một nhiệm vụ cụ thể. Điều này giúp giảm độ phức tạp, dễ dàng kiểm thử và sửa lỗi từng phần. Tính tái sử dụng (Reusability): Khi bạn có một hàm tính toán 'xịn sò' ở utils.js, bạn có thể import nó vào bất kỳ đâu mà không cần viết lại. Giống như bạn có một công thức nấu ăn ngon, bạn dùng nó cho mọi bữa tiệc vậy. Dễ bảo trì (Maintainability): Nếu có lỗi ở hàm add, bạn chỉ cần vào utils.js sửa, không cần 'đụng chạm' đến các file khác. Khả năng mở rộng (Scalability): Khi dự án lớn lên, bạn có thể dễ dàng thêm module mới mà không làm ảnh hưởng đến cấu trúc hiện có. ES Modules còn có một lợi thế lớn là static analysis (phân tích tĩnh). Tức là, các công cụ có thể biết được những module nào được import vào một file ngay cả trước khi code được chạy. Điều này mở ra cánh cửa cho các tối ưu hóa mạnh mẽ như tree-shaking (loại bỏ code chết) và code splitting (chia nhỏ code để tải hiệu quả hơn), giúp ứng dụng của bạn 'bay' nhanh hơn trên trình duyệt. 5. Ứng dụng thực tế: Ai đang 'xài' import? Nói thật là, hầu hết các ứng dụng và website 'đỉnh cao' mà các bạn đang dùng hàng ngày đều 'xài' import (hoặc require ở các dự án cũ) đó. Từ những website thương mại điện tử lớn, mạng xã hội, cho đến các công cụ phát triển phần mềm. Các framework Node.js: Như Express.js, NestJS, Next.js (khi chạy ở phía server) đều sử dụng hệ thống module để tổ chức code của họ. Mỗi controller, service, model... đều là một module riêng biệt được import vào khi cần. Các thư viện UI/UX: React, Vue, Angular – tất cả đều dựa vào import để bạn có thể dùng các component, hook, service từ các thư viện đó hoặc từ các file bạn tự tạo. Các công cụ build/bundler: Webpack, Vite, Rollup... chúng 'ngốn' các import statement của bạn để tạo ra một bundle cuối cùng hiệu quả nhất cho trình duyệt. Bất cứ khi nào bạn thấy import React from 'react'; hay import { useState } from 'react'; trong các project frontend, đó chính là import statement đang 'làm nhiệm vụ' đấy. 6. Thử nghiệm và Nên dùng cho case nào? Anh Creyt đã từng 'chinh chiến' qua cả thời require 'thống trị' và bây giờ là thời 'hoàng kim' của import. Mỗi cái có ưu nhược điểm riêng, nhưng xu hướng rõ ràng là import. Nếu bạn đang làm dự án Node.js mới toanh: 'Chơi' liền ES Modules (import) bằng cách thêm "type": "module" vào package.json. Đây là tương lai, là tiêu chuẩn mới, và nó mang lại nhiều lợi ích về tối ưu hóa và cú pháp hiện đại. Nếu bạn đang làm việc với một dự án Node.js cũ: Rất có thể nó đang dùng require. Trong trường hợp này, hãy tiếp tục dùng require để tránh 'phá vỡ' cấu trúc hiện có. Việc chuyển đổi từ CommonJS sang ES Modules có thể hơi 'khoai' nếu project lớn, cần cân nhắc kỹ lưỡng. Sử dụng import() động (Dynamic Import): Đôi khi bạn chỉ muốn tải một module khi thực sự cần nó (ví dụ: một thư viện nặng chỉ dùng cho một tính năng ít khi được truy cập). Khi đó, bạn có thể dùng import('./path/to/module.js') như một hàm trả về Promise. Nó giúp ứng dụng của bạn khởi động nhanh hơn và tải tài nguyên hiệu quả hơn. // Dynamic Import example in Node.js async function loadAndUseHeavyModule() { if (userClicksButton) { // Chỉ tải khi người dùng thực hiện hành động này const { someHeavyFunction } = await import('./heavyModule.js'); console.log(someHeavyFunction()); } } Tóm lại, import statement không chỉ là một cú pháp, nó là một 'triết lý' về cách chúng ta tổ chức và xây dựng phần mềm. Nắm vững nó, các bạn sẽ có trong tay 'siêu năng lực' để tạo ra những ứng dụng 'đỉnh của chóp', 'mượt mà' và dễ bảo trì. Giờ thì, 'go forth and code', các 'dev-er' tương lai của anh Creyt! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

49 Đọc tiếp
Require() trong Node.js: Cổng Dịch Chuyển Mã Nguồn Của GenZ
18/03/2026

Require() trong Node.js: Cổng Dịch Chuyển Mã Nguồn Của GenZ

Chào các "coder nhí" thế hệ Z! Anh là Creyt, giảng viên lập trình lão luyện, và hôm nay chúng ta sẽ "mổ xẻ" một khái niệm siêu "cool" nhưng đôi khi lại bị hiểu lầm: require() trong Node.js. Nghe có vẻ "old-school" so với import (ESM) đúng không? Nhưng tin anh đi, không hiểu require() thì coi như bạn bỏ lỡ một "mảnh ghép" quan trọng trong lịch sử và cả những dự án "lão làng" nữa đấy! 1. require() là gì mà "hot" thế? (Giải thích khái niệm theo hướng GenZ) Trong thế giới lập trình, không ai "full stack" đến mức tự tay viết hết mọi thứ từ A đến Z. Bạn cần một hàm để tính tổng? Bạn cần một thư viện để xử lý ngày tháng? Hay bạn cần kết nối database? Thay vì tự viết lại từ đầu, chúng ta thường "mượn" những đoạn code đã được người khác viết sẵn và đóng gói cẩn thận. Đó chính là ý nghĩa của Module. Hãy tưởng tượng thế này: Bạn đang "build" một "siêu app" TikTok phiên bản của riêng mình. Bạn cần tính năng chỉnh sửa video, tính năng filter "ảo diệu", tính năng chat "nhanh như chớp". Mỗi tính năng đó là một "chuyên gia" riêng biệt, được đóng gói trong một "hộp công cụ". require() chính là cái "điện thoại gọi chuyên gia" của bạn. Bạn muốn "chuyên gia filter"? Gọi require('filter-module'). Bạn muốn "chuyên gia chat"? Gọi require('chat-module'). Nó sẽ "triệu hồi" ngay lập tức "chuyên gia" đó (cùng với tất cả "đồ nghề" của họ) vào ứng dụng của bạn để bạn có thể dùng ngay lập tức. "Ngon" chưa? Nói một cách "học thuật" hơn, require() là một hàm toàn cục trong Node.js (thuộc hệ thống module CommonJS) dùng để tải và import các module vào phạm vi hiện tại của file JavaScript. Nó cho phép bạn chia nhỏ code thành các file độc lập, dễ quản lý, dễ tái sử dụng hơn. 2. Code Ví Dụ Minh Hoạ Rõ Ràng, Chuẩn Kiến Thức Để require() hoạt động, module bạn muốn import phải "xuất khẩu" (export) ra bên ngoài. Trong CommonJS, chúng ta dùng module.exports hoặc exports. Ví dụ 1: Import một file cục bộ (Local File) Bạn có một file math.js chứa các phép tính cơ bản: // math.js function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } const PI = 3.14159; // "Xuất khẩu" các hàm và biến này ra ngoài để người khác dùng module.exports = { addFunc: add, // Đổi tên khi export cho rõ subtractFunc: subtract, piValue: PI }; // Hoặc bạn có thể export từng cái một: // exports.addFunc = add; // exports.subtractFunc = subtract; // exports.piValue = PI; Bây giờ, bạn muốn dùng chúng trong file app.js của mình: // app.js // "Gọi" chuyên gia toán học của chúng ta const mathOperations = require('./math'); // Đường dẫn tương đối console.log('Tổng 5 và 3 là:', mathOperations.addFunc(5, 3)); // Output: Tổng 5 và 3 là: 8 console.log('Hiệu 10 và 4 là:', mathOperations.subtractFunc(10, 4)); // Output: Hiệu 10 và 4 là: 6 console.log('Giá trị của PI là:', mathOperations.piValue); // Output: Giá trị của PI là: 3.14159 // Bạn cũng có thể "destructure" ngay lúc require để dùng trực tiếp: const { addFunc, piValue } = require('./math'); console.log('Tổng 7 và 2 là:', addFunc(7, 2)); // Output: Tổng 7 và 2 là: 9 console.log('PI lại là:', piValue); // Output: PI lại là: 3.14159 Ví dụ 2: Import một Module tích hợp sẵn của Node.js (Built-in Module) Node.js có rất nhiều module "nhà làm" cực kỳ mạnh mẽ, ví dụ như fs (File System) để làm việc với file và thư mục, hay http để tạo server web. // file_operations.js const fs = require('fs'); // Không cần đường dẫn, Node.js tự tìm trong các module built-in // Đọc nội dung file bất đồng bộ fs.readFile('hello.txt', 'utf8', (err, data) => { if (err) { console.error('Lỗi khi đọc file:', err); return; } console.log('Nội dung file hello.txt:', data); }); // Ghi nội dung vào file const content = 'Xin chào từ Node.js!'; fs.writeFile('new_file.txt', content, (err) => { if (err) { console.error('Lỗi khi ghi file:', err); return; } console.log('Đã ghi nội dung vào new_file.txt thành công!'); }); (Để chạy ví dụ này, bạn cần tạo file hello.txt với nội dung bất kỳ trong cùng thư mục). Ví dụ 3: Import một Module từ npm (Third-party Module) Thế giới Node.js "phát triển" nhờ cộng đồng với hàng triệu module trên npm. Để dùng, bạn cần cài đặt chúng trước. Ví dụ, axios là một thư viện phổ biến để gửi các HTTP request. Trước tiên, cài đặt axios: npm install axios Sau đó, bạn có thể require nó: // fetch_data.js const axios = require('axios'); // Node.js sẽ tìm trong thư mục node_modules async function fetchPosts() { try { const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1'); console.log('Dữ liệu bài viết:', response.data); } catch (error) { console.error('Lỗi khi lấy dữ liệu:', error.message); } } fetchPosts(); 3. Mẹo (Best Practices) để ghi nhớ hoặc dùng thực tế "Chuyên gia" phải rõ ràng: Luôn sử dụng module.exports hoặc exports để "xuất khẩu" những gì bạn muốn người khác dùng. Nếu không, require() sẽ chỉ nhận về một đối tượng rỗng. Nhớ nhé, exports là một tham chiếu đến module.exports. Đường dẫn "chuẩn chỉ": require('./module') hoặc require('../module'): Dùng cho các file cục bộ, đường dẫn tương đối. require('/path/to/module'): Dùng cho đường dẫn tuyệt đối (ít dùng hơn). require('module-name'): Dùng cho built-in modules (như fs, http) hoặc third-party modules đã cài qua npm (Node.js sẽ tìm trong node_modules). "Gọi" một lần là đủ: require() có cơ chế caching siêu "xịn". Lần đầu bạn require một module, Node.js sẽ tải, biên dịch và chạy nó. Từ lần thứ hai trở đi, nó sẽ trả về bản sao đã được cache, không tải lại nữa. Điều này giúp tăng tốc độ đáng kể! Phân biệt require và import (ESM): require() thuộc hệ thống CommonJS, hoạt động đồng bộ (synchronous). import (ESM - ECMAScript Modules) là tiêu chuẩn mới hơn, hoạt động bất đồng bộ (asynchronous) và có nhiều tính năng hiện đại hơn. Trong các dự án Node.js mới, đặc biệt khi dùng TypeScript hoặc các framework hiện đại, bạn sẽ thấy import được ưu tiên hơn. Tuy nhiên, require() vẫn "sống khỏe" trong các dự án cũ và một số trường hợp đặc biệt. 4. Văn phong học thuật sâu của Harvard, dạy dễ hiểu tuyệt đối "Thưa các quý vị sinh viên, hãy nhìn vào require() như một nguyên lý cơ bản của kỹ thuật phần mềm: Modularization (mô-đun hóa). Trong khoa học máy tính, việc phân tách một hệ thống phức tạp thành các thành phần độc lập, có thể tái sử dụng là chìa khóa để đạt được khả năng mở rộng (scalability), dễ bảo trì (maintainability) và độ tin cậy (reliability). require() chính là hiện thân của nguyên lý này trong bối cảnh Node.js CommonJS. Cơ chế hoạt động của require() là đồng bộ (synchronous). Điều này có nghĩa là luồng thực thi của chương trình sẽ tạm dừng cho đến khi module được tải, biên dịch và thực thi hoàn tất. Mặc dù có vẻ như một điểm hạn chế so với tính chất bất đồng bộ vốn có của JavaScript, nhưng trong bối cảnh tải module, nó đảm bảo rằng tất cả các phụ thuộc đều sẵn sàng trước khi code sử dụng chúng tiếp tục chạy, tránh các trạng thái không xác định. Hơn nữa, để tối ưu hiệu suất, Node.js áp dụng một cơ chế caching tinh vi. Sau lần tải đầu tiên, mỗi module sẽ được lưu trữ trong một bộ nhớ đệm nội bộ. Các lời gọi require() tiếp theo đến cùng một module sẽ không kích hoạt quá trình tải lại tốn kém mà thay vào đó sẽ trả về ngay lập tức phiên bản đã được cache. Đây là một tối ưu hóa thiết yếu, phản ánh nguyên tắc memoization trong lập trình, giúp giảm thiểu tài nguyên và tăng tốc độ khởi tạo ứng dụng." 5. Ví dụ thực tế các ứng dụng/website đã ứng dụng Hầu hết các ứng dụng Node.js "cũ" hoặc các dự án đã có từ trước khi ESM (ES Modules) trở nên phổ biến đều sử dụng require() một cách rộng rãi. Cụ thể: Express.js Applications: Các dự án backend xây dựng với Express.js (một framework web cực kỳ phổ biến của Node.js) thường dùng require() để import các router, middleware, hay các module xử lý logic nghiệp vụ. // app.js trong một dự án Express const express = require('express'); const app = express(); const userRoutes = require('./routes/users'); // Import router riêng const authMiddleware = require('./middleware/auth'); // Import middleware app.use('/users', authRoutes); // Sử dụng router // ... Các công cụ CLI (Command Line Interface) với Node.js: Nhiều công cụ dòng lệnh như npm (chính nó!), Webpack (phiên bản cũ), Gulp đều được viết bằng Node.js và sử dụng require() để tổ chức code. Thư viện và Framework cũ: Nhiều thư viện npm được phát triển từ lâu vẫn chủ yếu export theo chuẩn CommonJS, do đó bạn sẽ dùng require() để import chúng. 6. Thử nghiệm đã từng và hướng dẫn nên dùng cho case nào Thử nghiệm đã từng: Anh Creyt từng "kinh qua" những ngày đầu của Node.js, khi require() là "người bạn" duy nhất và "quyền lực" nhất. Mọi thứ từ việc xây dựng server, đọc ghi file, đến kết nối database đều phải thông qua require(). Nó đã chứng minh được sự hiệu quả trong việc quản lý code base lớn và phức tạp. Hướng dẫn nên dùng cho case nào: Dự án Node.js "Legacy" (cũ): Nếu bạn đang làm việc với một dự án Node.js đã có sẵn, được viết trước khi ES Modules (ESM) trở nên phổ biến hoặc yêu cầu cụ thể sử dụng CommonJS, thì require() là lựa chọn bắt buộc. Khi cần đồng bộ (Synchronous) hoàn toàn: Mặc dù hiếm, nhưng đôi khi bạn cần đảm bảo rằng một module được tải và thực thi xong hoàn toàn trước khi bất kỳ dòng code nào khác chạy. require() cung cấp hành vi đồng bộ này. Khi sử dụng các thư viện chỉ hỗ trợ CommonJS: Một số thư viện cũ trên npm có thể chỉ cung cấp các export theo chuẩn CommonJS. Trong trường hợp đó, bạn sẽ cần dùng require(). Files cấu hình (Configuration Files): Nhiều file cấu hình trong Node.js, ví dụ như webpack.config.js hoặc các file cấu hình database, thường sử dụng module.exports và được require() bởi các công cụ build. Khi nào nên cân nhắc import (ESM) thay vì require()? Dự án Node.js mới: Đối với các dự án mới, đặc biệt là khi bạn sử dụng Node.js phiên bản 12 trở lên, việc sử dụng ES Modules (import/export) được khuyến khích. Nó là tiêu chuẩn của JavaScript hiện đại, có tính năng "tree-shaking" tốt hơn (giúp giảm kích thước bundle), và hỗ trợ cú pháp top-level await. Khi muốn code "thuần" JavaScript hơn: ESM là một phần của tiêu chuẩn JavaScript, giúp code của bạn nhất quán hơn giữa môi trường trình duyệt và Node.js. Tóm lại: require() không phải là lỗi thời, nó là một phần lịch sử và vẫn cực kỳ quan trọng trong nhiều ngữ cảnh của Node.js. Nắm vững nó giúp bạn "đọc vị" và làm việc hiệu quả với hàng triệu dòng code Node.js đã tồn tại. Hãy xem nó như một "vũ khí" trong "kho vũ khí" của bạn, biết khi nào nên dùng nó, và khi nào nên "nâng cấp" lên import cho các trận chiến mới! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

49 Đọc tiếp
ES Modules: Nâng tầm code Node.js của bạn, gọn gàng như Gen Z!
18/03/2026

ES Modules: Nâng tầm code Node.js của bạn, gọn gàng như Gen Z!

Chào các 'dev' tương lai, hay đúng hơn là các 'code influencer' của thế hệ Z! Hôm nay, Anh Creyt sẽ cùng các bạn 'mổ xẻ' một khái niệm nghe có vẻ hàn lâm nhưng lại cực kỳ 'chill' và cần thiết cho mọi dự án hiện đại: ES Modules trong Node.js. 1. ES Modules là gì mà 'hot' vậy? Để làm gì? Ngày xửa ngày xưa, khi JavaScript còn 'ngây thơ', mỗi file code là một thế giới riêng, và mọi thứ bạn khai báo (biến, hàm) đều có thể 'va chạm' với nhau nếu không cẩn thận. Giống như một căn phòng trọ sinh viên, mỗi đứa vứt đồ đạc lung tung, y rằng sẽ có ngày giẫm phải đồ của đứa khác và cãi nhau ỏm tỏi vậy. Rồi đến lúc code to dần, cần chia nhỏ ra nhiều file để dễ quản lý. Lúc này, 'bài toán' làm sao để các file có thể 'giao tiếp' với nhau, chia sẻ các 'công thức' (hàm) hay 'nguyên liệu' (biến) mà không gây 'đụng độ' toàn cục, trở thành một cơn đau đầu kinh niên. Các hệ thống module ra đời để giải quyết vấn đề này, như CommonJS trong Node.js ngày trước, hay AMD, UMD trên trình duyệt. Nhưng rồi, 'thời đại mới' đến, và ES Modules (ECMAScript Modules) chính là 'người hùng' được sinh ra để thống nhất mọi thứ. Hãy tưởng tượng ES Modules như việc bạn xây dựng một căn hộ chung cư cao cấp. Mỗi căn hộ là một module, có cửa ra vào (export) để cung cấp dịch vụ (hàm, biến) cho các căn hộ khác, và có thể 'nhập khẩu' (import) dịch vụ từ các căn hộ lân cận. Mỗi căn hộ hoạt động độc lập, có không gian riêng, nhưng vẫn có thể kết nối với nhau một cách có trật tự. Để làm gì ư? Đơn giản là để: Tổ chức code gọn gàng: Chia dự án thành các phần nhỏ, dễ quản lý, dễ đọc, dễ bảo trì. Tránh xung đột: Mỗi module có phạm vi riêng, không làm bẩn môi trường toàn cục. Tái sử dụng code: Viết một lần, dùng nhiều nơi, tiết kiệm thời gian và công sức. Tối ưu hiệu suất (Tree-shaking): Các công cụ đóng gói (bundler) có thể loại bỏ những phần code không dùng đến, giúp ứng dụng nhẹ hơn, load nhanh hơn. Giống như bạn chỉ mang những món đồ cần thiết khi đi du lịch vậy. 2. Code Ví Dụ Minh Họa: 'Mở cửa' và 'Mời vào' module Để Node.js hiểu rằng bạn muốn dùng ES Modules, có hai cách chính: Dùng "type": "module" trong package.json: Đây là cách phổ biến và khuyến khích cho các dự án mới. { "name": "my-esm-app", "version": "1.0.0", "description": "", "main": "index.js", "type": "module", // <-- Thêm dòng này "scripts": { "start": "node index.js" }, "keywords": [], "author": "", "license": "ISC" } Dùng đuôi file .mjs: Node.js sẽ tự động coi các file .mjs là ES Modules, bất kể package.json có gì. Bây giờ, hãy tạo một module đơn giản: utils.js (hoặc utils.mjs) // utils.js // Export named: Giống như bạn có nhiều món đồ để bán, mỗi món có tên riêng export const add = (a, b) => a + b; export const multiply = (a, b) => a * b; export const greeting = (name) => `Hello, ${name}! Welcome to the ES Modules club.`; // Export default: Chỉ có một món đồ 'best-seller' của cửa hàng const secretMessage = "This is a secret message from utils."; export default secretMessage; Và cách bạn 'nhập khẩu' chúng vào file chính: index.js (hoặc index.mjs) // index.js // Import named: Mua đúng món đồ mình cần theo tên import { add, multiply, greeting } from './utils.js'; // Lưu ý: phải có đuôi .js (hoặc .mjs) // Import default: Mua món 'best-seller' của cửa hàng, bạn có thể đặt tên tùy ý import mySecret from './utils.js'; console.log('Using named exports:'); console.log('2 + 3 =', add(2, 3)); // Output: 2 + 3 = 5 console.log('4 * 5 =', multiply(4, 5)); // Output: 4 * 5 = 20 console.log(greeting('Creyt')); // Output: Hello, Creyt! Welcome to the ES Modules club. console.log('\nUsing default export:'); console.log('Secret:', mySecret); // Output: Secret: This is a secret message from utils. // Bạn cũng có thể import tất cả các named exports vào một object: import * as Utils from './utils.js'; console.log('\nImporting all named exports as an object:'); console.log('10 + 20 =', Utils.add(10, 20)); // Output: 10 + 20 = 30 Để chạy, bạn chỉ cần mở terminal trong thư mục dự án và gõ: node index.js (Hoặc node index.mjs nếu bạn dùng .mjs) 3. Mẹo (Best Practices) để 'chơi' ES Modules đỉnh cao Luôn dùng đuôi file: Trong Node.js, khi import một module cục bộ, bạn phải thêm đuôi .js, .mjs, .json... Đây là một điểm khác biệt so với khi bạn import trên trình duyệt hoặc với các bundler như Webpack (nơi bạn thường bỏ qua đuôi file). Quên cái này là 'toang' ngay! Thống nhất cách dùng: Nếu đã dùng "type": "module" thì cứ thế mà triển khai. Hạn chế tối đa việc trộn lẫn CommonJS (require/module.exports) và ES Modules (import/export) trong cùng một dự án lớn, trừ khi bạn là 'phù thủy' và biết mình đang làm gì. Việc này có thể dẫn đến những lỗi khó lường và 'debug' mệt nghỉ. Đường dẫn tương đối: Luôn dùng đường dẫn tương đối (ví dụ: ./utils.js, ../components/button.js) cho các module cục bộ của bạn. Điều này giúp code của bạn dễ di chuyển và hoạt động tốt hơn trong các môi trường khác nhau. Hiểu rõ import là async: Không giống như require của CommonJS (thường là synchronous), import về cơ bản là asynchronous. Tuy nhiên, Node.js đã tối ưu để chúng hoạt động 'như thể' synchronous trong hầu hết các trường hợp. Dù vậy, việc hiểu bản chất này sẽ giúp bạn khi làm việc với các hệ thống phức tạp hơn. Tree-shaking là 'chân ái': Khi bạn chỉ import những thứ bạn cần (ví dụ: import { add } from './utils.js'; thay vì import * as Utils from './utils.js';), các bundler sẽ có thể loại bỏ phần code không dùng đến, làm ứng dụng của bạn nhẹ hơn đáng kể. Đây là một 'siêu năng lực' mà CommonJS không có được. 4. Góc nhìn học thuật sâu của Harvard: Why ES Modules? Từ góc độ 'học thuật' (nhưng vẫn dễ hiểu nha), sự ra đời của ES Modules không chỉ là một 'cải tiến' mà là một 'cuộc cách mạng' trong việc chuẩn hóa hệ sinh thái JavaScript. Trước đây, mỗi môi trường (browser, Node.js) lại có một cách quản lý module riêng, tạo ra sự phân mảnh và đau đầu cho các nhà phát triển. ES Modules được thiết kế để trở thành tiêu chuẩn chung của ECMAScript, nghĩa là nó hoạt động được cả trên trình duyệt lẫn Node.js (và các môi trường JavaScript khác). Điều này mang lại: Tính tương thích cao: Code module của bạn có thể chạy 'ngon lành' ở mọi nơi. Phân tích tĩnh (Static Analysis): Cấu trúc import/export của ES Modules cho phép các công cụ (như bundler) hiểu được mối quan hệ giữa các module ngay cả trước khi code được thực thi. Điều này là nền tảng cho các tính năng mạnh mẽ như tree-shaking và kiểm tra lỗi sớm. Thiết kế bất đồng bộ: Mặc dù hiện tại Node.js đã tối ưu để import hoạt động hiệu quả, nhưng về bản chất, thiết kế của ES Modules hỗ trợ tốt cho việc tải module bất đồng bộ, rất quan trọng đối với hiệu suất trên web. Loại bỏ vấn đề 'global scope pollution': Các module tạo ra các phạm vi (scope) riêng biệt, đảm bảo biến và hàm không 'làm bẩn' phạm vi toàn cục, giảm thiểu lỗi và tăng tính ổn định của ứng dụng. 5. Ví dụ thực tế: Ai đang dùng ES Modules? 'Hội' ES Modules giờ đây đông đảo vô cùng, từ các framework 'lẫy lừng' đến những công cụ 'xịn sò': React, Vue, Angular: Các framework frontend này sử dụng ES Modules làm nền tảng cho việc tổ chức component và quản lý dependency. Mỗi component là một module, 'export' component chính và 'import' các component con hoặc utility khác. Next.js, Nuxt.js, SvelteKit: Các framework meta này xây dựng trên React/Vue/Svelte và Node.js, tận dụng triệt để ES Modules để tối ưu hóa quá trình build và server-side rendering. Webpack, Rollup, Vite: Các công cụ đóng gói (bundler) này là 'fan cuồng' của ES Modules. Chúng dùng cấu trúc import/export để phân tích cây dependency, thực hiện tree-shaking, code splitting và nhiều tối ưu hóa khác, giúp ứng dụng web của bạn 'nhanh như điện'. Các thư viện Node.js hiện đại: Rất nhiều thư viện đã chuyển sang hoặc hỗ trợ cả ES Modules song song với CommonJS, ví dụ như lodash-es, date-fns. 6. Thử nghiệm và Nên dùng cho case nào? Khi nào nên dùng ES Modules? Dự án mới: Bất kỳ dự án JavaScript/Node.js nào bạn bắt đầu từ bây giờ đều nên dùng ES Modules. Đây là tương lai, là tiêu chuẩn. Phát triển Frontend: Luôn luôn dùng ES Modules. Trình duyệt đã hỗ trợ native ES Modules từ lâu, và các bundler frontend cũng hoạt động tốt nhất với chúng. Thư viện/package: Nếu bạn đang phát triển một thư viện để chia sẻ, việc hỗ trợ ES Modules là cực kỳ quan trọng để người dùng có thể tận dụng tree-shaking và tích hợp dễ dàng vào các dự án hiện đại. Khi nào nên cân nhắc (hoặc tạm thời chưa dùng)? Dự án cũ dùng CommonJS: Nếu bạn đang làm việc với một dự án Node.js 'lão làng' chỉ toàn CommonJS, việc chuyển đổi toàn bộ sang ES Modules có thể tốn thời gian và công sức. Hãy cân nhắc lợi ích so với chi phí. Đôi khi, bạn có thể 'dùng chung' (interop) bằng cách import CommonJS module vào ES Module, nhưng không phải lúc nào cũng mượt mà. Môi trường hạn chế: Một số công cụ hoặc môi trường rất cũ có thể chưa hỗ trợ ES Modules đầy đủ. Nhưng trường hợp này ngày càng hiếm. Thử nghiệm: Bạn có thể thử nghiệm bằng cách tạo một dự án nhỏ với "type": "module" trong package.json và sau đó cố gắng require một module CommonJS từ một file ES Module. Node.js hỗ trợ điều này, nhưng bạn sẽ không thể import một ES Module từ một file CommonJS một cách trực tiếp. Đây là một điểm cần lưu ý khi làm việc với các dự án hybrid. // esm-file.js (type: module) import { someFunction } from './cjs-module.cjs'; // Có thể import CJS vào ESM console.log(someFunction()); // cjs-module.cjs (mặc định là CommonJS) module.exports = { someFunction: () => 'Hello from CJS!' }; // cjs-file.js (không có type: module) // const { someFunction } = require('./esm-module.js'); // Sẽ lỗi! Không thể require ESM vào CJS trực tiếp // Để import ESM vào CJS, bạn cần dùng dynamic import() async function run() { const { greeting } = await import('./esm-module.js'); console.log(greeting('Dynamic Import User')); } run(); // esm-module.js (type: module) export const greeting = (name) => `Hello, ${name} from ESM!`; Đó, các bạn thấy không? ES Modules không chỉ là một cú 'upgrade' về cú pháp, mà nó còn là cả một triết lý mới trong việc tổ chức và xây dựng ứng dụng JavaScript. Hãy 'ôm' lấy nó, vì nó sẽ giúp code của bạn 'sạch sẽ' hơn, 'thông minh' hơn và 'chuẩn' hơn trong thế giới lập trình hiện đại. 'Keep coding, keep learning!'. Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

46 Đọc tiếp
CommonJS Modules: Mở Khóa Sức Mạnh Tổ Chức Code Node.js (Genz Edition)
18/03/2026

CommonJS Modules: Mở Khóa Sức Mạnh Tổ Chức Code Node.js (Genz Edition)

CommonJS Modules: Mở Khóa Sức Mạnh Tổ Chức Code Node.js (Genz Edition) Chào các bạn Gen Z của anh Creyt! Hôm nay, chúng ta sẽ cùng nhau 'unbox' một khái niệm tưởng chừng khô khan nhưng lại là xương sống của mọi dự án Node.js đời đầu: CommonJS Modules. Đừng lo, anh sẽ 'hack' nó thành thứ gì đó dễ hiểu, dễ nhớ nhất. 1. CommonJS Modules là gì mà 'hot' thế? Để dễ hình dung, các bạn cứ coi dự án code của chúng ta như một khu chung cư cao cấp. Mỗi căn hộ (file .js) là nơi ở của một 'team' code, chuyên làm một nhiệm vụ cụ thể nào đó (ví dụ: căn hộ A chuyên tính toán, căn hộ B chuyên xử lý database). CommonJS Modules chính là cái 'quy tắc quản lý chung' của khu chung cư này, giúp các căn hộ có thể trao đổi đồ đ đạc (dữ liệu, hàm) cho nhau một cách có trật tự, không ai lấn sang 'lãnh thổ' của ai. Nói một cách hàn lâm hơn, CommonJS là một đặc tả (specification) định nghĩa cách các module (các file JavaScript) có thể được định nghĩa, xuất (export) và nhập (import) vào các file khác trong môi trường Node.js. Nó là hệ thống module mặc định của Node.js trong một thời gian rất dài, trước khi ES Modules (ESM) 'nhảy vào cuộc chơi'. Nó sinh ra để làm gì? Tránh 'ô nhiễm' không gian toàn cục (Global Scope Pollution): Tưởng tượng mỗi căn hộ (file code) đều vứt đồ đạc ra hành lang chung (global scope). Chẳng mấy chốc sẽ thành bãi rác, không biết đồ của ai với ai. CommonJS giúp mỗi căn hộ giữ đồ đạc của mình, chỉ chia sẻ những gì cần thiết. Tái sử dụng code (Code Reusability): Viết một lần, dùng nhiều nơi. Như việc bạn có một cái máy pha cà phê xịn (một hàm tiện ích) ở căn hộ mình, thay vì mỗi lần muốn uống lại phải mua máy mới, bạn chỉ cần 'export' nó ra, căn hộ khác 'import' vào dùng là xong. Dễ quản lý (Maintainability): Code được chia nhỏ thành các module độc lập, dễ dàng tìm kiếm, sửa lỗi và nâng cấp. Rõ ràng về phụ thuộc (Dependency Management): Ai cần gì, lấy từ đâu là rõ ràng. Không còn cảnh 'đồ của tôi tự nhiên xuất hiện' mà không biết từ đâu ra. 2. Code Ví Dụ Minh Họa: 'Mở cửa' và 'Đặt đồ' trong khu chung cư code Trong CommonJS, chúng ta có hai 'thao tác' chính: require(): Đây là 'chìa khóa' để bạn 'mở cửa' và 'lấy đồ' từ một căn hộ (module) khác. Khi bạn require một module, Node.js sẽ tải module đó và trả về những gì nó đã 'export'. module.exports (hoặc exports): Đây là 'hộp thư' hoặc 'bảng hiệu' của căn hộ bạn, nơi bạn 'đặt đồ' (hàm, biến, đối tượng) để các căn hộ khác có thể 'lấy' khi dùng require. Ví dụ 'Căn hộ tiện ích' (utils.js) // utils.js - Căn hộ chuyên làm các việc vặt tiện ích function add(a, b) { console.log('Đang thực hiện phép cộng...'); return a + b; } function subtract(a, b) { console.log('Đang thực hiện phép trừ...'); return a - b; } const PI = 3.14159; // 'Đặt đồ' vào hộp thư module.exports để căn hộ khác lấy module.exports = { addFunction: add, // Đặt hàm 'add' dưới tên 'addFunction' subtractFunction: subtract, // Đặt hàm 'subtract' dưới tên 'subtractFunction' PI_CONSTANT: PI // Đặt biến 'PI' dưới tên 'PI_CONSTANT' }; // Hoặc bạn có thể 'đặt từng món đồ' riêng lẻ: // exports.addFunction = add; // exports.subtractFunction = subtract; // exports.PI_CONSTANT = PI; // Lưu ý: Không gán trực tiếp 'exports = ...' mà phải gán 'module.exports = ...' nếu muốn thay đổi toàn bộ đối tượng exports. Ví dụ 'Căn hộ chính' (app.js) // app.js - Căn hộ chính, cần dùng tiện ích từ utils.js // Dùng 'chìa khóa' require để 'mở cửa' và 'lấy đồ' từ utils.js // Lưu ý: Đường dẫn './utils' là đường dẫn tương đối đến file utils.js const myUtils = require('./utils'); // Giờ thì dùng 'đồ' đã lấy được thôi! console.log('Kết quả 5 + 3 =', myUtils.addFunction(5, 3)); // Output: Đang thực hiện phép cộng... // Kết quả 5 + 3 = 8 console.log('Kết quả 10 - 4 =', myUtils.subtractFunction(10, 4)); // Output: Đang thực hiện phép trừ... // Kết quả 10 - 4 = 6 console.log('Hằng số PI là:', myUtils.PI_CONSTANT); // Output: Hằng số PI là: 3.14159 // Bạn cũng có thể dùng cú pháp 'destructuring' để lấy trực tiếp các món đồ: const { addFunction, PI_CONSTANT } = require('./utils'); console.log('PI từ destructuring:', PI_CONSTANT); // Output: PI từ destructuring: 3.14159 console.log('2 + 7 =', addFunction(2, 7)); // Output: Đang thực hiện phép cộng... // 2 + 7 = 9 Để chạy ví dụ này, bạn chỉ cần tạo hai file utils.js và app.js trong cùng một thư mục, sau đó mở terminal tại thư mục đó và gõ: node app.js 3. Mẹo (Best Practices) từ 'Giáo sư' Creyt 'Quy hoạch' rõ ràng: Luôn nghĩ xem module của bạn sẽ 'export' ra những gì. Đừng 'vứt' tất cả mọi thứ ra module.exports. Chỉ chia sẻ những gì module đó chịu trách nhiệm và cần thiết cho module khác. Đường dẫn 'chuẩn chỉ': Khi require các module tự viết trong dự án, luôn dùng đường dẫn tương đối (ví dụ: ./myModule, ../anotherModule). Khi require các thư viện cài từ npm (ví dụ: express, lodash), chỉ cần dùng tên gói. module.exports là 'ông chủ': Khi muốn xuất một đối tượng, hàm, hay giá trị duy nhất từ module, hãy dùng module.exports = .... Nếu muốn xuất nhiều thứ, hãy gán các thuộc tính vào module.exports (hoặc exports). Nhớ rằng exports chỉ là một tham chiếu đến module.exports ban đầu; nếu bạn gán exports = { ... }, tham chiếu sẽ bị đứt và module sẽ xuất ra một đối tượng rỗng. Tốt nhất, cứ dùng module.exports cho rõ ràng. 'Cache' là bạn: Node.js sẽ cache module sau lần require đầu tiên. Điều này có nghĩa là nếu bạn require cùng một module nhiều lần, nó sẽ không chạy lại code trong module đó mà chỉ trả về đối tượng đã được cache. Điều này giúp tối ưu hiệu suất nhưng cũng cần lưu ý nếu module của bạn có 'side effects' (tác dụng phụ) khi được tải. Đồng bộ (Synchronous) là 'đặc sản': require() là một hoạt động đồng bộ. Điều này có nghĩa là code của bạn sẽ dừng lại cho đến khi module được tải xong. Với các module code thuần túy thì không sao, nhưng nếu bạn require một module mà bên trong nó làm các tác vụ I/O nặng (ví dụ: đọc file lớn), nó có thể làm chậm ứng dụng. 4. Góc học thuật Harvard: CommonJS dưới kính hiển vi Tại sao exports, require, module, __filename, __dirname lại 'tự nhiên xuất hiện' trong mỗi file Node.js mà chúng ta không cần khai báo? Đó là vì Node.js không chạy code của bạn trực tiếp. Thay vào đó, nó bao bọc (wraps) mỗi module trong một hàm đặc biệt, trông giống như thế này: (function (exports, require, module, __filename, __dirname) { // Code của bạn ở đây // Ví dụ: console.log('Hello from module'); // module.exports = someValue; }); Khi Node.js tải một module, nó thực thi hàm bao bọc này và truyền vào các đối tượng exports, require, module, __filename, __dirname làm tham số. Điều này tạo ra một không gian cục bộ (local scope) cho mỗi module, giữ cho các biến và hàm không bị xung đột với các module khác hoặc không gian toàn cục. module: Là một đối tượng chứa thông tin về module hiện tại, quan trọng nhất là thuộc tính exports của nó. module.exports: Là đối tượng mà module sẽ trả về khi được require. exports: Ban đầu, exports là một tham chiếu đến module.exports. Bạn có thể thêm thuộc tính vào exports (ví dụ: exports.myFunc = ...). Tuy nhiên, nếu bạn gán exports = { ... }, bạn đã thay đổi tham chiếu của exports mà không thay đổi module.exports, dẫn đến việc module vẫn trả về module.exports ban đầu (thường là một đối tượng rỗng). require: Hàm dùng để nhập các module khác. __filename: Đường dẫn tuyệt đối đến file module hiện tại. __dirname: Đường dẫn tuyệt đối đến thư mục chứa file module hiện tại. 5. Ứng dụng thực tế: Ai đang dùng CommonJS? CommonJS là 'công thần' của Node.js, nên bạn sẽ thấy nó ở khắp mọi nơi, đặc biệt là trong các dự án cũ hơn: Express.js: Framework web 'quốc dân' của Node.js, trong các phiên bản cũ và cấu hình mặc định, vẫn sử dụng CommonJS. Lodash, Mongoose, Moment.js: Hầu hết các thư viện utility, ORM/ODM phổ biến được phát triển cho Node.js đều dùng CommonJS. Các công cụ Build: Webpack, Gulp, Grunt (trước đây) thường sử dụng CommonJS cho các file cấu hình của chúng. Backend của các ứng dụng lớn: Nhiều dịch vụ backend của các công ty như PayPal, Netflix, Uber (một số microservices) sử dụng Node.js, và nhiều phần trong đó vẫn đang chạy trên CommonJS modules. Các CLI Tools (Command Line Interface Tools): Nhiều công cụ dòng lệnh được viết bằng Node.js cũng dùng CommonJS để tổ chức code. 6. Thử nghiệm và Nên dùng cho trường hợp nào? Khi nào nên 'chiến' với CommonJS? Dự án Node.js cũ: Nếu bạn đang 'đào mộ' hoặc bảo trì một dự án Node.js được xây dựng từ lâu, khả năng cao nó đang dùng CommonJS. Nắm vững nó là chìa khóa để hiểu và sửa đổi code. Thư viện chỉ hỗ trợ CommonJS: Một số thư viện cũ hơn có thể chưa chuyển sang ES Modules. Trong trường hợp này, bạn buộc phải dùng CommonJS để require chúng. Khi package.json không có "type": "module": Theo mặc định, Node.js coi các file .js là CommonJS modules. Nếu bạn không khai báo "type": "module" trong package.json, thì đó là CommonJS. Các script Node.js đơn giản: Đối với các script backend nhỏ, nhanh gọn, CommonJS vẫn là lựa chọn tiện lợi và không cần cấu hình phức tạp. Khi nào nên 'nhảy tàu' sang ES Modules (cho Gen Z muốn 'up-to-date')? Dự án Node.js mới: Nếu bạn đang bắt đầu một dự án Node.js hoàn toàn mới, anh Creyt khuyến khích bạn nên cân nhắc sử dụng ES Modules (với cú pháp import/export). Nó là tiêu chuẩn của JavaScript hiện đại, tương thích tốt hơn với trình duyệt và có nhiều tính năng 'xịn sò' hơn như top-level await. Cần 'Tree Shaking': Đối với các ứng dụng frontend được bundle (ví dụ với Webpack), ES Modules cho phép 'tree shaking' hiệu quả hơn, loại bỏ code không dùng đến để giảm kích thước bundle. Thống nhất với Frontend: Nếu bạn làm cả frontend và backend, việc dùng ES Modules ở cả hai nơi giúp codebase đồng nhất hơn. Thử nghiệm ngay! Để thực sự 'thấm' CommonJS, hãy tự mình thử nghiệm: Tạo một thư mục mới, ví dụ my-commonjs-project. Trong thư mục đó, tạo hai file: calculator.js và main.js. Trong calculator.js, viết vài hàm toán học (cộng, trừ, nhân, chia) và module.exports chúng ra. Trong main.js, require calculator.js và gọi các hàm đó. Chạy node main.js và xem kết quả. Thử thay đổi cách export (dùng exports.func = ... hoặc module.exports = { ... }) và cách require (destructuring) để xem sự khác biệt. Đây là cách tốt nhất để 'đúc kết' kiến thức và biến nó thành kinh nghiệm của riêng bạn. Hãy nhớ, code là để thực hành, không phải chỉ để đọc! Chúc các bạn Gen Z 'code' vui vẻ và trở thành những dev 'đỉnh của chóp'! Thuộc Series: Nodejs Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

49 Đọc tiếp