Cài đặt Node.js: kiểm tra hoạt động của nút trên máy chủ không cần trình duyệt

Để chạy JavaScript trên máy chủ, trước hết cần cài đặt Node.js. Node.js 24.21.0 đã được cài trên một máy chủ WordPress dùng Nginx và Apache, và jsdom 30.1.3 được dùng để kiểm tra script nút của trang web mà không cần trình duyệt.
nodejs trong kho mặc định là 16.20.2, còn jsdom 30.1.3 dùng để kiểm tra script yêu cầu Node.js 22.22.2 trở lên. Vì vậy việc cài đặt được thực hiện từ luồng mô-đun dnf 24.
1️⃣ Mục đích cài Node.js và jsdom trên máy chủ
Để kiểm tra script nút trên máy chủ, cần hai thứ: Node.js và jsdom.
🔲 Node.js
JavaScript thường chạy trong trình duyệt, nhưng khi cài Node.js, máy chủ cũng có thể đọc và chạy JavaScript.
Cài Node.js nghĩa là đặt thêm lên máy chủ một bộ chạy JavaScript vốn chỉ có trong trình duyệt. Vì vậy Node.js được dùng để tạo máy chủ web, tạo lệnh xử lý nhiều tệp cùng lúc, hoặc nạp các gói như jsdom để kiểm tra trang. Ghost cũng là một CMS chạy trên Node.js.
🔲 jsdom
jsdom là gói dùng trong Node.js, đọc HTML và biến nó thành tài liệu có nút bấm được như trong trình duyệt. jsdom dựng cấu trúc tài liệu (DOM) mà trình duyệt tạo ra khi mở trang ngay trong máy chủ mà không cần màn hình, nên script tìm nút và đổi chữ như đang ở trong trình duyệt thật. Vì không mở cửa sổ, có thể chạy trên máy chủ bằng một dòng lệnh.
Nói cách khác, việc kiểm tra mà trước đây người ta phải mở trình duyệt và bấm từng thứ một nay được máy chủ làm thay bằng lệnh. Vì vậy jsdom còn được dùng để tự động thử hoạt động của nút sau mỗi lần sửa, chỉ lấy nội dung như tiêu đề và liên kết từ trang, hoặc chỉnh HTML bài viết hàng loạt.
Nếu lấy trang bằng PHP hoặc curl, bạn chỉ thấy HTML được gửi lần đầu. Chữ thay đổi sau khi bấm nút chỉ xuất hiện khi script chạy.
Trình duyệt đi qua bốn bước: nhận trang, đọc trang, thử bấm nút và hiển thị lên màn hình. jsdom chạy mọi bước trên máy chủ trừ bước hiển thị lên màn hình, nên vị trí và kích thước của nút được kiểm tra trong trình duyệt.
2️⃣ Kiểm tra trước khi cài: kho mặc định và luồng mô-đun
Trước khi chạy [dnf install nodejs], hãy kiểm tra trước phiên bản sẽ được cài. nodejs trong kho mặc định của AlmaLinux 9.8 là 16.20.2.
dnf list --available nodejsAvailable Packages
nodejs.x86_64 1:16.20.2-8.el9_4 appstreamKho mô-đun có bốn luồng: 18, 20, 22 và 24. Tính đến ngày kiểm tra, luồng 22 là 22.23.2 và luồng 24 là 24.21.0.
dnf module list nodejsnodejs 18 common [d], development, minimal, s2i Javascript runtime
nodejs 20 common [d], development, minimal, s2i Javascript runtime
nodejs 22 common [d], development, minimal, s2i Javascript runtime
nodejs 24 common [d], development, minimal, s2i Javascript runtimeTheo npm registry, phiên bản jsdom 30.1.3 yêu cầu là 22.22.2 trở lên ở dòng 22, 24.15.0 trở lên ở dòng 24, hoặc từ 26 trở lên. Cả luồng 22 và 24 đều đáp ứng điều kiện này.
3️⃣ Cài đặt Node.js: dnf module
Lần này luồng 24 được cài, và trước khi chạy, danh sách gói sẽ được cài đã được kiểm tra trước bằng tùy chọn [--assumeno].
dnf module install nodejs:24 --assumenoDanh sách chỉ có năm gói: nodejs, npm, nodejs-libs, nodejs-docs và nodejs-full-i18n. Không có gói máy chủ web, PHP hay kernel. Sau khi kiểm tra, hãy tiến hành cài bằng tùy chọn [-y].
dnf module install -y nodejs:24Dependencies resolved.
==============================================================================================
Package Architecture Version Repository Size
==============================================================================================
Installing group/module packages:
nodejs x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 70 k
npm noarch 1:11.19.0-1.24.21.0.1.module_el9.8.0+321+1555b6a2 appstream 2.1 M
Installing dependencies:
nodejs-libs x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 24 M
Installing weak dependencies:
nodejs-docs noarch 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 5.3 M
nodejs-full-i18n x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 8.9 M
Installing module profiles:
nodejs/common
Enabling module streams:
nodejs 24
Transaction Summary
==============================================================================================
Install 5 Packages
Total download size: 40 M
Installed size: 185 M[Installing weak dependencies] liệt kê các weak dependencies, tức là những gói nên cài kèm. Dung lượng tải về là 40M và dung lượng sau khi cài là 185M.
node -vv24.21.0npm -v11.19.0cat /etc/dnf/modules.d/nodejs.module[nodejs]
name=nodejs
stream=24
profiles=common
state=enablednode được cài ở phiên bản 24.21.0 và npm ở 11.19.0. Tệp cấu hình duy nhất thay đổi sau khi cài là [/etc/dnf/modules.d/nodejs.module], ghi luồng 24 và profile common ở trạng thái đang bật.
4️⃣ Cài jsdom và kiểm tra script nút
jsdom được cài bằng npm vào thư mục làm việc, và thư mục làm việc được tạo bên ngoài web root.
mkdir ~/jsdom-test && cd ~/jsdom-test
npm init -y[npm init -y] tạo package.json với giá trị mặc định, sau đó jsdom được cài vào cùng thư mục.
npm install jsdomadded 36 packages, and audited 37 packages in 2s
8 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilitiesnpm ls jsdomjsdom-test@1.0.0 /root/jsdom-test
└── jsdom@30.1.336 gói, gồm cả jsdom 30.1.3, đã được cài, với 0 lỗ hổng đã biết. Dung lượng node_modules trong thư mục làm việc là 26M.
node -e 'const { JSDOM } = require(`jsdom`); console.log(new JSDOM(`<h1>Xin chào</h1>`).window.document.querySelector(`h1`).textContent)'Xin chàoKhi jsdom đọc HTML chỉ gồm một thẻ h1 thành tài liệu và in ra chữ bên trong là [Xin chào], việc kiểm tra hoạt động đã xong.
Kiểm tra script nút là xác nhận trên máy chủ rằng chữ thay đổi đúng sau khi bấm. Ví dụ, một tệp HTML được tạo trong thư mục làm việc, trong đó bấm nút [Sao chép] thì chữ đổi thành [Đã sao chép].
cat btn.html<button id="copy">Sao chép</button>
<script>
document.getElementById('copy').addEventListener('click', function () {
this.textContent = 'Đã sao chép';
});
</script>Script kiểm tra đọc tệp HTML bằng jsdom, chạy script trong đó rồi in chữ trước và sau khi bấm nút. Lỗi script được in ra ở dòng bắt đầu bằng [Lỗi:].
cat check.jsconst fs = require('fs');
const { JSDOM, VirtualConsole } = require('jsdom');
const vc = new VirtualConsole();
vc.on('jsdomError', (e) => console.log('Lỗi:', e.message));
const dom = new JSDOM(fs.readFileSync(process.argv[2], 'utf8'), {
runScripts: 'dangerously',
virtualConsole: vc,
});
const btn = dom.window.document.querySelector('#copy');
console.log('Trước khi bấm:', btn.textContent);
btn.click();
console.log('Sau khi bấm:', btn.textContent);node check.js btn.htmlTrước khi bấm: Sao chép
Sau khi bấm: Đã sao chépSau khi bấm, chữ đổi thành [Đã sao chép], qua đó xác nhận script nút hoạt động.
Chỉ một lỗi gõ trong script cũng làm kết quả thay đổi. Cùng phép kiểm tra được chạy với tệp đã đổi chữ I hoa trong getElementById thành chữ l thường.
sed 's/getElementById/getElementByld/' btn.html > btn-broken.html
node check.js btn-broken.htmlLỗi: Uncaught [TypeError: document.getElementByld is not a function]
Trước khi bấm: Sao chép
Sau khi bấm: Sao chépLỗi được in ở dòng đầu tiên và script dừng lại, nên dù bấm nút, chữ vẫn là [Sao chép].
Nút được đặt chiều rộng 120px và chiều cao 40px bằng CSS, sau đó kích thước được in ra.
cat size.jsconst { JSDOM } = require('jsdom');
const dom = new JSDOM('<button id="copy" style="width:120px;height:40px">Sao chép</button>');
const btn = dom.window.document.querySelector('#copy');
console.log('chiều cao:', btn.offsetHeight, '/ chiều rộng:', btn.getBoundingClientRect().width);node size.jschiều cao: 0 / chiều rộng: 0jsdom không có bước vẽ lên màn hình, nên chiều cao và chiều rộng được in ra là 0.
🔢 FAQ & nội dung đề xuất







ℹ️ Thông báo tiếp thị liên kết
Nội dung trên trang này có chứa liên kết affiliate (tiếp thị liên kết). Khi khách truy cập mua sản phẩm hoặc dịch vụ qua các liên kết này, trang sẽ nhận hoa hồng từ bên bán. Trong quá trình đó, số tiền người mua phải trả (sẽ giảm khi có chương trình khuyến mãi ↓) không hề tăng lên. Giá, khuyến mãi và tình trạng hàng được đăng theo thời điểm viết bài và có thể khác với thực tế, vì vậy hãy kiểm tra lại lần cuối với bên bán trước khi mua. Việc chọn và đánh giá sản phẩm dựa trên tiêu chí riêng của trang; việc có nhận hoa hồng hay không không ảnh hưởng đến thứ tự giới thiệu hay nội dung đánh giá.