Jsdom: دعم WebComponents API

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

نحن نحاول استخدام jsdom في اختبارات الوحدة الخاصة بنا لـ React core (http://facebook.github.io/react/).

لسوء الحظ ، لا يدعم jsdom مواصفات مكونات الويب أصلاً ، ولا يعمل webcomponents.js polyfill على jsdom. تتطلب هذه المشكلة إضافة دعم WebComponent (عناصر مخصصة ، shadow dom ، عمليات استيراد html ، إلخ).

feature

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

TL ؛ DR

لقد عملت خلال الأسبوعين الماضيين على تقييم جدوى إضافة دعم للعنصر المخصص في jsdom. ها هي نتيجة التحقيق.

يمكنك العثور على تنفيذ متوافق مع المواصفات للعنصر المخصص هنا: https://github.com/jsdom/jsdom/compare/master...pmdartus : custom-element؟ expand = 1. لا تزال هناك بعض الجوانب الخشنة هنا وهناك ، ولكن على الأقل معظم اجتياز اختبار WPT . الاختبارات الفاشلة المتبقية هي إما مشكلات JSDOM المعروفة أو مشكلات ثانوية يمكن معالجتها عندما نتعامل مع التنفيذ الفعلي في jsdom.

الآن هذه هي الأخبار السارة ، الآن بعد أن تم دعم Shadow DOM محليًا ، مع كل من فرع العنصر المخصص ومراقب الطفرات ، تمكنت من تحميل وتقديم أحدث إصدار من مثال تطبيق Polymer 3 hello world في jsdom 🎉. في حالته الحالية ، لا يتمكن الفرع من تحميل تطبيق Stencil (يتطلب وضع Stencil dev بعض الميزات غير المدعومة مثل module ، ويظهر وضع prod لسبب غير معروف).

خطة عمل

فيما يلي قائمة بالتغييرات التي يجب أن تحدث أولاً من قبل ، والبدء في معالجة التنفيذ الفعلي لمواصفات العنصر المخصص. كل عنصر في القائمة مستقل ويمكن معالجته بشكل متوازٍ.

دعم السمات الموسعة لـ [CEReactions] IDL

إحدى السمات الأساسية المفقودة وظيفيًا في jsdom لإضافة دعم للعناصر المخصصة هي سمات [CEReactions] . تمكنت جزئيًا من التغلب على هذه المشكلة عن طريق تصحيح خصائص النموذج الأولي الصحيح. يعمل هذا النهج طالما أن مكدس تفاعل العنصر المخصص عام وليس لكل وحدة من سياقات التصفح ذات الأصل المتشابه حيث يتم مشاركة جميع نماذج الواجهات الأولية.

هذا الأسلوب به بعض أوجه القصور حيث أن بعض الواجهات لها سمات [CEReactions] المرتبطة بالخصائص المفهرسة ( HTMLOptionsCollection ، DOMStringMap ). داخليًا ، يستخدم jsdom البروكسيات لتتبع الطفرة في تلك الخصائص. لا يعمل تصحيح النموذج الأولي للواجهة في هذه الحالة. هناك طريقة أخرى للتغلب على هذه المشكلة وهي تصحيح التطبيق بدلاً من الواجهة (غير مطبق).

لست على دراية كافية بـ webidl2js الداخلي ، ولكن يجب علينا استكشاف إضافة خطاف عام مقابل [CEReactions] ؟

التغييرات:

دعم السمات الموسعة لـ [HTMLConstructor] IDL

كما أوضح domenic أعلاه ، فإن إضافة دعم لـ [HTMLConstructor] هو أحد العوائق الرئيسية هنا.

لقد تمكنت من التغلب على هذه المشكلة هنا عن طريق تصحيح مُنشئ الواجهة لكل سياق تصفح. سيكون مُنشئ الواجهة قادرًا على الوصول إلى النافذة الصحيحة وكائن المستند مع الاحتفاظ بالنموذج الأولي المشترك. يتجنب هذا النهج أيضًا عبء الأداء لإعادة تقييم النموذج الأولي للواجهة لكل سياق تصفح جديد.

لست متأكدًا مما إذا كان هذا هو أفضل نهج هنا ، لكنه يناسب المتطلبات دون تقديم أداء إضافي.

التغييرات:

جعل خوارزمية جعل تحليل الجزء متوافقة مع المواصفات (# 2522)

كما تمت مناقشته هنا ، تطبيق algo لتحليل جزء HTML المستخدم في Element.innerHTML و Element.outerHTML غير صحيح. تحتاج خوارزمية التحليل إلى إعادة بنائها ، حتى يتم استدعاء عمليات رد نداءات تفاعلات العنصر المخصص بشكل صحيح.

التغييرات:

تحسين البحث عن الواجهة لإنشاء عنصر algo

كانت إحدى المشكلات التي عثرت عليها بسرعة ، هي إدخال تبعيات دائرية جديدة عند إضافة دعم لإنشاء عنصر مخصص. يتطلب كل من CustomElementRegistry و إنشاء خوارزمية عنصر الوصول إلى واجهات Element ، مما يخلق تبعيات دائرية كابوس.

كان الأسلوب المتبع في الفرع هو إنشاء InterfaceCache ، والذي من شأنه أن يسمح بالبحث في الواجهة عن طريق مساحة اسم العنصر والاسم ولكن أيضًا عن طريق اسم الواجهة. يتم تقييم وحدات الواجهة بشكل كسول وتخزينها مؤقتًا بمجرد تقييمها. يتخلص هذا النهج من التبعيات الدائرية لأن الواجهات لم تعد مطلوبة في المستوى الأعلى بعد الآن.

هذه طريقة واحدة لحل هذه المشكلة طويلة الأمد في jsdom ، وإحدى هذه المشكلات في هذا النهج هي أنه ربما يكسر إصدار حزمة الويب / المستعرض من jsdom (لم يتم اختباره).

التغييرات:

~ إصلاح Element.isConnected لدعم Shadow DOM (https://github.com/jsdom/jsdom/pull/2424)~

هذه مشكلة تراجعت مع إدخال Shadow DOM ، حيث تقوم isConnected بإرجاع false إذا كان العنصر جزءًا من شجرة الظل. يجب إضافة اختبار WPT جديد هنا ، حيث لا يوجد اختبار يتحقق من هذا السلوك.

التغييرات:

إصلاح مستندات HTMLTemplateElement.templateContents عقدة (# 2426)

تحتوي محتويات القالب كما هو محدد في المواصفات على مستند عقدة مختلف عن HTMLTemplateElement نفسه. لا يطبق jsdom هذا السلوك اليوم ، كما أن HTMLTemplateElement ومحتويات القالب تشترك فيهما
عقدة الوثيقة.

التغييرات:

  • HTMLTemplateElement-impl.js
  • htmltodom.js . هذا التغيير له أيضًا بعض التأثير المتجه إلى المصب على المحلل اللغوي. إذا كان عنصر السياق عبارة عن HTMLTemplateElement ، فيجب أن تلتقط خوارزمية تحليل جزء HTML عقدة المستند من محتوى القالب وليس من العنصر نفسه.

أضف خطوات اعتماد مفقودة إلى HTMLTemplateElement (# 2426)

يحتاج HTMLTemplateElement إلى تشغيل بعض الخطوات المحددة عند اعتماده في مستند آخر. وبقدر ما أعلم ، فإن واجهة التربة لها خطوة اعتماد خاصة. سيحتاج تطبيق خوارزمية اعتماد العقدة أيضًا إلى التحديث لاستدعاء خطوة التبني هذه.

التغييرات:

إضافة دعم لبحث isValue في المسلسل parse5

تختلف أجزاء HTML المتسلسلة ، عند إجراء تسلسل لبحث عنصر ، تكون القيمة المرتبطة بالعنصر وتعكسها كسمة في المحتوى المتسلسل. سيكون من المثير للاهتمام إضافة خطاف آخر في محول الشجرة parse5 ، والذي سيبحث عن القيمة المرتبطة بالعنصر getIsValue(element: Element): void | string .

تتمثل الطريقة البديلة (غير المطبقة) في إضافة تغيير سلوك الخطاف الحالي getAttrList لإرجاع قيمة is إلى قائمة السمات ، إذا كان للعنصر قيمة مرتبطة.

أداء

قبل القيام بأي تحسين للأداء ، أردت أيضًا التحقق من أداء التغييرات في الفرع. تضيف إضافة العناصر المخصصة زيادة في الأداء بنسبة 10٪ مقارنة بالنتيجة الحالية على المستوى الرئيسي لمعايير طفرة الشجرة. ومع ذلك ، فإن إنشاء بيئة JSDOM الجديدة أصبح الآن أبطأ من 3x إلى 6x مقارنةً بالبيئة الرئيسية ، فقد يتطلب الأمر تحقيقًا أعمق لتحديد السبب الجذري.

مزيد من التفاصيل: هنا

ال 89 كومينتر

سيكون من المثير للاهتمام البحث عن واجهات برمجة التطبيقات webcomponents.js التي لا يدعمها jsdom. إذا اضطررت إلى التخمين ، فسيكون ذلك أسهل بكثير في التنفيذ من مواصفات مكونات الويب الكاملة.

ومع ذلك ، سيكون من الرائع تنفيذ مكونات الويب. ربما ليس بالصعوبة التي قد يعتقدها المرء - المواصفات صغيرة نسبيًا.

كان لدي وقت للتعمق في هذا قليلاً:

أولاً ، ليس لدينا Window معرّفًا في نطاق النافذة. لقد قمت للتو بتصحيح هذا باستخدام this.Window = this.prototype في المُنشئ Window .
ثانيًا ، تتوقع webcomponentsjs أن يكون لدى Window نموذج أولي آخر ، أي النموذج الأولي EventTarget ، والذي لا نطبقه ككيان منفصل.

مجرد القليل من المعلومات ، لأنه كان لدي القليل من الوقت.

لطيف - جيد. يجب أن تكون قادرة على كشف النافذة بسهولة تامة. يعد النموذج الأولي EventTarget أصعب قليلاً ولكنه يبدو ممكنًا نظرًا لكيفية تنفيذنا لهذه الأشياء حاليًا ؛ لقد كان TODO لي.

حسنًا ، التصحيحات سهلة إلى حد ما حتى الآن:

  • [x] this.Window = Window; في مُنشئ النوافذ
  • [x] inherits(dom.EventTarget, Window, dom.EventTarget.prototype); بعد تعريف النافذة

يحدث الانهيار التالي في webcomponents.js بسبب عدم قيامنا بتنفيذ HTMLUnknownElement (# 1068) ، بعد التألق بأننا نحتاج إلى تنفيذ SVGUseElement . هذا ما أحظر عليه حاليًا ، لأن webcomponents.js على ما يبدو لا يحب SVGUseElement المتلألئ بواسطة HTMLDivElement ويلقي تأكيدًا.

حسنًا ، لقد قمت بتسجيل الدخول إلى Polyfill أكثر ، نحتاج إلى تنفيذ / تحتاج إلى تقشير ما يلي:

  • [x] HTMLUnknownElement # 1068
  • [] SVGUseElement
  • [] window.CanvasRenderingContext2D
  • [] مجموعة واجهات برمجة التطبيقات (بما في ذلك: document.getRange() ، window.getSelection() ، window.Range ، window.Selection ؛ # 804 قد تكون البداية)
  • [] npm i canvas

(قائمة غير شاملة في الوقت الحالي)

البداية هي شيء من هذا القبيل:

jsdom.env({
  file: __dirname + '/index.htm', // refers to webcomponent.js
  created: function (err, window) {
    jsdom.getVirtualConsole(window).sendTo(console)

    window.document.createRange = function () { }
    window.getSelection = function () { }
    window.Range = function () { }
    window.Selection = function () { }
    window.CanvasRenderingContext2D = function () { } // Object.getPrototypeOf(require("canvas")(0,0).getContext("2d")) might be better
    window.SVGUseElement = window.HTMLUnknownElement
  },
  done: function (err, window) {
    console.log(err[0].data.error);
    console.log(window.CustomElements)
  },
  features: {
    ProcessExternalResources: ['script']
  }
});

بعد القيام بذلك ، هناك بعض الأخطاء في مُنشئ HTMLDocument الخاص بنا ، مما يؤدي إلى الحد الأقصى لخطأ مكدس الاستدعاءات. المُنشئ في الوقت الحالي للاستخدام الداخلي فقط ، ولكن من الصحيح أن بعض البرامج النصية على الموقع تقوم بإجراء مكالمات إليها ، لذلك نحتاج إلى جعل هذا المنشئ متاحًا للاستهلاك العام.

أحب أن أرى WebComponents على jsdom ، خاصة مع زيادة شعبية Polymer ، سيكون من الرائع أن تكون قادرًا على اختبار العناصر المخصصة على نظام بدون رأس.

في الوقت الحالي ، لا يوجد تعريف عبر المستعرضات لمكونات الويب ، لذلك سيكون من السابق لأوانه التنفيذ. (لن نقوم فقط بنسخ Chrome.) في غضون ذلك ، يمكنك تجربة استخدام Polymer مع jsdom.

@ دومينيك عادل بما فيه الكفاية. حسنًا ، إنه دعم WebComponents.js polyfill الذي أسعى إليه ، لأن هذا ما يعتمد عليه Polymer - أو webcomponents-lite (تملأ جميع هذه العناصر باستثناء Shadow DOM) في الوقت الحالي. بذلت بضع محاولات لجعل Polymer يعمل على jsdom ، لكن لم يحالفني الحظ حتى الآن - أفترض أن مهام Sebmaster في التعليق أعلاه ستحتاج على الأقل إلى التصحيح أولاً.

ما أفهمه هو أن هناك ثلاث حزم منفصلة في السؤال. واحد في OP منفصل عن البوليمر. ثم هناك polyfills webcomponents.org ، والتي كانت تستخدم في البوليمر القديم. ثم في Polymer 1.0 ، لديهم polyfills الخاصة بهم ، على ما أعتقد ، والتي ليست في الحقيقة polyfill ، ولكن بدلاً من ذلك مكتبات بديلة تقوم بأشياء نوعًا ما مكون ويب. ربما هذا هو webcomponents-lite بالرغم من ذلك.

في WebComponentsJS repo ، تقول أن webcomponentsjs-lite هو متغير ، يوفر polyfills لجميع _but_ Shadow DOM ، والذي يحاول Polymer بعد ذلك بشكل مستقل استخدام نظام Shady DOM الخاص بهم. لذلك أنا متأكد من أن Polymer تعتمد على WebComponents بقدر ما تستطيع ، مع WebComponentsJS polyfill الذي يقوم بالعمل الشاق. من المفترض أن تكون النسخة الخفيفة أقل وزنًا بشكل ملحوظ (بما يكفي من المرح ..) لذا سأرى ما إذا كان بإمكاني تحديد ما يحتاجه jsdom للإصدار البسيط. ما رأيك في فرص الحصول على polyfill (خفيف أو كامل) يعمل في jsdom؟

من الصعب حقًا القول بدون إجراء بعض التحقيقات ... أتطلع إلى ما تكتشفه.

نعم ، أعتقد أن قائمة مهام المهام التي يجب القيام بها لا تزال قابلة للتطبيق ومطلوبة لاستخدام الحشوات. قد يؤدي دمج رقم 1227 إلى جعلنا أسرع كثيرًا في تنفيذ واجهات متوافقة مع المعايير حتى نتمكن من إصلاح الواجهات المفقودة بسرعة أكبر.

لقد بدأت (ربما بسذاجة) في العمل على إضافة CustomElementsRegistry كطريقة لفهم كيفية بناء jsdom. لقد أضفت "عناصر مخصصة / عناصر مخصصة-ريجستري / تعريف.html" إلى قائمة اختبارات منصة الويب ويتم تمريرها عندما لا يكون من المفترض أن تفعل ذلك (لم أقم بتنفيذ ما يكفي تقريبًا حتى الآن). أنا متأكد من أن الاختبار لا يعمل حقًا لأن إضافة throw في الجزء العلوي من الاختبار لن يمنعه من اجتيازه. لذلك من الواضح أنني فاتني شيء ما ؛ بصرف النظر عن إضافة الاختبار في test/web-platform-tests/index.js ، هل هناك أي شيء آخر يجب أن أفعله؟

يبدو أن هذا سبب فشلنا في السطر الأول const testWindow = iframe.contentDocument.defaultView; لأن contentDocument غير محدد لسبب ما. قد تكون مشكلة في أمر التحميل لدينا مقابل تنفيذ البرنامج النصي ، لكن لم يتم التعمق في ذلك. أتمنى أن يساعدك ذلك في التغلب على ذلك. قد نضطر إلى تبسيط الاختبار لأغراضنا (في الوقت الحالي).

هذا يساعد كثيرا ، شكرا! سأرى ما إذا كان بإمكاني اكتشاف ما يجري هناك ، وإذا لم يكن الأمر كذلك ، فسوف أقوم بإنشاء اختبار مبسط كما أوصيت.

Sebmaster فقط في حالة اهتمامك ، قمت ببعض البحث حول ما يجري في هذا الاختبار وكانت النتائج مفاجئة بالنسبة لي.

يستخدم الاختبار ميزة الوصول المسماة لـ html . هذا يعني أنه يمكنك القيام بأشياء مثل:

<div id="foo"></div>
<script>
  console.log(window.foo === document.getElementById('foo'));
</script>

_ومع ذلك ، إذا كان العنصر يحتوي على سياق تصفح متداخل ، فيجب أن يشير العام إلى ذلك بدلاً من ذلك (انظر المواصفات المرتبطة). بالنسبة إلى iframe ، يكون هذا هو contentWindow . jsdom يحصل على هذا بشكل صحيح ، حتى أن هناك اختبارًا . سفاري هو الصحيح أيضا.

الجنون هو أن Chrome و Firefox يخطئون في فهم ذلك ؛ النقاط العامة إلى iframe ، وليس contentWindow. عند رؤية هذا ، افترضت أنه كان خطأ jsdom وقمت ببعض الصيد ، وفي النهاية وجدت هذا الاختبار ، الذي قادني إلى المواصفات.

TLDR. العمل على jsdom تعليمي للغاية وأنتم تقومون بعمل رائع.

الذهاب إلى ملف الخلل في المتصفحات المعنية. سأرسل أيضًا PR إلى اختبارات منصة الويب ، وجدت بعض الأخطاء الأخرى في الاختبار أيضًا.

يعد هذا دافعًا أكبر للاختبارات الأولية مثل https://github.com/tmpvar/jsdom/blob/master/test/living-html/itled-properties-window.js إلى WPT. شكرا لك على النشر! إنه يجعلني أشعر بالرضا حيال jsdom ^ _ ^

أهلا!

تمكنت من جعل Custom Elements polyfill تعمل مع jsdom من خلال الدمج

ملاحظة: يستخدم الريبو jsdom 8.5.0. والسبب هو أنني نجحت فقط مع MutationObserver polyfill ، الذي يستخدم أحداث الطفرة داخليًا. تمت إزالة أحداث الطفرة بعد 8.5.0 بسبب الأداء السيئ. إذا ظهر برنامج Mutation Observer الأصلي ، فسوف أزيل polyfill وأحدث آخر jsdom.

لقد حصلت على أحدث إصدار من jsdom ، و https://github.com/WebReflection/document-register-element يعمل من أجلي! لقد كنت أجرب المزيد من polyfills الرسمية ، وأواجه مشكلة لسبب ما. هدفي هو تشغيل عناصر مخصصة على الأقل واستيراد html ... سيكون رائعًا لو تمكنا من تشغيل Polymer أيضًا.

يمكنني تشغيل نصوص البوليمر بدون أخطاء. يمكنني حتى إنشاء مكون وتمريره إلى مُنشئ البوليمر. بعد ذلك تفشل بصمت. أعتقد أن Shadow DOM هي المشكلة.

لقد كنت أحاول تشغيل webcomponentsjs HTML لاستيراد polyfill. يمكنني تشغيل البرنامج النصي ، وأعتقد أن عمليات استيراد HTML الخاصة بي تنفذ طلب xmlhttprequest ، لكن لا يبدو أنه يتم تشغيل البرامج النصية في عمليات الاستيراد.

هل تهتم بمشاركة مثالlastmjs؟ أنا حاليًا أعماق الركبة في مكونات الويب بنفسي. إذا كان بإمكاني تقديم المساعدة ، فسأكون سعيدًا بالمساهمة معك.

snuggs شكرا! أعطني يومًا أو يومين ، فأنا في منتصف بعض الأشياء الملحة في الوقت الحالي.

snuggs إذا تمكنا من تشغيل polyfill webcomponents-lite ، يجب أن نكون قادرين على استخدام Polymer. يبدو Shadow DOM أنه أصعب عملية تعديل تعبئة حتى الآن ، وإذا استخدمنا webcomponents-lite فلن نقلق بشأن ذلك في الوقت الحالي ، لأنه سيكون لدينا وصول إلى template و custom elements و HTML imports .

يمكنني الحصول على واردات HTML للعمل مع polyfill webcomponents-lite . كنت أواجه سلوكًا غريبًا ، ثم صادفت هذا: https://github.com/Polymer/polymer/issues/1535 يبدو أنه لا يمكن تحميل واردات HTML إلا عبر بروتوكول بدون ملفات ممكّن لـ cors. لذلك قمت بإنشاء خادم http سريع في الدليل الجذر لمشروعي:

npm install -g http-server
http-server --cors

وإليكم الكود الأساسي الذي كنت أعمل به:

const jsdom = require('jsdom');

const doc = jsdom.jsdom(`
    <!DOCTYPE html>

    <html>
        <head>
            <script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
            <link rel="import" href="http://localhost:8080/bower_components/polymer/polymer.html">
        </head>

        <body>
            <test-app></test-app>

            <dom-module id="test-app">
                <template>
                </template>

                <script>
                    setTimeout(() => {
                        class TestApp {
                            beforeRegister() {
                                this.is = 'test-app';
                                console.log('before register');
                            }

                            ready() {
                                console.log('ready');
                            }

                            created() {
                                console.log('created');
                            }

                            attached() {
                                console.log('attached');
                            }
                        }

                        Polymer(TestApp);
                    }, 1000);
                </script>
            </dom-module>
        </body>
    </html>
`, {
    virtualConsole: jsdom.createVirtualConsole().sendTo(console)
});

لسبب ما ، لا بد لي من التفاف إنشاء مثيل TestApp بـ setTimeout . يبدو أن استيراد Polymer HTML لا يمنع عرض باقي HTML ، لذلك بدون setTimeout لا يتم تعريف مُنشئ البوليمر. هل هذا سلوك طبيعي لواردات HTML؟

تم استدعاء beforeRegister ، لذلك يقوم مُنشئ البوليمر بعمل شيء ما. حتى الآن لدينا عمليات استيراد HTML بشكل فعال ، وبالطبع تعمل قوالب الدورة التدريبية مع polyfill webcomponents-lite . لست متأكدًا من كيفية عمل العناصر المخصصة polyfill.

عندما أضع داخل فئة TestApp طريقة ready أو created ، لم يتم استدعائها. يبدو أنه لا يتم التعامل مع أحداث دورة الحياة بشكل صحيح. قد يكون جذر هذه المشكلة في تنفيذ متعدد تعبئة العناصر المخصصة. سأستمر في اللعب.

المشاكل المحتملة التي يتعين حلها:

  • [] لا يتم حظر استيراد HTML بشكل صحيح
  • [] عنصر مخصص polyfill يعمل أم لا؟
  • [] لم يتم استدعاء طرق دورة حياة البوليمر

المزيد من الترقيع يؤدي إلى مزيد من الأفكار. أعتقد أن ترتيب الواردات والتسجيلات قد يفسد الأمور بالنسبة لنا. عندما أقوم بتشغيل const testApp = document.createElement('test-app'); بعد استدعاء مُنشئ البوليمر ، يتم استدعاء الأسلوبين created و ready ، لكن ليس الأسلوب attached . ربما لا يتعامل jsdom مع القيم الحرفية للعنصر المخصص بشكل صحيح؟ أيضًا ، حتى عند استدعاء document.body.appendChild(testApp) ، لا يتم استدعاء طريقة دورة الحياة attached مطلقًا.

قد يساعد ذلك في فهم ترتيب التحميل: https://github.com/webcomponents/webcomponentsjs#helper -utilities

lastmjs لقد قمت حاليًا بتقليب العملات المعدنية بين CustomElementRegistry.define() و document.registerElement() . لقد رأيت أن Domenic قد قدم بعض المدخلات الرائعة ودمج بعض الأعمال المتعلقة بـ whatwg (https://github.com/whatwg/html/issues/1329) يبدو أن هناك ترحيل API جاريًا. على سبيل المثال ، أعتقد أن المواصفات تستدعي connectedCallback الذي يقترن بوظيفة attachedCallback . بافتراض أنك تعني attachedCallback عندما قلت attached لأن هذا المعالج ليس جزءًا من API. لقد واجهت define() و registerElement() إطلاق عمليات رد نداء مختلفة لكل طريقة. لقد اكتشفت إستراتيجية العناصر المخصصة. تم ذكر HTMLImports Domenic قبل تطبيق يستخدم تصحيح XMLHTTPRequest. أعتقد أنه يمكن التحويل مباشرة إلى DocumentFragment مباشرة من الاستجابة. مثل هذه الرائحة يمكن أن تكون زيت الثعبان مع "الواردات". قد يكون الاستيراد "الزائف" حيث يعيش العقل.

يبدو أيضًا أن هناك بعض الأواني مع super() يتم استدعاؤها على HTMLElement عند التحويل من ES6 -> ES5 لذا احتفظ برأيك لذلك. لقد جربت ذلك مع Rollup.js / Babel واضطررت إلى استخدام الرقاقة (خفيفة الوزن) من حزمة webcomponents.
https://developers.google.com/web/fundamentals/getting-started/primers/customelements

أخيرًا ، يبدو أنني أحقق (المزيد) من النجاح عندما أقوم بإنشاء علامة نموذج أولي.

document.createElement('main', 'test-app')

كما ذكرت domenic لي من قبل ، نريد توخي الحذر عند تنفيذ أقل مواصفات القاسم المشترك وليس مجرد تنفيذ ما تفعله GOOGLE. يبدو أن الخطوط غير واضحة مع مكونات الويب. لكني معجب.

ما هي الأساليب التي كنت تعمل بها؟

حتى الآن كنت ألعب في الغالب مع polyfills webcomponents-lite فقط ، والبوليمر <2.0. لذلك عندما ذكرت طريقة attached ، قصدت طريقة دورة حياة البوليمر التي يستخدمونها بدلاً من attachedCallback . أيضًا ، على حد علمي ، لم تتحول polyfills إلى مواصفات العناصر المخصصة الجديدة v1 حتى الآن. لذا فإن كل ما ألعب به هو فقط على أمل جعل البوليمر يعمل مع polyfills الحالية.

snuggs هل تستخدم polyfills الآن أم أنك تعمل على تطبيق فعلي في jsdom؟

lastmjs أنا لا أستخدم polyfills لأنني أشعر أنه ليس من الضروري الحصول على 80٪ من الطريق. أصبحت المنصة ناضجة بما يكفي الآن لدرجة أنه مع القليل من التغيير والتبديل في المقدمة ، يمكن فقط استخدام التركيبات الأصلية. أحب استخدام أدوات خفيفة الوزن (عادةً ما تكون ملفوفة يدويًا) بدلاً من الأطر. قال هذا ليس معظم الناس. يبدو أن القصد من Domenic هو Custom Elements 👍 استيراد html 👎 ولكن لا توجد مشكلة في تمديد طلب XMLHTTPRequest للتعامل مع fetching للمستند الذي سيصلنا إلى هناك. كان ذلك قبل حوالي 6 أشهر. لقد تغير الكثير منذ التنفيذ. من المحتمل جدا التفكير. إذن أين ننتهي منlastmjs؟

snuggs ربما يكون أكثر الأشياء عقلانية وإثباتًا للمستقبل هو تنفيذ دعم من الدرجة الأولى للعناصر المخصصة و Shadow DOM في jsdom. كلا المعيارين في الإصدار 1 ويبدو من المحتمل مما سمعته أن غالبية المتصفحات الرئيسية ستطبقهما. كيف يجب أن نفعل هذا؟ لديّ وقت محدود الآن ، لكن ربما يمكننا تحديد ما يجب القيام به على الأقل. domenic هل لديك أي اقتراحات حول كيفية المضي قدمًا في هذه التطبيقات ، أو أي أسباب تمنعنا من ذلك؟

لا توجد اقتراحات محددة مني ، باستثناء مجرد تنفيذ المواصفات :)

لدي فرع عملت فيه منذ بعض الوقت (تغيرت المواصفات قليلاً منذ ذلك الحين). كان تنفيذ CustomElementsRegistry سهلاً بدرجة كافية ، حيث واجهت صعوبة في معرفة كيفية نسج تفاعلات العناصر المخصصة في قاعدة الشفرة ومتى يجب استدعاءها ومن أين. إذا كنت سأختار هذه النسخة الاحتياطية (بدون وعود) فهذا على الأرجح ما سأركز عليه.

matthewp يبدو ذلك مفيدًا ، أين يمكنني العثور على هذا الفرع؟

matthewp نعم سيكون ذلك لطيفا

https://github.com/matthewp/jsdom/commits/custom-elements كما قلت ، تغيرت المواصفات منذ ذلك الحين ، لذا فهي قديمة. وهذا هو الجزء الأسهل ، لكنه نقطة انطلاق إذا أراده أي شخص. تضمين التغريدة

  • تم اعتماد القوالب من قبل جميع المستعرضات الرئيسية ( مواصفات W3C )
  • ستكون العناصر المخصصة قريبًا ( مواصفات W3C )
  • لن يتم تنفيذ استيراد HTML بواسطة بائع المستعرض في أي وقت قريبًا ( مواصفات W3C )
  • يقع Shadow dom بين ... ( مواصفات W3c )

(http://jonrimmer.github.io/are-we-componentized-yet/)

شخصيًا ، سيكون دعم العنصر المخصص أمرًا رائعًا بالفعل.

(لاحظ أن ما فهمته هو أن phantomJS 2.5 يجب أن يدعم القوالب على الأقل وربما عنصرًا مخصصًا أثناء انتقالهم إلى الإصدار الأحدث من Webkit ، ولست متأكدًا من أي واحد).

في الواقع ، أنا أسخر من العناصر المخصصة ، باستخدام عنصر lib document-register-element

const {before} = require('mocha')

before(mockDOM)
before(mockCustomElements)

function mockDOM() {
  const {JSDOM: Dom} = require('jsdom')
  const dom = new Dom('<!doctype html><html><body></body></html>')
  global.document = dom.window.document
  global.window = document.defaultView
  window.Object = Object
  window.Math = Math
}

function mockCustomElements() {
  require('document-register-element/pony')(window)
}

رائع ، هل لديك أي مشاكل؟

حتى الآن لا: د

لكني أحتاج إلى كتابة المزيد من المواصفات ، وتغطية المزيد من الأشياء لأشعر بتحسن

من الرائع أن نرى أن هناك طريقة. بقدر ما أحب البوليمر ، فإن اختبار setu هو الجحيم وامتلاك jsdom كبديل جيد ؛) شكرًا على وضع العمل فيه

يبدو أن هناك علاقات عامة تدفع هذا إلى الأمام! https://github.com/tmpvar/jsdom/pull/1872

في الواقع ، أنا أسخر من customElements ، باستخدام lib document-register- elementdarlanmendonca

يجب قراءة هذا الرابط حول إرفاق jsdom globals بالعقدة العالمية. إنه مضاد للنمط.

اهلا جميعا،
أنا مرتبك قليلاً فيما يتعلق بحالة تشغيل البوليمر داخل JSDOM (باستخدام Node.js 6.7.0 و JSDOM 11.1.0). لقد جربت أشياء مختلفة بنتائج مختلطة. سأكون ممتنًا حقًا إذا تمكن شخص ما من ملء لي هنا ...

ما فعلته حتى الآن:

1) لقد قمت بتشغيل خادم http من دليلي الجذر

./node_modules/http-server/bin/http-server --cors

2) قمت بتحميل أحد مكونات البوليمر الخاصة بي في JSDOM:

jsdom.JSDOM.fromURL("http://localhost:8080/path/to/my-component.html",
  { runScripts: "dangerously",
    resources: "usable"
  })
.then(function (dom) {
  setTimeout(() => {
    window = dom.window;
    component = window.document.querySelector("my-component");
  }, 10000);
})

(حاولت أيضًا تحميل ملف المكون من نظام الملفات ، بنفس النتائج.)

3) هذا هو رمز المكون الخاص بي:

<!DOCTYPE html>
<html>
<head>
  <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
</head>

<body>
<link rel="import" href="/bower_components/polymer/polymer.html">
<dom-module id="order-app">
  <template>
    <h1>Hello Polymer</h1>
  </template>

  <script>
    console.log("javascript is being executed");
    addEventListener('WebComponentsReady', function () {
      console.log("web components are ready");
      Polymer({
        is: 'order-app'
      });
    });
  </script>
</dom-module>
</body>
</html>

(لقد أضفت رأس HTML من أجل تحميل polyfill مكونات الويب.)

ماذا يمكنني أن ألاحظ؟

عندما أجري هذا ، أرى

  • أنه يتم تحميل polyfill مكونات الويب من خادم الويب
  • الرسالة "يتم تنفيذ جافا سكريبت" في وحدة التحكم

ما لا أراه

  • أنه يتم تحميل مكون polymer.html من خادم الويب
  • الرسالة "مكونات الويب جاهزة" في وحدة التحكم

يقودني هذا إلى استنتاج مفاده أنه لم يتم تشغيل حدث WebComponentsReady (ربما لأن استيراد HTML لا يعمل؟). أيضا،
يحتوي window.WebComponents على { flags: { log: {} } } - المؤشر ready مفقود.

لقد جربت أيضًا بعض الاستهزاء والتعبئة:

  window.Object = Object;
  window.Math = Math;
  require('document-register-element/pony')(window);

ولكن لا يبدو أن هذا يغير شيئًا.

الآن ، أنا أتساءل :-) هل من المفترض أن يعمل هذا على الإطلاق؟ إذا كان الأمر كذلك ، فلماذا لا يعمل معي؟ إذا لم يكن كذلك ، فما هو المفقود / المطلوب لتشغيله؟

شكرا لأية رؤى!

معين

حتى أنني حاولت ذلك بنجاح أقل واستسلمت لانتظار ما ستكون نتيجة هذه المناقشة هنا.

https://github.com/sebs/noframework/blob/master/test/configurator.js

ليس حلاً مجرد محاولة فاشلة أخرى. نفس الارتباك راجع للشغل. نفس النتيجة كذلك

ثبت أن Polyfilling المخصصة للعناصر في jsdom صعبة للغاية. هل يمكن لشخص أن يسرد تحديات تطبيق ذلك في الحكم القضائي؟ محاولة تقييم مستوى الجهد لتحقيق ذلك.

العقبة الأساسية هي أن jsdom يشارك المنشئين ونماذجهم الأولية .

هذا يجعل من المستحيل بشكل أساسي تنفيذ سجل عناصر مخصصة لكل نافذة ، لأن مُنشئ HTMLElement مُنشئ مشترك بين جميع النوافذ. لذلك عندما تقوم باستدعاء super() في مُنشئ العنصر المخصص الخاص بك ، فإن المُنشئ HTMLElement الذي يتم تشغيله الآن لا يعرف النافذة التي سيتم البحث فيها عن الأشياء. هذا أمر مزعج.

لست متأكدًا مما إذا كانت هناك أي حلول وسيطة جيدة. المسدس الكبير هو نقل jsdom إلى بنية تسمح للمنشئين / النماذج الأولية غير المشتركة. يمكننا القيام بذلك بعدة طرق ، كل ذلك بمقايضات مختلفة. ربما نرغب في فتح قضية مخصصة لمناقشتها مع الفريق والمجتمع ، ولكن في الوقت الحالي ، اسمحوا لي أن أدرج تلك التي تتبادر إلى الذهن من أعلى رأسي:

  • استخدم [WebIDL2JSFactory] لكل شيء في jsdom ، أو على الأقل HTMLElement وكل ما هو متفرع منه. لست متأكدًا مما إذا كان [WebIDL2JSFactory] يعمل بشكل جيد مع الميراث حتى الآن ، ولكن يمكن جعله يعمل. يتسبب هذا البديل في دفع الجميع تكلفة الإنشاءات / النماذج الأولية الإضافية ، ولكن ربما يكون ذلك أفضل من جعل العناصر المخصصة ميزة اختيارية.
  • لديك خيار حيث يقوم jsdom بتشغيل جميع وحدات تعريف الفئة داخل صندوق الحماية vm . على سبيل المثال ، لديك بعض خطوات البناء التي تجمع جميع واجهات برمجة تطبيقات الويب في jsdom ، ثم عند إنشاء نافذة جديدة ، نقوم بعمل vm.runScript() مع هذه الحزمة داخل sandbox global الجديد. من المحتمل أن يسمح لنا هذا بالتخلص من [WebIDL2JSFactory] .

أعتقد أن الحل الآخر هو تنفيذ عناصر مخصصة مع تحذير عملاق من أن سجل العنصر المخصص عالمي لكل عملية Node.js؟ هذا يبدو فظيعا بالرغم من ذلك


بعد هذه العقبة الأولية ، يكون الباقي واضحًا نسبيًا من حيث اتباع المواصفات. من المحتمل أن يكون الجزء الأصعب هو تنفيذ [CEReactions] وتحديث جميع ملفات IDL الخاصة بنا للحصول على ذلك في الأماكن المناسبة ، ولكنه ليس صعبًا للغاية.

لقد كنت أفكر في الحصول على نسخة نموذجية منفصلة أيضًا. وهنا بعض من أفكاري.

لست متأكدًا مما إذا كان [WebIDL2JSFactory] يعمل بشكل جيد مع الميراث حتى الآن ، ولكن يمكن جعله يعمل.

لا ، ليس كذلك ، ولست متأكدًا من كيفية إنجاحه بالضبط. الحل الثاني هو أكثر مباشرة في رأيي.

لديك خيار حيث يقوم jsdom بتشغيل جميع وحدات تعريف الفئة داخل صندوق الحماية vm .

هذا ما أفضله. تكمن المشكلة الرئيسية في تمرير الفئات الضمنية إلى صندوق الحماية vm أثناء التهيئة ، على الرغم من أنه يمكن القيام بذلك عن طريق وضع كل شيء من السياق الخارجي في خاصية عالمية واحدة ، و delete تلك الخاصية العامة بعد الانتهاء من ذلك . سيسمح أيضًا بتنفيذ [NamedConstructor] واثنين من السمات الموسعة الأخرى بشكل صحيح ، وربما حتى إنشاء لقطة بدء تشغيل V8 لبيئة jsdom إذا كان شخص ما لديه الجرأة الكافية.

كان العمل التجاري الذي [WebIDL2JSFactory] بالكامل اختراقًا في المقام الأول ، وأود التخلص منه في أقرب وقت ممكن.

لا تُعد تعليقات 1+ مفيدة في تطوير هذه الميزة ، لذلك أقوم بحذف واحدة حديثة على الأقل.

مرحبًا ، لم أكن أدرك أن @ TimothyGu كان يعمل على هذا.
لدي في الواقع تسجيل وإنشاء عنصر مخصص يعمل في
https://github.com/mraerino/jsdom/tree/custom-elements-spec

أحاول أن أكون أقل تدخلًا ممكنًا وأن أبقى قريبًا من المواصفات قدر الإمكان.
تم اجتياز اختبارات منصة الويب لسجل العنصر المخصص.

أثناء القرصنة الليلة الماضية وجدت حلاً يعمل بدون تعديل webIdl2JS.
انظر هنا: https://github.com/mraerino/jsdom/commit/592ad1236e9ca8f63f789d48e1887003305bc618

TimothyGu هل أنت على استعداد لتوحيد القوى في هذا واحد؟

فقط بعض التحديثات هنا:
أنا واثق تمامًا من تطبيقي للمواصفات ، لكنني عالق حاليًا بسبب سمة IDL الموسعة [HTMLConstructor] . لهذا السبب فتحت https://github.com/jsdom/webidl2js/issues/87

في غضون ذلك ، سأقوم بتنفيذ خوارزمية [HTMLConstructor] باستخدام سمة [Constructor] لأتمكن من التبديل بسهولة لاحقًا. (لقد قمت بتطبيقه في البداية عن طريق إدخال فئة HTMLElement وهمية في window ، لكن هذا لا يبدو صحيحًا.)

نعم ، كما هو مذكور في https://github.com/tmpvar/jsdom/issues/1030#issuecomment -333994158 ، فإن تنفيذ HTMLConstructor بشكل صحيح سيتطلب تغييرات أساسية في بنية jsdom.

هل لديك أي معلومات عن عدد اختبارات منصة الويب التي يجتازها إصدارك؟

فقط العناصر المخصصة في الوقت الحالي ، ويمكن أن أكون مخطئًا تمامًا بشأن تقدمي.

تحرير: حسنًا ، بعد إعادة قراءة تعليقك ، فهمت ما تقصده. سأحاول ذلك مع تطبيقي ، لكن يبدو أن @ TimothyGu يعمل أيضًا على الفصل.

أستخدم البوليمر لذا فأنا: +1: في ميزة الطلب هذه

@ dman777mraerino نفسه لمطوري Slim.js. يستخدم Slim مكونات الويب الأصلية API ولا يمكنه أن يرث HTMLElement بدون اختراق على jsdom.

مرت ثلاث سنوات على فتح هذا العدد. يمكن لأي شخص أن يقول متى تقريبا سوف يدعم jsdom العناصر المخصصة؟

TL ؛ DR

لقد عملت خلال الأسبوعين الماضيين على تقييم جدوى إضافة دعم للعنصر المخصص في jsdom. ها هي نتيجة التحقيق.

يمكنك العثور على تنفيذ متوافق مع المواصفات للعنصر المخصص هنا: https://github.com/jsdom/jsdom/compare/master...pmdartus : custom-element؟ expand = 1. لا تزال هناك بعض الجوانب الخشنة هنا وهناك ، ولكن على الأقل معظم اجتياز اختبار WPT . الاختبارات الفاشلة المتبقية هي إما مشكلات JSDOM المعروفة أو مشكلات ثانوية يمكن معالجتها عندما نتعامل مع التنفيذ الفعلي في jsdom.

الآن هذه هي الأخبار السارة ، الآن بعد أن تم دعم Shadow DOM محليًا ، مع كل من فرع العنصر المخصص ومراقب الطفرات ، تمكنت من تحميل وتقديم أحدث إصدار من مثال تطبيق Polymer 3 hello world في jsdom 🎉. في حالته الحالية ، لا يتمكن الفرع من تحميل تطبيق Stencil (يتطلب وضع Stencil dev بعض الميزات غير المدعومة مثل module ، ويظهر وضع prod لسبب غير معروف).

خطة عمل

فيما يلي قائمة بالتغييرات التي يجب أن تحدث أولاً من قبل ، والبدء في معالجة التنفيذ الفعلي لمواصفات العنصر المخصص. كل عنصر في القائمة مستقل ويمكن معالجته بشكل متوازٍ.

دعم السمات الموسعة لـ [CEReactions] IDL

إحدى السمات الأساسية المفقودة وظيفيًا في jsdom لإضافة دعم للعناصر المخصصة هي سمات [CEReactions] . تمكنت جزئيًا من التغلب على هذه المشكلة عن طريق تصحيح خصائص النموذج الأولي الصحيح. يعمل هذا النهج طالما أن مكدس تفاعل العنصر المخصص عام وليس لكل وحدة من سياقات التصفح ذات الأصل المتشابه حيث يتم مشاركة جميع نماذج الواجهات الأولية.

هذا الأسلوب به بعض أوجه القصور حيث أن بعض الواجهات لها سمات [CEReactions] المرتبطة بالخصائص المفهرسة ( HTMLOptionsCollection ، DOMStringMap ). داخليًا ، يستخدم jsdom البروكسيات لتتبع الطفرة في تلك الخصائص. لا يعمل تصحيح النموذج الأولي للواجهة في هذه الحالة. هناك طريقة أخرى للتغلب على هذه المشكلة وهي تصحيح التطبيق بدلاً من الواجهة (غير مطبق).

لست على دراية كافية بـ webidl2js الداخلي ، ولكن يجب علينا استكشاف إضافة خطاف عام مقابل [CEReactions] ؟

التغييرات:

دعم السمات الموسعة لـ [HTMLConstructor] IDL

كما أوضح domenic أعلاه ، فإن إضافة دعم لـ [HTMLConstructor] هو أحد العوائق الرئيسية هنا.

لقد تمكنت من التغلب على هذه المشكلة هنا عن طريق تصحيح مُنشئ الواجهة لكل سياق تصفح. سيكون مُنشئ الواجهة قادرًا على الوصول إلى النافذة الصحيحة وكائن المستند مع الاحتفاظ بالنموذج الأولي المشترك. يتجنب هذا النهج أيضًا عبء الأداء لإعادة تقييم النموذج الأولي للواجهة لكل سياق تصفح جديد.

لست متأكدًا مما إذا كان هذا هو أفضل نهج هنا ، لكنه يناسب المتطلبات دون تقديم أداء إضافي.

التغييرات:

جعل خوارزمية جعل تحليل الجزء متوافقة مع المواصفات (# 2522)

كما تمت مناقشته هنا ، تطبيق algo لتحليل جزء HTML المستخدم في Element.innerHTML و Element.outerHTML غير صحيح. تحتاج خوارزمية التحليل إلى إعادة بنائها ، حتى يتم استدعاء عمليات رد نداءات تفاعلات العنصر المخصص بشكل صحيح.

التغييرات:

تحسين البحث عن الواجهة لإنشاء عنصر algo

كانت إحدى المشكلات التي عثرت عليها بسرعة ، هي إدخال تبعيات دائرية جديدة عند إضافة دعم لإنشاء عنصر مخصص. يتطلب كل من CustomElementRegistry و إنشاء خوارزمية عنصر الوصول إلى واجهات Element ، مما يخلق تبعيات دائرية كابوس.

كان الأسلوب المتبع في الفرع هو إنشاء InterfaceCache ، والذي من شأنه أن يسمح بالبحث في الواجهة عن طريق مساحة اسم العنصر والاسم ولكن أيضًا عن طريق اسم الواجهة. يتم تقييم وحدات الواجهة بشكل كسول وتخزينها مؤقتًا بمجرد تقييمها. يتخلص هذا النهج من التبعيات الدائرية لأن الواجهات لم تعد مطلوبة في المستوى الأعلى بعد الآن.

هذه طريقة واحدة لحل هذه المشكلة طويلة الأمد في jsdom ، وإحدى هذه المشكلات في هذا النهج هي أنه ربما يكسر إصدار حزمة الويب / المستعرض من jsdom (لم يتم اختباره).

التغييرات:

~ إصلاح Element.isConnected لدعم Shadow DOM (https://github.com/jsdom/jsdom/pull/2424)~

هذه مشكلة تراجعت مع إدخال Shadow DOM ، حيث تقوم isConnected بإرجاع false إذا كان العنصر جزءًا من شجرة الظل. يجب إضافة اختبار WPT جديد هنا ، حيث لا يوجد اختبار يتحقق من هذا السلوك.

التغييرات:

إصلاح مستندات HTMLTemplateElement.templateContents عقدة (# 2426)

تحتوي محتويات القالب كما هو محدد في المواصفات على مستند عقدة مختلف عن HTMLTemplateElement نفسه. لا يطبق jsdom هذا السلوك اليوم ، كما أن HTMLTemplateElement ومحتويات القالب تشترك فيهما
عقدة الوثيقة.

التغييرات:

  • HTMLTemplateElement-impl.js
  • htmltodom.js . هذا التغيير له أيضًا بعض التأثير المتجه إلى المصب على المحلل اللغوي. إذا كان عنصر السياق عبارة عن HTMLTemplateElement ، فيجب أن تلتقط خوارزمية تحليل جزء HTML عقدة المستند من محتوى القالب وليس من العنصر نفسه.

أضف خطوات اعتماد مفقودة إلى HTMLTemplateElement (# 2426)

يحتاج HTMLTemplateElement إلى تشغيل بعض الخطوات المحددة عند اعتماده في مستند آخر. وبقدر ما أعلم ، فإن واجهة التربة لها خطوة اعتماد خاصة. سيحتاج تطبيق خوارزمية اعتماد العقدة أيضًا إلى التحديث لاستدعاء خطوة التبني هذه.

التغييرات:

إضافة دعم لبحث isValue في المسلسل parse5

تختلف أجزاء HTML المتسلسلة ، عند إجراء تسلسل لبحث عنصر ، تكون القيمة المرتبطة بالعنصر وتعكسها كسمة في المحتوى المتسلسل. سيكون من المثير للاهتمام إضافة خطاف آخر في محول الشجرة parse5 ، والذي سيبحث عن القيمة المرتبطة بالعنصر getIsValue(element: Element): void | string .

تتمثل الطريقة البديلة (غير المطبقة) في إضافة تغيير سلوك الخطاف الحالي getAttrList لإرجاع قيمة is إلى قائمة السمات ، إذا كان للعنصر قيمة مرتبطة.

أداء

قبل القيام بأي تحسين للأداء ، أردت أيضًا التحقق من أداء التغييرات في الفرع. تضيف إضافة العناصر المخصصة زيادة في الأداء بنسبة 10٪ مقارنة بالنتيجة الحالية على المستوى الرئيسي لمعايير طفرة الشجرة. ومع ذلك ، فإن إنشاء بيئة JSDOM الجديدة أصبح الآن أبطأ من 3x إلى 6x مقارنةً بالبيئة الرئيسية ، فقد يتطلب الأمر تحقيقًا أعمق لتحديد السبب الجذري.

مزيد من التفاصيل: هنا

pmdartus هذا عمل واعد جدا ، ممتاز! لقد كنت أستخدم فرع الاختراق الخاص بي jsdom-wc ، لعدم وجود خيار أفضل. أرى بعض السلوكيات الغريبة وكنت آمل في استبدال فرعك ، لكنني أتصدى للمشكلات.

أسجل عناصر مخصصة مثل:

class Component extends HTMLElement {

}

customElements.define('custom-component', Component);

لكن إذا فعلت:

const el = assign(this.fixture, {
  innerHTML: `
    <custom-component></custom-component>
  `,
});

أحصل على فوري: Error: Uncaught [TypeError: Illegal constructor] .

اي افكار في هذا؟

يتم تشغيل مقتطف الشفرة التالي بشكل صحيح على الفرع custom-elements على مفترقتي: https://github.com/pmdartus/jsdom/tree/custom-elements

const { JSDOM } = require("jsdom");

const dom = new JSDOM(`
<body>
  <div id="container"></div>
  <script>
    class Component extends HTMLElement {
        connectedCallback() {
            this.attachShadow({ mode: "open" });
            this.shadowRoot.innerHTML = "<p>Hello world</p>";
        }
    }
    customElements.define('custom-component', Component);

    const container = document.querySelector("#container");

    Object.assign(container, {
        innerHTML: "<custom-component></custom-component>"
    })

    console.log(container.innerHTML); // <custom-component></custom-component>
    console.log(container.firstChild.shadowRoot.innerHTML); // <p>Hello world</p>
  </script>
</body>
`, { 
    runScripts: "dangerously" 
});

من المحتمل أن يكون المُنشئ غير القانوني قد تم طرحه بواسطة مُنشئ HTMLElement الأصلي ، يجب أن تقوم التغييرات على الفرع بتصحيح المُنشئ لكل كائن إطار جديد. tbranyen هل لديك مثال استنساخ كامل حتى يمكنني تجربته محليًا؟

مرحبًا pmdartus ، لست متأكدًا بعد من سبب مشاكلي ، لكنني كتبت بعض الرموز المعزولة مباشرة في فرعك والتي عملت بشكل مثالي:

const { JSDOM } = require('.');
const window = (new JSDOM()).window;
const { HTMLElement, customElements, document } = window;

class CustomElement extends HTMLElement {
  constructor() {
    super();

    console.log('constructed');
  }

  connectedCallback() {
    console.log('connected');
  }
}

customElements.define('custom-element', CustomElement);
document.body.appendChild(new CustomElement());
//constructed
//connected

{
  const window = (new JSDOM()).window;
  const { HTMLElement, customElements, document } = window;

  class CustomElement extends HTMLElement {
    constructor() {
      super();

      console.log('Constructed');
    }

    connectedCallback() {
      console.log('Connected');
    }
  }

  customElements.define('custom-element', CustomElement);
  document.body.appendChild(new CustomElement());
  //constructed
  //connected
}

هذا هو ما يفعله نظام الاختبار الخاص بي بشكل فعال ، لكنه ينكسر. لذلك قد يكون شيء في نهايتي.

يحرر:

آه ، حسنًا ، أعتقد أنني قمت بتضييق نطاق المكان الذي تحدث فيه المشكلة على الأرجح. يجب أن أكون متمسكًا بالمُنشئ الأولي HTMLElement الذي تم إنشاؤه. إذا قمت بتعديل الكود أعلاه لإعادة استخدام المُنشئ:

  // Inside the block, second component, reuse the HTMLElement.
  const { customElements, document } = window;

سينتج عن ذلك ما يلي:

connected
/home/tbranyen/git/pmdartus/jsdom/lib/jsdom/living/helpers/create-element.js:643
        throw new TypeError("Illegal constructor");

تحرير 2:

وجدته:

  // Don't reuse the previously defined Element...
  global.HTMLElement = global.HTMLElement || jsdom.window.HTMLElement;

مع ملاحظة أن هذا الموضوع عمره 4 سنوات ، هل مكونات الويب مدعومة أو مخطط لها؟

سيكون من الجيد أن يكون لديك مكونات ويب في هذا ، ولكن كبديل إذا كان أي شخص يرغب في معرفة .... يمكن الآن استخدام الكروم مقطوع الرأس في العقدة لتقديم / إنشاء ملف اللدغة html.

مع ملاحظة أن هذا الموضوع عمره 4 سنوات ، هل مكونات الويب مدعومة أو مخطط لها؟

إنه عمل مستمر حيث يتم تنفيذ المواصفات قطعة قطعة.

polyfill على: https://github.com/WebReflection/document-register-element يعمل مثل السحر! خالص شكري للمؤلف!

لأولئك الذين يعانون من نفس المشكلة ، فقط قم بما يلي:

npm install -D document-register-element

في تكوين jest الخاص بك ، قم بتعيين ملف الإعداد الذي سيتم تشغيله قبل جميع الاختبارات الخاصة بك:

{ "setupFilesAfterEnv": [ "./tests/setup.js" ] }

وأخيرًا ، داخل هذا الملف ('الاختبارات / setup.js'):

import 'document-register-element'

بعد القيام بذلك ، التسجيل وإنشاء عناصر مخصصة في jsdom عبر document.createElement ("مكون مخصص") يعمل بشكل مثالي! ومع ذلك ، لا يبدو أن الشظايا تعمل. (بالمناسبة أنا لا أستخدم الظل دوم).

tebanep كما ذكرت أن polyfill غير مناسب لمعظم أعمال مكونات الويب ، إذا كانت لا تدعم Shadow DOM ، فهي في الحقيقة ليست مقارنة بما يحققه هذا.

tebanep شكرا. نظرًا لأنني لا أحتاج إلى ظل دوم ، فهذه معلومات رائعة

أي أمل في أن يتم تنفيذ ذلك؟ الآن نحن نستخدم jsdom-wc مع الكثير من الأخطاء ، لكن ليس لدينا أي حل أفضل. أملي والصلاة في هذا الموضوع.

dknight أعرف أن jsdom-wc هو إلى حد كبير اختراق لجعله يعمل نوعًا ما. لقد قمت بنشر الوحدة مع توافق أفضل بشكل ملحوظ ضمن نطاق npm الشخصي الخاص بي. يمكنك تثبيته باستخدام:

npm install @tbranyen/[email protected] --save-dev

أنا أستخدم هذا الآن لجميع احتياجات مكونات الويب لـ JSDOM الخاصة بي حتى الأراضي المستقرة.

tbranyen هل ألغيت نشر الشوكة الخاصة بك؟ لا يمكنني العثور عليه في npm.

KingHenne Dangit ، يبدو أنه انتهى به المطاف في سجل "enterprise". لقد نشرت للتو للجمهور npm. اسف بشأن ذلك!

لا تفعل @ me ، ولكن لا ينبغي علينا اختبار رمز واجهة المستخدم على الويب في متصفح حقيقي ، على سبيل المثال باستخدام محرك الدمى. تختفي مشكلة دعم Shadow DOM / Custom Elements بعد ذلك.

لا تنشر تعليقًا إذا كنت لا تريد أن تكون @ 'dGeorgegriff. هذه إستراتيجية صالحة ، لكنها بطيئة وعربة من نواحٍ أخرى لأنك تقوم بعمل IPC بشكل فعال ، نعم حتى مع محرك الدمى. عندما يموت المتصفح ، ليس من الواضح السبب في كثير من الحالات. ما عليك سوى محاولة تصحيح مشكلات محرك الدمى على سبيل الدعابة للتعرف على سبب عدم كونها دائمًا أفضل فكرة.

أنا شخصياً أفضل الاستمرار في الاختبار متزامن وعلى نفس الموضوع. لا يوجد سبب يجعل التنفيذ المعزول للمواصفات لا ينبغي أن يكون وقت تشغيل معقول لاختبار المكونات. JSDOM هو متصفح فعال في هذه المرحلة ، ولكنه ليس مستقرًا مثل الثلاثة الكبار.

polyfill على: https://github.com/WebReflection/document-register-element يعمل مثل السحر! خالص شكري للمؤلف!

لأولئك الذين يعانون من نفس المشكلة ، فقط قم بما يلي:

npm install -D document-register-element

في تكوين jest الخاص بك ، قم بتعيين ملف الإعداد الذي سيتم تشغيله قبل جميع الاختبارات الخاصة بك:

{ "setupFilesAfterEnv": [ "./tests/setup.js" ] }

وأخيرًا ، داخل هذا الملف ('الاختبارات / setup.js'):

import 'document-register-element'

بعد القيام بذلك ، التسجيل وإنشاء عناصر مخصصة في jsdom عبر document.createElement ("مكون مخصص") يعمل بشكل مثالي! ومع ذلك ، لا يبدو أن الشظايا تعمل. (بالمناسبة أنا لا أستخدم الظل دوم).

إنه يعمل بشكل جيد بالنسبة لي ولكن connectedCallback لم يتم الاتصال به مطلقًا ، أي فكرة؟

FaBeyyy نفس الشيء بالنسبة لي :(

FaBeyyy @ majo44 عليك إلحاق المكون الخاص بك بمستند أي. document.body.appendChild(...) مقابل connectedCallback ليتم طردك. حسب المواصفات ، يتم استدعاؤه عند إرفاق المكون بـ Dom.

JSDOM هو متصفح فعال في هذه المرحلة ، ولكنه ليس مستقرًا مثل الثلاثة الكبار.

في هذه المرحلة ، يبدو الأمر أشبه بالاثنين الكبيرين ، لأن Microsoft تتخلى عن نظامهم ، الذي ظل معهم منذ فترة طويلة مثل Windows.

FaBeyyy @ majo44 عليك إلحاق المكون الخاص بك بمستند أي. document.body.appendChild(...) مقابل connectedCallback ليتم طردك. حسب المواصفات ، يتم استدعاؤه عند إرفاق المكون بـ Dom.

شكرا كابتن واضح ولكن هذا بالطبع ليس هو القضية هنا. إذا لم أكن أعرف كيف تعمل دورة حياة المكون ، فربما لن أحاول كتابة الاختبارات 😄. سيتم إنشاء عرض الريبو لاحقًا عندما أجد الوقت.

تضمين التغريدة
لذلك وجدت الإعداد الذي يناسبني. اضطررت إلى إضافة polyfill لـ MutationObserver. أنا أستخدم JSDOM لاختبار خنزير البحر ، مع Jest ، وإعداد العمل هو:

// package.json
{  ...
  "jest": {
    "transform": {
      "^.+\\.(mjs|jsx|js)$": "babel-jest"
    },
    "setupFiles": [
      "<rootDir>/node_modules/babel-polyfill/dist/polyfill.js",
      "<rootDir>/node_modules/mutationobserver-shim/dist/mutationobserver.min.js",
      "<rootDir>/node_modules/document-register-element/build/document-register-element.node.js"
    ]
  }
... 
}
//.bablerc
{
    "presets": [
        ["@babel/preset-env", { "modules": "commonjs"}]
    ]
}

تضمين التغريدة
لذلك وجدت الإعداد الذي يناسبني. اضطررت إلى إضافة polyfill لـ MutationObserver. أنا أستخدم JSDOM لاختبار خنزير البحر ، مع Jest ، وإعداد العمل هو:

// package.json
{  ...
  "jest": {
    "transform": {
      "^.+\\.(mjs|jsx|js)$": "babel-jest"
    },
    "setupFiles": [
      "<rootDir>/node_modules/babel-polyfill/dist/polyfill.js",
      "<rootDir>/node_modules/mutationobserver-shim/dist/mutationobserver.min.js",
      "<rootDir>/node_modules/document-register-element/build/document-register-element.node.js"
    ]
  }
... 
}

//.bablerc { "presets": [ ["@babel/preset-env", { "modules": "commonjs"}] ] }

جميل شكرا!

@ majo44 هذا غير مطلوب مع أحدث jsdom. عند العمل مع Jest (الذي يستخدم jsdom v11) ، يمكنك فقط استخدام البيئة المحدثة: https://www.npmjs.com/package/jest-environment-jsdom-fourteen

شكرًا mgibas ، مع jest-environment-jsdom-fourteen ، فهو يعمل أيضًا بشكل جيد ولا يلزم إضافة ملاحظ للطفرات (ولكن الإصدار 0.1.0 ، حزمة الالتزام الفردي :))

هل هناك تفصيل لمكونات الويب التي يدعمها JSDOM حاليًا؟ يبدو أن Shadow DOM مدعوم ، لكن ليس العناصر المخصصة (على الأقل في فرع الإصدار / الريبو)؟

npm install @tbranyen/[email protected] --save-dev

tbranyen هل لديك شفرة المصدر للشوكة الخاصة بك متوفرة في مكان ما؟ سيكون من الغريب إلقاء نظرة على الفرق 🙂

أنا أستخدم jest-environment-jsdom-fifteen مثل @ majo44 المقترح ، وعنصر babel-polyfill و document-register-element (راجع إجابات mgibas ). لكن ما زلت أحصل على خطأ عندما أحاول استرداد ظل مكون الويب الخاص بي للاختبارات.

el.shadowRoot خالٍ مع:

const el;
beforeEach(async() => {
  const tag= 'my-component'
  const myEl = document.createElement(tag);
  document.body.appendChild(myEl);
  await customElements.whenDefined(tag);
  await new Promise(resolve => requestAnimationFrame(() => resolve()));
  el = document.querySelector(tag);
}

it(() => {
  const fooContent = el.shadowRoot.querySelectorAll('slot[name=foo] > *');
})

أي فكرة عن حل؟ لمعلوماتك ، تم اختباره بالفعل مع Karma و Mocha و Chai و Jasmine.

لا يوجد شيء مميز في المكون الخاص بي:

customElements.define(
  'my-component',
  class extends HTMLElement {
    constructor() {
      super();

      const shadowRoot = this.attachShadow({ mode: 'open' });
      ...
  }
})

يحرر

لقد أجريت بعض التصحيح باستخدام jsdom 15.1.1 لفهم مشكلتي بشكل أفضل.
مع ذلك ، لا أفهم سبب كونه فارغًا هنا ...

لذلك ، تم تنفيذ Element.shadowRoot منذ 88e72ef
https://github.com/jsdom/jsdom/blob/1951a19d8d40bc196cfda62a8dafa76ddda6a0d2/lib/jsdom/living/nodes/Element-impl.js#L388 -L415

بعد document.createElement ، يعد this._shadowDom مناسبًا على https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/living/nodes/Element-impl.js#L403. ويتم إنشاء كل عنصر في الظل دوم (يسمى مُنشئ العنصر بالقيم الصحيحة).

لكن عندما أتصل بـ el.shadowDom مباشرة بعد document.body.appendChild (el) (https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/living/nodes/Element-impl .js # L408) ، this. _shadowRoot فارغ!

نفس الشيء بعد

 await customElements.whenDefined(tag);
 await new Promise(resolve => requestAnimationFrame(() => resolve()));

أو حتى إذا استخدمت ما يلي بدلاً من المستند.

document.body.innerHTML = `
  <my-component id="fixture"></my-component>
`:

للتكاثر ، انظر:
https://github.com/noelmace/devcards/tree/jest

nminhnguyen أعتقد أنه يمكنك العثور على الكود المصدري للشوكة التي صنعهاtbranyan هنا https://github.com/tbranyen/jsdom/tree/initial-custom-elements-impl

أحاول اختبار مكونات الويب التي تم إنشاؤها باستخدام lit-html و lit-element ولاحظت هذا الاختلاف عند إنشاء العناصر.

const myElem = new MyElem();

document.body.appendChild(myElem);
await myElem.updateComplete;

console.log(myElem.shadowRoot) // exists and has the rendered markup

وعندما أستخدم document.createElement

const myElem = document.createElement('my-elem');

document.body.appendChild(myElem);
await myElem.updateComplete;

console.log(myElem.shadowRoot) // null

لتكوين الدعابة ، استخدم فقط polyfill واحدًا وهو: setupFiles: ['document-register-element']

يبدو أنه لم يتم استدعاء طريقة التقديم في myElem . بعد تصحيح الأخطاء قليلاً ، اكتشفت أن الطريقة initialize الموجودة في العنصر المضاء لا يتم استدعاؤها مطلقًا.
لذا فإن المثال الثاني سيعمل إذا قمت بذلك

const myElem = document.createElement('my-elem');
myElem.initialize();

document.body.appendChild(myElem);
await myElem.updateComplete;

console.log(myElem.shadowRoot) //  exists and has the rendered markup

لقد قمت بإنشاء DOM بديل يدعم مكونات الويب. حاولت أولاً إنشاء علاقات عامة ، لكن الطريقة التي يعمل بها JSDOM جعلت من الصعب عليّ تلبية احتياجاتي هناك. أنت حر في استخدامه أو إلقاء نظرة على الكود.

DOM:
https://www.npmjs.com/package/happy-dom

بيئة الدعابة:
https://www.npmjs.com/package/jest-environment-happy-dom

يبدو رائعا. شكرا لك.

في يوم الإثنين ، 7 أكتوبر ، 2019 ، الساعة 1:08 صباحًا ، كتب capricorn86 [email protected] :

لقد قمت بإنشاء DOM بديل يدعم مكونات الويب. انا اولا
حاولت إنشاء علاقات عامة ، لكن الطريقة التي يعمل بها JSDOM جعلت من الصعب علي حل مشكلة
يحتاج هناك. أنت حر في استخدامه و / أو إلقاء نظرة على الكود.

DOM:
https://www.npmjs.com/package/happy-dom

بيئة الدعابة:
https://www.npmjs.com/package/jest-environment-happy-dom

-
أنت تتلقى هذا لأنك مشترك في هذا الموضوع.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/jsdom/jsdom/issues/1030؟email_source=notifications&email_token=ACQ5ZD5QUEITPND4SXWOHW3QNILSRA5CNFSM4A4G5SF2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW38
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/ACQ5ZDYU465DXI4KHBQH4KTQNILSRANCNFSM4A4G5SFQ
.

يارب احفظها
عملك يجعل بيئة الاختبار الخاصة بي بسيطة ، شكرا!
https://github.com/EasyWebApp/WebCell/tree/v2/MobX

يارب احفظها
عملك يجعل بيئة الاختبار الخاصة بي بسيطة ، شكرا!
https://github.com/EasyWebApp/WebCell/tree/v2/MobX

شكرا لك @ TechQuery!

يبدو رائعا. شكرا لك.
...
في الاثنين ، 7 أكتوبر 2019 ، الساعة 1:08 صباحًا capricorn86 @ . * > كتب: لقد أنشأت DOM بديلًا يدعم مكونات الويب. حاولت أولاً إنشاء علاقات عامة ، لكن الطريقة التي يعمل بها JSDOM جعلت من الصعب عليّ تلبية احتياجاتي هناك. أنت حر في استخدامه و / أو إلقاء نظرة على الكود. DOM: https://www.npmjs.com/package/happy-dom بيئة Jest: https://www.npmjs.com/package/jest-environment-happy-dom - أنت تتلقى هذا لأنك مشترك في هذا مسلك. الرد على هذا البريد الإلكتروني مباشرة، مشاهدته على جيثب <# 1030؟ email_source = الإخطارات وemail_token = ACQ5ZD5QUEITPND4SXWOHW3QNILSRA5CNFSM4A4G5SF2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEAOO5ZA # issuecomment-538767076>، أو كتم موضوع https://github.com/notifications/unsubscribe-auth/ACQ5ZDYU465DXI4KHBQH4KTQNILSRANCNFSM4A4G5SFQ .

شكرا @ motss!

هل هناك تفصيل لمكونات الويب التي يدعمها JSDOM حاليًا؟ يبدو أن Shadow DOM مدعوم ، لكن ليس العناصر المخصصة (على الأقل في فرع الإصدار / الريبو)؟

سأكون مهتمًا بهذا أيضًا :)

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