Node.js 설치: 브라우저 없이 서버에서 버튼 작동 체크

서버에서 자바스크립트를 실행하려면 먼저 Node.js 설치가 필요합니다. Nginx와 Apache 구성의 워드프레스 서버에 Node.js 24.21.0을 설치하고, jsdom 30.1.3으로 브라우저 없이 웹 페이지의 버튼 스크립트를 검사했습니다.
기본 저장소의 nodejs는 16.20.2이며, 스크립트 검사에 사용할 jsdom 30.1.3은 Node.js 22.22.2 이상을 요구합니다. 그래서 dnf 모듈 스트림 24로 설치를 진행했습니다.
1️⃣ 서버에 Node.js와 jsdom 설치 목적
서버에서 버튼 스크립트를 검사하려면 Node.js와 jsdom 두 가지가 필요합니다.
🔲 Node.js
자바스크립트는 보통 브라우저 안에서 실행되지만, Node.js를 설치하면 서버에서도 자바스크립트를 읽고 실행할 수 있습니다.
Node.js를 설치하는 것은 브라우저 안에만 있던 자바스크립트 실행기를 서버에도 하나 두는 것입니다. 그래서 Node.js는 웹 서버를 만들거나, 여러 파일을 한꺼번에 처리하는 명령을 만들거나, jsdom 같은 패키지를 불러와 페이지를 검사할 때 사용합니다. Ghost도 Node.js 위에서 실행되는 CMS입니다.
🔲 jsdom
jsdom은 Node.js에서 사용하는 패키지로, HTML을 읽어 브라우저처럼 버튼을 누를 수 있는 문서로 만듭니다. 브라우저가 페이지를 열 때 만드는 문서 구조(DOM)를 화면 없이 서버 안에 그대로 만드는 방식이라, 스크립트는 실제 브라우저에 있는 것처럼 버튼을 찾고 글자를 바꿉니다. 창을 띄우지 않으므로 서버에서 명령 한 줄로 실행할 수 있습니다.
이는 곧 사람이 브라우저를 열어 하나씩 눌러 보던 확인을 서버가 명령으로 대신한다는 것입니다. 그래서 jsdom은 버튼 동작을 고칠 때마다 자동으로 시험하거나, 페이지에서 제목·링크 같은 내용만 뽑아내거나, 글 HTML을 한꺼번에 손볼 때도 사용합니다.
PHP나 curl로 페이지를 받으면 처음 내려온 HTML만 확인할 수 있습니다. 버튼을 누른 뒤 바뀌는 글자는 스크립트가 실행되어야 나타납니다.
브라우저는 페이지 받기, 페이지 읽기, 버튼 눌러 보기, 화면에 보여 주기의 네 단계를 거칩니다. jsdom은 화면에 보여 주는 단계만 빼고 나머지 세 단계를 서버에서 진행하므로, 버튼의 위치와 크기는 브라우저에서 확인합니다.
2️⃣ 설치 전 확인: 기본 저장소와 모듈 스트림
[dnf install nodejs]를 실행하기 전에 설치될 판부터 확인합니다. AlmaLinux 9.8 기본 저장소의 nodejs는 16.20.2입니다.
dnf list --available nodejs사용 가능한 꾸러미
nodejs.x86_64 1:16.20.2-8.el9_4 appstream모듈 저장소에는 18, 20, 22, 24 네 스트림이 있으며, 확인일 기준 22 스트림은 22.23.2, 24 스트림은 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 runtimenpm 레지스트리 기준 jsdom 30.1.3이 요구하는 판은 22 계열 22.22.2 이상, 24 계열 24.15.0 이상, 또는 26 이상입니다. 22와 24 스트림 모두 이 조건을 충족합니다.
3️⃣ Node.js 설치: dnf module
이번에는 24 스트림을 설치했으며, 실행 전에 [--assumeno] 옵션으로 설치될 꾸러미 목록부터 확인했습니다.
dnf module install nodejs:24 --assumeno목록에는 nodejs와 npm, nodejs-libs, nodejs-docs, nodejs-full-i18n 다섯 꾸러미만 있었습니다. 웹 서버와 PHP, 커널 꾸러미는 포함되지 않았습니다. 확인한 뒤 [-y] 옵션으로 설치를 진행합니다.
dnf module install -y nodejs:24종속성이 해결되었습니다.
==============================================================================================
꾸러미 구조 버전 저장소 크기
==============================================================================================
그룹/모듈 꾸러미 설치:
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
종속 꾸러미 설치 중:
nodejs-libs x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 24 M
취약한 종속 꾸러미 설치 중:
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
모듈 프로파일 설치:
nodejs/common
모듈 스트림 활성화:
nodejs 24
연결 요약
==============================================================================================
설치 5 꾸러미
전체 내려받기 크기: 40 M
설치된 크기 : 185 M[취약한 종속 꾸러미]는 함께 설치하면 좋은 꾸러미를 뜻하는 weak dependencies를 dnf 한국어 화면이 옮긴 말입니다. 내려받기 크기는 40M, 설치 크기는 185M입니다.
node -vv24.21.0npm -v11.19.0cat /etc/dnf/modules.d/nodejs.module[nodejs]
name=nodejs
stream=24
profiles=common
state=enablednode는 24.21.0, npm은 11.19.0으로 설치되었습니다. 설치 뒤 바뀐 설정 파일은 [/etc/dnf/modules.d/nodejs.module] 하나이며, 24 스트림과 common 프로필이 활성 상태로 기록됩니다.
4️⃣ jsdom 설치와 버튼 스크립트 검사
jsdom은 npm으로 작업 폴더에 설치하며, 작업 폴더는 웹 루트 밖에 만듭니다.
mkdir ~/jsdom-test && cd ~/jsdom-test
npm init -y[npm init -y]는 기본값으로 package.json을 만들며, 이어서 같은 폴더에 jsdom을 설치합니다.
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.3jsdom 30.1.3을 포함해 패키지 36개가 설치되었으며, 알려진 취약점은 0건입니다. 작업 폴더의 node_modules 크기는 26M입니다.
node -e 'const { JSDOM } = require(`jsdom`); console.log(new JSDOM(`<h1>안녕</h1>`).window.document.querySelector(`h1`).textContent)'안녕h1 태그 하나로 된 HTML을 jsdom이 문서로 읽어, 그 안의 글자 [안녕]을 출력하면 작동 확인이 끝납니다.
버튼 스크립트 검사는 누른 뒤 글자가 제대로 바뀌는지를 서버에서 확인하는 일입니다. 예시로 [복사] 버튼을 누르면 글자가 [복사됨]으로 바뀌는 HTML 파일을 작업 폴더에 만들었습니다.
cat btn.html<button id="copy">복사</button>
<script>
document.getElementById('copy').addEventListener('click', function () {
this.textContent = '복사됨';
});
</script>검사 스크립트는 HTML 파일을 jsdom으로 읽어 스크립트를 실행하고, 버튼을 누르기 전과 누른 뒤의 글자를 출력합니다. 스크립트 오류는 [오류:]로 시작하는 줄로 출력합니다.
cat check.jsconst fs = require('fs');
const { JSDOM, VirtualConsole } = require('jsdom');
const vc = new VirtualConsole();
vc.on('jsdomError', (e) => console.log('오류:', 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('누르기 전:', btn.textContent);
btn.click();
console.log('누른 뒤:', btn.textContent);node check.js btn.html누르기 전: 복사
누른 뒤: 복사됨누른 뒤 글자가 [복사됨]으로 바뀌어, 버튼 스크립트가 작동하는 것을 확인할 수 있습니다.
스크립트에 오타가 하나 있으면 결과가 달라집니다. getElementById의 대문자 I를 소문자 l로 바꾼 파일로 같은 검사를 실행했습니다.
sed 's/getElementById/getElementByld/' btn.html > btn-broken.html
node check.js btn-broken.html오류: Uncaught [TypeError: document.getElementByld is not a function]
누르기 전: 복사
누른 뒤: 복사첫 줄에 오류가 출력되고 스크립트가 멈춰, 버튼을 눌러도 글자가 [복사]로 남습니다.
버튼에 CSS로 너비 120px, 높이 40px을 지정한 뒤 크기를 출력했습니다.
cat size.jsconst { JSDOM } = require('jsdom');
const dom = new JSDOM('<button id="copy" style="width:120px;height:40px">복사</button>');
const btn = dom.window.document.querySelector('#copy');
console.log('높이:', btn.offsetHeight, '/ 너비:', btn.getBoundingClientRect().width);node size.js높이: 0 / 너비: 0jsdom에는 화면에 그리는 단계가 없어 높이와 너비가 0으로 출력됩니다.
🔢 FAQ & 추천 콘텐츠







ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.