Jsdom: كيف تقوم بتحميل البرامج النصية الخارجية؟

تم إنشاؤها على ٧ يوليو ٢٠١٧  ·  3تعليقات  ·  مصدر: jsdom/jsdom

يمكن لـ jsdom تشغيل نصوص مضمنة داخل علامة <head> للمستند ، ولكن كيف تجعلها تشغل البرامج النصية المرتبطة في رأس المستند عبر <script src=""> ؟

للخيارات التي أستخدمها:

{
    url: url,
    resources: 'usable',
    runScripts: 'dangerously',
}

معلومات أساسية:

  • إصدار Node.js: 8.1.2
  • إصدار jsdom: 11.1.0

حالة التكاثر الأدنى:

// index.js
const request = require('request')
const jsdom = require('jsdom')
const {JSDOM} = jsdom
const url = 'http://localhost:8000'

request(url, (error, response, body) => {
  const options = {
    url: url,
    resources: 'usable',
    runScripts: 'dangerously',
  }

  const dom = new JSDOM(body, options)

  console.log(dom.window.document.body.children.length) // Expecting to see `1`
  console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
})
// external.js
document.addEventListener('DOMContentLoaded', () => {
  document.write('<h1>Hello world!</h1>')
})
<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JSDOM test</title>
    <script src="external.js"></script>
  </head>
  <body>
  </body>
</html>

أكمل مثال العمل الأدنى: https://github.com/cg433n/jsdom-test

التعليق الأكثر فائدة

المشكلة هنا هي أن DOMContentLoaded حدث غير متزامن. أنت تقوم بتسجيل الدخول قبل أن تتاح له فرصة حدوث ذلك. أنت بحاجة إلى الانتظار حتى إطلاق النار ؛ عندها فقط سيحدث document.write() .

ربما يجب أن يعمل شيء مثل هذا:

const dom = new JSDOM(body, options)

dom.window.document.addEventListener('DOMContentLoaded', () => {
  // We need to delay one extra turn because we are the first DOMContentLoaded listener,
  // but we want to execute this code only after the second DOMContentLoaded listener
  // (added by external.js) fires.
  setImmediate(() => {
    console.log(dom.window.document.body.children.length) // Expecting to see `1`
    console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
  });
});

ال 3 كومينتر

المشكلة هنا هي أن DOMContentLoaded حدث غير متزامن. أنت تقوم بتسجيل الدخول قبل أن تتاح له فرصة حدوث ذلك. أنت بحاجة إلى الانتظار حتى إطلاق النار ؛ عندها فقط سيحدث document.write() .

ربما يجب أن يعمل شيء مثل هذا:

const dom = new JSDOM(body, options)

dom.window.document.addEventListener('DOMContentLoaded', () => {
  // We need to delay one extra turn because we are the first DOMContentLoaded listener,
  // but we want to execute this code only after the second DOMContentLoaded listener
  // (added by external.js) fires.
  setImmediate(() => {
    console.log(dom.window.document.body.children.length) // Expecting to see `1`
    console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
  });
});

فهمت! أنتم يا رفاق رائعون - استمروا في العمل الجيد!

ملاحظة: سمتان من العرض التوضيحي أعلاه محفوفة بالمخاطر.

اختراق FS

بدلاً من ذلك ، أوصي باستخدام fs لقراءة وتحميل أكواد js من الملفات ، راجع Stackoverflow بناءً على نهجEricRicketts ' FS.read() في # 3023 و Domenic addEventListener() في # 1914. يتضمن عرض العمل الذي أقترحه ما يلي:

  • استخدم fs.readFileSync لتحميل js الخارجية إلى html كسلاسل
  • حلقة للتعامل مع عدة ملفات شبيبة خارجية
  • استخدام حالة إطلاق وظائف js الخارجية
  • استخدام حالة تمرير المتغيرات الطرفية إلى العقدة ، ثم إلى وظائف js خارجية

من المحتمل أن يمنعك هذا من إجراء مكالمات xhr / API وبالتالي يحل المشكلة جزئيًا فقط.

عناوين URL

لم أستطع معرفة طريقة عمل عنوان url.
من الناحية المثالية ، سيكون موضع ترحيب حد أدنى محدث من JSDOM تحميل ملفات external.js عبر عرض عمل url . :قلب:

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

tolmasky picture tolmasky  ·  4تعليقات

drewish picture drewish  ·  4تعليقات

camelaissani picture camelaissani  ·  4تعليقات

potapovDim picture potapovDim  ·  4تعليقات

lehni picture lehni  ·  4تعليقات