jsdom은 Node.js와 함께 사용하기 위해 많은 웹 표준, 특히 WHATWG DOM 및 HTML 표준을 순수 JavaScript로 구현한 것입니다. 일반적으로 이 프로젝트의 목표는 실제 웹 애플리케이션을 테스트하고 스크랩하는 데 유용할 만큼 웹 브라우저의 하위 집합을 충분히 에뮬레이트하는 것입니다.
최신 버전의 jsdom에는 Node.js v18 이상이 필요합니다. (v23 이하의 jsdom 버전은 이전 Node.js 버전에서 계속 작동하지만 지원되지 않습니다.)
const jsdom = require("jsdom");const { JSDOM } = jsdom;
jsdom을 사용하려면 주로 jsdom 기본 모듈의 명명된 내보내기인 JSDOM
생성자를 사용합니다. 생성자에 문자열을 전달합니다. 여러 가지 유용한 속성, 특히 window
있는 JSDOM
객체를 얻게 됩니다.
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);console.log(dom.window.document.querySelector("p").textContent); // "안녕하세요 세계"
(jsdom은 묵시적인 <html>
, <head>
및 <body>
태그를 포함하여 브라우저와 마찬가지로 전달한 HTML을 구문 분석합니다.)
결과 객체는 JSDOM
클래스의 인스턴스이며, 여기에는 window
외에도 여러 가지 유용한 속성과 메서드가 포함되어 있습니다. 일반적으로 일반 DOM API로는 불가능한 작업을 수행하면서 "외부"에서 jsdom에 대해 작업하는 데 사용할 수 있습니다. 이 기능이 필요하지 않은 간단한 경우에는 다음과 같은 코딩 패턴을 권장합니다.
const { window } = new JSDOM(`...`);// 또는 evenconst { document } = (new JSDOM(`...`)).window;
JSDOM
클래스로 수행할 수 있는 모든 작업에 대한 전체 문서는 아래 " JSDOM
개체 API" 섹션에 있습니다.
JSDOM
생성자는 다음과 같은 방법으로 jsdom을 사용자 정의하는 데 사용할 수 있는 두 번째 매개변수를 허용합니다.
const dom = 새로운 JSDOM(``, { URL: "https://example.org/", 리퍼러: "https://example.com/", 콘텐츠 유형: "텍스트/html", includeNodeLocations: true, 저장 할당량: 10000000});
url
window.location
, document.URL
및 document.documentURI
에서 반환되는 값을 설정하고 문서 내의 상대 URL 확인, 하위 리소스를 가져오는 동안 사용되는 동일 출처 제한 및 리퍼러 등에 영향을 줍니다. 기본값은 "about:blank"
입니다.
referrer
document.referrer
에서 읽은 값에만 영향을 미칩니다. 기본값은 리퍼러 없음(빈 문자열로 반영)입니다.
contentType
document.contentType
에서 읽은 값과 문서가 구문 분석되는 방식(HTML 또는 XML)에 영향을 줍니다. HTML MIME 유형이나 XML MIME 유형이 아닌 값이 발생합니다. 기본값은 "text/html"
입니다. charset
매개변수가 있으면 이진 데이터 처리에 영향을 미칠 수 있습니다.
includeNodeLocations
HTML 파서에서 생성된 위치 정보를 보존하므로 nodeLocation()
메서드(아래 설명)를 사용하여 해당 정보를 검색할 수 있습니다. 또한 <script>
요소 내에서 실행되는 코드에 대한 예외 스택 추적에 보고된 줄 번호가 올바른지 확인합니다. 최상의 성능을 제공하기 위해 기본값은 false
이며, XML 파서는 위치 정보를 지원하지 않으므로 XML 콘텐츠 유형과 함께 사용할 수 없습니다.
storageQuota
는 localStorage
및 sessionStorage
에서 사용하는 별도의 저장 영역에 대한 코드 단위의 최대 크기입니다. 이 제한보다 큰 데이터를 저장하려고 하면 DOMException
이 발생합니다. 기본적으로 HTML 사양에서 영감을 받아 원본당 5,000,000 코드 단위로 설정됩니다.
url
과 referrer
모두 사용되기 전에 정규화됩니다. 예를 들어 "https:example.com"
전달하면 jsdom은 "https://example.com/"
을 지정한 것처럼 해석합니다. 구문 분석할 수 없는 URL을 전달하면 호출이 발생합니다. (URL은 URL 표준에 따라 구문 분석되고 직렬화됩니다.)
jsdom의 가장 강력한 기능은 jsdom 내부에서 스크립트를 실행할 수 있다는 것입니다. 이러한 스크립트는 페이지의 콘텐츠를 수정하고 jsdom이 구현하는 모든 웹 플랫폼 API에 액세스할 수 있습니다.
그러나 이는 신뢰할 수 없는 콘텐츠를 다룰 때에도 매우 위험합니다. jsdom 샌드박스는 완벽하지 않으며 DOM의 <script>
내부에서 실행되는 코드는 열심히 노력하면 Node.js 환경에 액세스할 수 있으므로 컴퓨터에 액세스할 수 있습니다. 따라서 HTML에 포함된 스크립트를 실행하는 기능은 기본적으로 비활성화되어 있습니다.
const dom = new JSDOM(`<body> <div id="content"></div> <script>document.getElementById("content").append(document.createElement("hr"));</script> </body>`);// 기본적으로 스크립트는 실행되지 않습니다:console.log(dom.window.document.getElementById("content").children.length); // 0
페이지 내에서 스크립트 실행을 활성화하려면 runScripts: "dangerously"
옵션을 사용하면 됩니다.
const dom = new JSDOM(`<body> <div id="content"></div> <script>document.getElementById("content").append(document.createElement("hr"));</script> </body>`, { runScripts: "dangerously" });// 스크립트가 실행되고 DOM:console.log(dom.window.document.getElementById("content").children.length); // 1
우리는 안전하다고 알고 있는 jsdom 코드를 입력할 때만 이것을 사용하도록 강조합니다. 임의의 사용자 제공 코드나 인터넷의 코드에 이를 사용하면 신뢰할 수 없는 Node.js 코드가 효과적으로 실행되고 시스템이 손상될 수 있습니다.
<script src="">
통해 포함된 외부 스크립트를 실행하려면 해당 스크립트가 로드되는지 확인해야 합니다. 이렇게 하려면 아래 설명과 같이 resources: "usable"
옵션을 추가하세요. (여기에 설명된 이유 때문에 url
옵션을 설정하고 싶을 수도 있습니다.)
<div onclick="">
과 같은 이벤트 핸들러 속성도 이 설정에 의해 제어됩니다. runScripts
"dangerously"
로 설정되어 있지 않으면 작동하지 않습니다. (그러나 div.onclick = ...
과 같은 이벤트 핸들러 속성은 runScripts
와 관계없이 작동합니다.)
단순히 "외부에서" 스크립트를 실행하려는 경우 <script>
요소 및 이벤트 핸들러 속성이 "내부에서" 실행되도록 하는 대신 runScripts: "outside-only"
옵션을 사용할 수 있습니다. JavaScript 사양에서 제공하는 모든 전역 변수가 window
에 설치됩니다. 여기에는 window.Array
, window.Promise
등이 포함됩니다. 특히 스크립트 실행을 허용하지만 jsdom window
전역으로 사용하는 window.eval
도 포함됩니다.
const dom = new JSDOM(`<body> <div id="content"></div> <script>document.getElementById("content").append(document.createElement("hr"));</script> </body>`, { runScripts: "outside-only" });// 외부에서 스크립트 실행 JSDOM:dom.window.eval('document.getElementById("content").append(document.createElement("p"));');console.log(dom.window.document.getElementById("content"). 어린이.길이); // 1console.log(dom.window.document.getElementsByTagName("hr").length); // 0console.log(dom.window.document.getElementsByTagName("p").length); // 1
성능상의 이유로 기본적으로 꺼져 있지만 활성화해도 안전합니다.
기본 구성에서 runScripts
설정하지 않으면 window.Array
, window.eval
등의 값은 외부 Node.js 환경에서 제공되는 값과 동일합니다. 즉, window.eval === eval
유지되므로 window.eval
유용한 방식으로 스크립트를 실행하지 않습니다.
jsdom과 Node 전역 환경을 결합하여(예: global.window = dom.window
수행) "스크립트 실행"을 시도한 다음 Node 전역 환경 내에서 스크립트나 테스트 코드를 실행하는 것을 강력히 권장합니다. 대신 jsdom을 브라우저처럼 처리하고 jsdom 환경 내에서 DOM에 액세스해야 하는 모든 스크립트와 테스트를 window.eval
또는 runScripts: "dangerously"
사용하여 실행해야 합니다. 예를 들어 브라우저에서와 마찬가지로 <script>
요소로 실행하기 위해 browserify 번들을 생성해야 할 수도 있습니다.
마지막으로 고급 사용 사례의 경우 아래에 설명된 dom.getInternalVMContext()
메서드를 사용할 수 있습니다.
jsdom에는 시각적 콘텐츠를 렌더링하는 기능이 없으며 기본적으로 헤드리스 브라우저처럼 작동합니다. document.hidden
과 같은 API를 통해 웹 페이지의 콘텐츠가 표시되지 않는다는 힌트를 웹 페이지에 제공합니다.
pretendToBeVisual
옵션이 true
로 설정되면 jsdom은 콘텐츠를 렌더링하고 표시하는 것처럼 가장합니다. 이 작업은 다음과 같이 수행됩니다.
true
대신 false
반환하도록 document.hidden
변경
document.visibilityState
"prerender"
대신 "visible"
반환하도록 변경
존재하지 않는 window.requestAnimationFrame()
및 window.cancelAnimationFrame()
메서드 활성화
const window = (new JSDOM(``, {pretentToBeVisual: true })).window;window.requestAnimationFrame(timestamp => { console.log(타임스탬프 > 0);});
jsdom은 여전히 어떤 레이아웃이나 렌더링도 수행하지 않습니다. 따라서 이는 실제 시각적 웹 브라우저가 구현할 플랫폼 부분을 구현하는 것이 아니라 시각적인 척하는 것에 관한 것입니다.
기본적으로 jsdom은 스크립트, 스타일시트, 이미지 또는 iframe과 같은 하위 리소스를 로드하지 않습니다. jsdom이 이러한 리소스를 로드하도록 하려면 사용 가능한 모든 리소스를 로드하는 resources: "usable"
옵션을 전달할 수 있습니다. 그것들은 다음과 같습니다:
<frame>
및 <iframe>
통한 프레임 및 iframe
<link rel="stylesheet">
를 통한 스타일시트
<script>
를 통한 스크립트 runScripts: "dangerously"
도 설정된 경우에만 해당)
<img>
통한 이미지( canvas
npm 패키지도 설치된 경우에만 해당)(아래 "캔버스 지원" 참조)
리소스를 로드하려고 시도할 때 url
옵션의 기본값은 "about:blank"
입니다. 이는 상대 URL을 통해 포함된 모든 리소스가 로드되지 않음을 의미합니다. (URL about:blank
에 대해 URL /something
구문 분석하려고 시도한 결과는 오류입니다.) 따라서 이러한 경우에는 url
옵션에 기본값이 아닌 값을 설정하거나 편의 중 하나를 사용하는 것이 좋습니다. 자동으로 이를 수행하는 API입니다.
jsdom의 리소스 로딩 동작을 더 완벽하게 사용자 정의하려면 ResourceLoader
클래스의 인스턴스를 resources
옵션 값으로 전달할 수 있습니다.
const ResourceLoader = 새로운 jsdom.ResourceLoader({ 프록시: "http://127.0.0.1:9001", 엄격한 SSL: 거짓, userAgent: "Mellblomenator/9000",});const dom = new JSDOM(``, { resources: resourcesLoader });
ResourceLoader
생성자에 대한 세 가지 옵션은 다음과 같습니다.
proxy
사용할 HTTP 프록시의 주소입니다.
strictSSL
false로 설정하면 SSL 인증서가 유효해야 한다는 요구 사항을 비활성화할 수 있습니다.
userAgent
전송된 User-Agent
헤더에 영향을 미치므로 navigator.userAgent
의 결과 값에 영향을 줍니다. 기본값은 `Mozilla/5.0 (${process.platform || "unknown OS"}) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/${jsdomVersion}`
입니다.
ResourceLoader
하위 클래스로 분류하고 fetch()
메서드를 재정의하여 리소스 가져오기를 추가로 사용자 정의할 수 있습니다. 예를 들어 다음은 특정 URL에 대해 제공된 응답을 재정의하는 버전입니다.
CustomResourceLoader 클래스는 jsdom.ResourceLoader를 확장합니다. fetch(url, options) {// 특이한 작업을 수행하려면 이 스크립트의 내용을 재정의합니다.if (url === "https://example.com/some-special-script.js") { return Promise.resolve( Buffer.from("window.someGlobal = 5;"));}return super.fetch(url, options); }}
jsdom은 위 섹션에 따라 "사용 가능한" 리소스를 발견할 때마다 사용자 정의 리소스 로더의 fetch()
메서드를 호출합니다. 이 메소드는 URL 문자열과 super.fetch()
호출하는 경우 수정되지 않은 상태로 전달해야 하는 몇 가지 옵션을 사용합니다. Node.js Buffer
객체에 대한 약속을 반환해야 하며, 리소스를 의도적으로 로드하지 않으려면 null
반환해야 합니다. 일반적으로 대부분의 경우 표시된 대로 super.fetch()
에 위임하려고 합니다.
fetch()
에서 받게 되는 옵션 중 하나는 리소스를 가져오는 요소(해당되는 경우)입니다.
CustomResourceLoader 클래스는 jsdom.ResourceLoader를 확장합니다. fetch(url, options) {if (options.element) { console.log(`${options.element.localName} 요소가 ${url} URL을 요청 중입니다`);}return super.fetch(url, options); }}
웹 브라우저와 마찬가지로 jsdom에는 "콘솔"이라는 개념이 있습니다. 이는 문서 내부에서 실행되는 스크립트를 통해 페이지에서 직접 전송된 정보와 jsdom 구현 자체의 정보를 모두 기록합니다. Node.js console
API 및 페이지 내부 window.console
API와 구별하기 위해 사용자 제어 가능 콘솔을 "가상 콘솔"이라고 부릅니다.
기본적으로 JSDOM
생성자는 모든 출력을 Node.js 콘솔로 전달하는 가상 콘솔이 있는 인스턴스를 반환합니다. 자신만의 가상 콘솔을 생성하고 이를 jsdom에 전달하려면 다음을 수행하여 이 기본값을 재정의할 수 있습니다.
const virtualConsole = new jsdom.VirtualConsole();const dom = new JSDOM(``, { virtualConsole });
이와 같은 코드는 동작이 없는 가상 콘솔을 생성합니다. 가능한 모든 콘솔 메서드에 대해 이벤트 리스너를 추가하여 동작을 제공할 수 있습니다.
virtualConsole.on("오류", () => { ... });virtualConsole.on("경고", () => { ... });virtualConsole.on("info", () => { ... });virtualConsole.on("dir", () => { ... });// ... 등 https://console.spec.whatwg.org/#logging 참조
(파싱 중에 오류나 콘솔 호출 스크립트가 발생할 수 있으므로 new JSDOM()
호출하기 전에 이러한 이벤트 리스너를 설정하는 것이 가장 좋습니다.)
단순히 가상 콘솔 출력을 기본 Node.js 콘솔과 같은 다른 콘솔로 리디렉션하려는 경우 다음을 수행할 수 있습니다.
virtualConsole.sendTo(콘솔);
jsdom 자체의 오류를 보고하기 위해 오류 개체와 함께 실행되는 특수 이벤트 "jsdomError"
도 있습니다. 이는 오류 메시지가 console.error
에 의해 시작되지 않은 경우에도 웹 브라우저 콘솔에 자주 표시되는 방식과 유사합니다. 지금까지 다음과 같은 오류가 이런 식으로 출력되었습니다.
하위 리소스(스크립트, 스타일시트, 프레임, iframe) 로드 또는 구문 분석 오류
true
반환하거나 event.preventDefault()
호출하는 창 onerror
이벤트 핸들러에서 처리되지 않는 스크립트 실행 오류
jsdom이 구현하지 않지만 웹 호환성을 위해 설치하는 window.alert
와 같은 메소드 호출로 인해 발생하는 구현되지 않은 오류
sendTo(c)
사용하여 c
에 오류를 보내는 경우 기본적으로 "jsdomError"
이벤트의 정보와 함께 c.error(errorStack[, errorDetail])
호출합니다. 이벤트와 메소드 호출의 엄격한 일대일 매핑을 유지하고 "jsdomError"
를 직접 처리하려는 경우 다음을 수행할 수 있습니다.
virtualConsole.sendTo(c, { 생략JSDOMErrors: true });
웹 브라우저와 마찬가지로 jsdom에는 HTTP 쿠키를 저장하는 쿠키 항아리 개념이 있습니다. 문서와 동일한 도메인에 URL이 있고 HTTP 전용으로 표시되지 않은 쿠키는 document.cookie
API를 통해 액세스할 수 있습니다. 또한 쿠키 항아리의 모든 쿠키는 하위 리소스 가져오기에 영향을 미칩니다.
기본적으로 JSDOM
생성자는 빈 쿠키 항아리가 있는 인스턴스를 반환합니다. 자신만의 쿠키 항아리를 만들어 jsdom에 전달하려면 다음을 수행하여 이 기본값을 재정의할 수 있습니다.
const cookieJar = new jsdom.CookieJar(store, options);const dom = new JSDOM(``, { cookieJar });
이는 여러 jsdom 간에 동일한 쿠키 항아리를 공유하려는 경우 또는 미리 특정 값으로 쿠키 항아리를 프라이밍하려는 경우에 주로 유용합니다.
쿠키 용기는 Tough-cookie 패키지에서 제공됩니다. jsdom.CookieJar
생성자는 브라우저 작동 방식과 더 잘 일치하기 때문에 기본적으로 looseMode: true
옵션을 설정하는 터프 쿠키 쿠키 항아리의 하위 클래스입니다. Tough-cookie의 유틸리티와 클래스를 직접 사용하려면 jsdom.toughCookie
모듈 내보내기를 사용하여 jsdom과 함께 패키지된 Tough-cookie 모듈 인스턴스에 액세스할 수 있습니다.
jsdom을 사용하면 아주 초기에 jsdom 생성에 개입할 수 있습니다. Window
및 Document
객체가 생성된 후, 문서를 노드로 채우기 위해 HTML이 구문 분석되기 전입니다.
const dom = new JSDOM(`<p>안녕하세요</p>`, { beforeParse(window) {window.document.childNodes.length === 0;window.someCoolAPI = () => { /* ... */ }; }});
이는 어떤 방식으로든 환경을 수정하려는 경우에 특히 유용합니다. 예를 들어 jsdom이 지원하지 않는 웹 플랫폼 API에 대한 shim을 추가하는 경우입니다.
JSDOM
객체 API JSDOM
객체를 생성하면 다음과 같은 유용한 기능을 갖게 됩니다.
속성 window
사용자를 위해 생성된 Window
개체를 검색합니다.
virtualConsole
및 cookieJar
속성은 전달한 옵션을 반영하거나 해당 옵션에 대해 아무것도 전달되지 않은 경우 생성된 기본값을 반영합니다.
serialize()
사용하여 문서 직렬화 serialize()
메소드는 doctype을 포함하여 문서의 HTML 직렬화를 반환합니다.
const dom = new JSDOM(`<!DOCTYPE html>hello`);dom.serialize() === "<!DOCTYPE html><html><head></head><body>hello</body></ html>";// 다음과 대조:dom.window.document.documentElement.outerHTML === "<html><head></head><body>hello</body></html>";
nodeLocation(node)
사용하여 노드의 소스 위치 가져오기 nodeLocation()
메서드는 소스 문서 내에서 DOM 노드가 있는 위치를 찾아 해당 노드에 대한 구문 분석 5 위치 정보를 반환합니다.
const dom = 새로운 JSDOM( `<p>안녕하세요 <img src="foo.jpg"> </p>`님, { includeNodeLocations: true });const document = dom.window.document;const bodyEl = document.body; // 암시적으로 생성됨const pEl = document.querySelector("p");const textNode = pEl.firstChild;const imgEl = document.querySelector("img");console.log(dom.nodeLocation(bodyEl)); // 널; sourceconsole.log(dom.nodeLocation(pEl))에 없습니다. // { startOffset: 0, endOffset: 39, startTag: ..., endTag: ... }console.log(dom.nodeLocation(textNode)); // { startOffset: 3, endOffset: 13 }console.log(dom.nodeLocation(imgEl)); // { startOffset: 13, endOffset: 32 }
이 기능은 includeNodeLocations
옵션을 설정한 경우에만 작동합니다. 성능상의 이유로 노드 위치는 기본적으로 꺼져 있습니다.
getInternalVMContext()
사용하여 Node.js vm
모듈과 인터페이스 Node.js에 내장된 vm
모듈은 jsdom의 스크립트 실행 마법을 뒷받침하는 것입니다. 스크립트를 사전 컴파일한 후 여러 번 실행하는 것과 같은 일부 고급 사용 사례는 jsdom이 생성한 Window
와 함께 vm
모듈을 직접 사용하는 것이 좋습니다.
vm
API와 함께 사용하기에 적합한 컨텍스트화된 전역 개체에 액세스하려면 getInternalVMContext()
메서드를 사용할 수 있습니다.
const { Script } = require("vm");const dom = new JSDOM(``, { runScripts: "outside-only" });const script = new Script(` if (!this.ran) { this.ran = 0; } ++this.ran;`);const vmContext = dom.getInternalVMContext();script.runInContext(vmContext);script.runInContext(vmContext);script.runInContext(vmContext);console.assert(dom.window.ran === 3);
이는 다소 고급 기능이므로 매우 특정한 요구 사항이 없는 한 일반 DOM API(예: window.eval()
또는 document.createElement("script")
)를 사용하는 것이 좋습니다.
runScripts
설정하지 않고 JSDOM
인스턴스가 생성되었거나 웹 브라우저에서 jsdom을 사용하는 경우 이 메서드는 예외를 발생시킵니다.
reconfigure(settings)
사용하여 jsdom 재구성 window
top
속성은 사양에서 [Unforgeable]
로 표시되어 있습니다. 이는 구성할 수 없는 자체 속성이므로 Object.defineProperty
사용하더라도 jsdom 내에서 실행되는 일반 코드로 재정의되거나 숨겨질 수 없음을 의미합니다.
마찬가지로, 현재 jsdom은 탐색(예: window.location.href = "https://example.com/"
설정)을 처리하지 않습니다. 그렇게 하면 가상 콘솔에서 이 기능이 구현되지 않았으며 아무 것도 변경되지 않음을 설명하는 "jsdomError"
가 발생합니다. 새 Window
또는 Document
객체는 없으며 기존 window
location
객체는 여전히 모두 동일합니다. 속성 값.
그러나 창 외부에서 작업하는 경우(예: jsdom을 생성하는 일부 테스트 프레임워크) 특수 reconfigure()
메서드를 사용하여 이들 중 하나 또는 둘 다를 재정의할 수 있습니다.
const dom = new JSDOM();dom.window.top === dom.window;dom.window.location.href === "about:blank";dom.reconfigure({ windowTop: myFakeTopForTesting, url: "https: //example.com/" });dom.window.top === myFakeTopForTesting;dom.window.location.href === "https://example.com/";
jsdom의 URL을 변경하면 window.location
, document.URL
및 document.documentURI
와 같은 현재 문서 URL을 반환하는 모든 API뿐만 아니라 문서 내의 상대 URL 확인 및 동일 출처 확인에도 영향을 미칩니다. 하위 리소스를 가져오는 동안 사용되는 리퍼러입니다. 그러나 해당 URL의 콘텐츠에 대한 탐색은 수행하지 않습니다. DOM의 내용은 변경되지 않고 그대로 유지되며 Window
, Document
등의 새 인스턴스는 생성되지 않습니다.
fromURL()
JSDOM
생성자 자체 외에도 jsdom은 URL에서 jsdom을 생성하기 위한 약속 반환 팩토리 메서드를 제공합니다.
JSDOM.fromURL("https://example.com/", options).then(dom => { console.log(dom.serialize());});
URL이 유효하고 요청이 성공하면 반환된 Promise는 JSDOM
인스턴스로 이행됩니다. 모든 리디렉션은 최종 목적지로 이어집니다.
fromURL()
에 제공되는 옵션은 JSDOM
생성자에 제공되는 옵션과 유사하며 다음과 같은 추가 제한 사항 및 결과가 있습니다.
url
및 contentType
옵션은 제공할 수 없습니다.
referrer
옵션은 초기 요청의 HTTP Referer
요청 헤더로 사용됩니다.
resources
옵션은 초기 요청에도 영향을 미칩니다. 이는 예를 들어 프록시를 구성하려는 경우에 유용합니다(위 참조).
결과 jsdom의 URL, 콘텐츠 유형 및 리퍼러는 응답을 통해 결정됩니다.
HTTP Set-Cookie
응답 헤더를 통해 설정된 모든 쿠키는 jsdom의 쿠키 항아리에 저장됩니다. 마찬가지로 제공된 쿠키 항아리에 이미 있는 모든 쿠키는 HTTP Cookie
요청 헤더로 전송됩니다.
fromFile()
fromURL()
과 유사하게 jsdom은 파일 이름에서 jsdom을 구성하기 위한 fromFile()
팩토리 메소드도 제공합니다.
JSDOM.fromFile("stuff.html", options).then(dom => { console.log(dom.serialize());});
반환된 Promise는 주어진 파일을 열 수 있는 경우 JSDOM
인스턴스로 이행됩니다. Node.js API에서 평소와 같이 파일 이름은 현재 작업 디렉터리를 기준으로 지정됩니다.
fromFile()
에 제공되는 옵션은 JSDOM
생성자에 제공되는 옵션과 유사하며 다음과 같은 추가 기본값이 있습니다.
url
옵션은 "about:blank"
대신 주어진 파일 이름에 해당하는 파일 URL로 기본 설정됩니다.
주어진 파일 이름이 .xht
, .xhtml
또는 .xml
로 끝나는 경우 contentType
옵션의 기본값은 "application/xhtml+xml"
입니다. 그렇지 않으면 계속 기본값이 "text/html"
입니다.
fragment()
가장 간단한 경우에는 관련된 모든 기능을 갖춘 전체 JSDOM
인스턴스가 필요하지 않을 수도 있습니다. Window
이나 Document
필요하지 않을 수도 있습니다! 대신 HTML을 구문 분석하고 조작할 수 있는 DOM 개체를 가져오기만 하면 됩니다. 이를 위해 주어진 문자열에서 DocumentFragment
를 생성하는 fragment()
있습니다.
const frag = JSDOM.fragment(`<p>안녕하세요</p><p><strong>안녕하세요!</strong>`);frag.childNodes.length === 2;frag.querySelector("strong"). textContent === "안녕하세요!";// 기타
여기서 frag
제공된 문자열을 구문 분석하여 내용이 생성되는 DocumentFragment
인스턴스입니다. 구문 분석은 <template>
요소를 사용하여 수행되므로 거기에 모든 요소( <td>
와 같은 이상한 구문 분석 규칙이 있는 요소 포함)를 포함할 수 있습니다. 결과 DocumentFragment
연관된 탐색 컨텍스트가 없다는 점에 유의하는 것도 중요합니다. 즉, 요소의 ownerDocument
에는 null defaultView
속성이 있고 리소스는 로드되지 않습니다.
fragment()
팩토리를 호출하면 동일한 템플릿 소유자 Document
공유하는 DocumentFragment
가 생성됩니다. 이를 통해 추가 오버헤드 없이 fragment()
여러 번 호출할 수 있습니다. 그러나 이는 또한 어떤 옵션을 사용하여도 fragment()
호출을 사용자 정의할 수 없음을 의미합니다.
전체 JSDOM
객체와 마찬가지로 DocumentFragment
의 직렬화는 쉽지 않습니다. DOM을 직렬화해야 한다면 아마도 JSDOM
생성자를 더 직접적으로 사용해야 할 것입니다. 그러나 단일 요소를 포함하는 조각의 특수한 경우에는 일반적인 방법을 통해 매우 쉽게 수행할 수 있습니다.
const frag = JSDOM.fragment(`<p>안녕하세요</p>`);console.log(frag.firstChild.outerHTML); // "<p>안녕하세요</p>"를 기록합니다.
jsdom에는 canvas
패키지를 사용하여 캔버스 API로 <canvas>
요소를 확장할 수 있는 지원이 포함되어 있습니다. 이 작업을 수행하려면 프로젝트에 jsdom
의 피어로 canvas
종속성으로 포함해야 합니다. jsdom이 canvas
패키지를 찾을 수 있으면 이를 사용하지만 존재하지 않으면 <canvas>
요소는 <div>
처럼 동작합니다. jsdom v13부터 canvas
버전 2.x가 필요합니다. 버전 1.x는 더 이상 지원되지 않습니다.
문자열을 제공하는 것 외에도 JSDOM
생성자는 Node.js Buffer
또는 ArrayBuffer
, Uint8Array
, DataView
등과 같은 표준 JavaScript 바이너리 데이터 유형의 형태로 바이너리 데이터를 제공할 수도 있습니다. 이 작업이 완료되면 jsdom이 스니핑합니다. 제공된 바이트에서 인코딩하여 브라우저와 마찬가지로 <meta charset>
태그를 검색합니다.
제공된 contentType
옵션에 charset
매개변수가 포함된 경우 해당 인코딩은 UTF-8 또는 UTF-16 BOM이 존재하지 않는 한 스니핑된 인코딩을 재정의합니다. 이 경우 UTF-8 또는 UTF-16 BOM이 우선 적용됩니다. (다시 말하지만 이것은 브라우저와 같습니다.)
이 인코딩 스니핑은 JSDOM.fromFile()
및 JSDOM.fromURL()
에도 적용됩니다. 후자의 경우 생성자의 contentType
옵션과 동일한 방식으로 응답과 함께 전송된 모든 Content-Type
헤더가 우선순위를 갖습니다.
많은 경우 이러한 방식으로 바이트를 제공하는 것이 문자열을 제공하는 것보다 나을 수 있습니다. 예를 들어 Node.js의 buffer.toString("utf-8")
API를 사용하려고 하면 Node.js는 선행 BOM을 제거하지 않습니다. 그런 다음 이 문자열을 jsdom에 제공하면 BOM은 그대로 유지하면서 그대로 해석합니다. 그러나 jsdom의 바이너리 데이터 디코딩 코드는 브라우저처럼 주요 BOM을 제거합니다. 이러한 경우 buffer
직접 제공하면 원하는 결과를 얻을 수 있습니다.
jsdom의 타이머( window.setTimeout()
또는 window.setInterval()
로 설정)는 정의에 따라 향후 창 컨텍스트에서 코드를 실행합니다. 프로세스를 활성 상태로 유지하지 않고는 나중에 코드를 실행할 수 없으므로 뛰어난 jsdom 타이머가 Node.js 프로세스를 활성 상태로 유지합니다. 마찬가지로, 객체를 활성 상태로 유지하지 않고 객체의 컨텍스트에서 코드를 실행할 수 있는 방법이 없기 때문에 뛰어난 jsdom 타이머는 예약된 창의 가비지 수집을 방지합니다.
jsdom 창을 확실히 종료하려면 window.close()
사용하세요. 그러면 실행 중인 모든 타이머가 종료됩니다(또한 창과 문서의 모든 이벤트 리스너도 제거됩니다).
Node.js에서는 Chrome DevTools를 사용하여 프로그램을 디버그할 수 있습니다. 시작하는 방법은 공식 문서를 참조하세요.
기본적으로 jsdom 요소는 콘솔에서 기존의 일반 JS 객체로 형식화됩니다. 디버깅을 더 쉽게 하려면 jsdom-devtools-formatter를 사용하면 실제 DOM 요소처럼 검사할 수 있습니다.
사람들은 jsdom을 사용할 때 비동기 스크립트 로딩에 문제가 있는 경우가 많습니다. 많은 페이지가 스크립트를 비동기식으로 로드하지만 언제 로드가 완료되었는지, 즉 코드를 실행하고 결과 DOM 구조를 검사하기에 좋은 시기가 언제인지 알 수 있는 방법이 없습니다. 이는 근본적인 한계입니다. 우리는 웹 페이지의 스크립트가 어떤 작업을 수행할지 예측할 수 없으므로 추가 스크립트 로드가 언제 완료되었는지 알려줄 수 없습니다.
이 문제는 몇 가지 방법으로 해결될 수 있습니다. 문제의 페이지를 제어하는 경우 가장 좋은 방법은 로드가 완료되는 시기를 감지하기 위해 스크립트 로더가 제공하는 모든 메커니즘을 사용하는 것입니다. 예를 들어 RequireJS와 같은 모듈 로더를 사용하는 경우 코드는 다음과 같습니다.
// Node.js 측에서:const window = (new JSDOM(...)).window;window.onModulesLoaded = () => { console.log("출시 준비 완료!");};
<!-- jsdom에 제공하는 HTML 내부 --><script>requirejs(["entry-module"], () => { window.onModulesLoaded();});</script>
페이지를 제어하지 않는 경우 특정 요소의 존재 여부를 폴링하는 등의 해결 방법을 시도해 볼 수 있습니다.
자세한 내용은 #640의 토론, 특히 @matthewkastor의 통찰력 있는 의견을 참조하세요.
우리는 jsdom에 새로운 기능을 추가하고 최신 웹 사양을 유지하는 것을 좋아하지만 API가 많이 누락되어 있습니다. 누락된 부분이 있으면 언제든지 문제를 제출해 주세요. 하지만 저희 팀은 규모가 작고 바쁘기 때문에 끌어오기 요청이 더 잘 작동할 수도 있습니다.
jsdom의 일부 기능은 종속성에 의해 제공됩니다. 이와 관련된 주목할만한 문서에는 CSS 선택기 엔진인 nwsapi
에 대해 지원되는 CSS 선택기 목록이 포함되어 있습니다.
아직 다루지 못한 기능 외에도 현재 jsdom의 범위를 벗어나는 두 가지 주요 기능이 있습니다. 이것들은 다음과 같습니다:
탐색 : 링크를 클릭하거나 location.href
또는 유사한 항목을 할당할 때 전역 개체 및 기타 모든 개체를 변경하는 기능입니다.
레이아웃 : CSS의 결과로 요소가 시각적으로 배치될 위치를 계산하는 기능으로, getBoundingClientRects()
와 같은 메서드나 offsetTop
과 같은 속성에 영향을 미칩니다.
현재 jsdom에는 탐색을 위해 가상 콘솔에 "구현되지 않은" "jsdomError"
보내거나 많은 레이아웃 관련 속성에 대해 0을 반환하는 등 이러한 기능의 일부 측면에 대한 더미 동작이 있습니다. 크롤링 중에 "탐색"하는 각 페이지에 대해 새 JSDOM
인스턴스를 생성하거나 Object.defineProperty()
사용하여 다양한 레이아웃 관련 getter 및 메서드가 반환하는 내용을 변경하는 등 코드에서 이러한 제한 사항을 해결할 수 있는 경우가 많습니다.
PhantomJS와 같은 동일한 공간의 다른 도구는 이러한 기능을 지원합니다. Wiki에는 jsdom과 PhantomJS에 대한 더 완전한 글이 있습니다.
jsdom은 자원봉사자 팀이 유지 관리하는 커뮤니티 중심 프로젝트입니다. 다음을 통해 jsdom을 지원할 수 있습니다.
Tidelift 구독의 일부로 jsdom에 대한 전문적인 지원을 받습니다. Tidelift는 팀에게 유지 관리, 라이센스 및 보안에 대한 확신을 제공하는 동시에 오픈 소스를 지속 가능하게 만드는 데 도움을 줍니다.
프로젝트에 직접 기여합니다.
jsdom에 대한 도움이 필요하면 다음 장소 중 하나를 자유롭게 이용하십시오.
메일링 리스트("어떻게 해야 하나요?"에 대한 질문에 가장 적합)
이슈 트래커(버그 보고서에 가장 적합)
매트릭스 룸: #jsdom:matrix.org