Published on

اطار عمل javascript جديد، لكن مختلف كليا.. تعرف على qwik الجزء الأول

Authors
tailwind-nextjs-banner

💡

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

مقدمة

نعم يوجد اطار عمل جديد لجافاسكرت 😅، وقبله المئات أو الألاف.
لكن يزعم مطورين qwik أنه مختلف كليا. كما هو الحال مع مطورين اطارات العمل من قبله :) ...

لكن فعلا، هو مختلف !

قبل أن نقول لماذا هو مختلف نحتاج ان نعرف مصطلح مهم جدا "hydration"
على تعريف wikipedia:

In web development, hydration or rehydration is a technique in which client-side JavaScript converts a static HTML web page, delivered either through static hosting or server-side rendering, into a dynamic web page by attaching event handlers to the HTML elements.

بمعنى : طريقة لإضافة تفاعل ديناميكي (جافاسكربت) الى صفحة html -سادة- التي تصل من السيرفر. عن طريق ربط معالجات الاحداث بعنصر الhtml الذي يستخدمه

مثال لمعالجات الاحداث

<button onClick={() => alert('hello')}></button>

الحدث هنا هو onClick واما المعالج او التفاعل هو الفنكشن بداخله

هذه المشكلة موجودة بشكل أكبر في اطارات العمل التي تتعامل ب ssr (التفاصيل ستكون في مقال قادم باذن الله)
لكن بشكل عام هذه صورة توضيحية

مثال ssr لnext js

الإشكالية الكبرى هي في معرفة ماهي معالجات تفاعلات جافاسكربت الموجودة ، واين تقع ؟، ثم ربطها وتشغيلها

معالجات تفاعلات جافاسكربت(event handlers): نعني بها فنكشن تحتوي على حدث ما ، وتحتاج أن يتفاعل معها المستخدم لكي يكون لها قيمة

أين تقع : هو موقع كل عنصر HTML يحتوي على معالجات تفاعلات

معالجات تفاعلات جافاسكربت تحتاج أيضا لمعرفة حالة التطبيق(state) اذا ارادت ان تغير في التطبيق وتصبح (ديناميكية)

const Comp = ()=>{
	const [counter,setCounter] = useState(0); حالة التطبيق
  return (
    <button
      onClick={()=>setCounter((c)=>c+1)} هذا السطر عبارة عن معالج حدث، وموقعه في شجرة العرض هو العنصر الأول في هذا الكمبوننت
    >
      {counter}
    </button>
  )
}

في السطر الثاني ذكرت (حالة التطبيق) مع أنه الحالة المعرفة هي خاصة بهذا الكمبوننت.

لان جميع الحالات هي في أصلها مخزنة خارج الكمبوننت، في الأوبجكت الخاص بـReact، يشرحها Dan abramov كالتالي 👇

As a component’s memory, state is not like a regular variable that disappears after your function returns. State actually “lives” in React itself—as if on a shelf!—outside of your function. When React calls your component, it gives you a snapshot of the state for that particular render. Your component returns a snapshot of the UI with a fresh set of props and event handlers in its JSX, all calculated **using the state values from that render!**

💡

لنسهل قراءة الجزئية التالية ونزيل التكرار سنستخدم أسامي مختصرة ، تفاعلات جافا سكربت = التفاعلات، اين تقع = أين

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

وطريقة التعامل مع التقفيلة هي مربط الفرس !

فحل الhydration هو أن تحمل جافاسكربت كاملة - أو جزئيا - لعمل تقفيلة [المعالجات] مع الstate

فبدون ان تحملها لن تستطيع ربطها بشكل صحيح !

وكما يقول ميشكو مطور اطار QWIK (مع تحريف لأجل التبسيط)

وباختصار طريقة الhydration هي عبارة عن استعادة [المعالجات] عن طريق ارسال الموقع الى العميل مرتين، مرة ك html والمرة الأخرة ك javascript ، وفي المرة الثانية يحتاج المتصفح أن ينفذ جميع كود الجافسكربت لاستعادة المعالجات مع موقعها والتقفيلات، ثم يقوم بالربط بينهما . كل هذا لأنه تجاهل (شيء) وصله مع السيرفر لكنه تجاهله

و - الشيء - الذي يقصده بكل بساطة هو الHTML !

فلماذا يحتاج أن يحمل الجافسكربت لاجل ان يربطه مع الHTML ، لماذا لا يستخدم ويستغل الHTML الموجود لديه ويقوم بالربط مباشرة ؟!

وهذه هي الطريقة التي اقترحها ميشكو والتي نفذها فعليا في اطاره وهي resumibility أو الاستمرارية .

فهو يقول أن الخطوة الزائدة لتحميل الجافاسكربت ، ثم بإستخدام الجافاسكربت معرفة مواقع المعالجات في الhtml وربطها هي خطوة زائدة ومكلفة جدا. بدلا من ذلك .. ضع علامات في الـHTML تخبرك أين موقع المعالج الذي تحتاجه !

const Comp = () => {
  const [counter, setCounter] = useState(0)
  return <button onClick={() => setCounter((c) => c + 1)}>{counter}</button>
}

const App = () => {
  return (
    <div>
      <Comp />
    </div>
  )
}

react

باستخدام نفس الكود السابق، هنا عرفنا كموننت اسمه Comp واستخدمناه بداخل الكمبوننت الأساسي App

في التحميل الأولي للHTML ، قبل تحميل الجافاسكربت، هكذا سيظهر الHTML في المتصفح

<div>
  <button>0</button>
</div>

html

لا توجد أي علامات تدل على موقع الجافاسكربت، ناهيك عن وجود جافاسكربت أصلا !

وبالتالي اطار العمل يحتاج أن يحمل جميع الجافاسكربت الذي تحتاجه والذي لا تحتاجه (احتياطا)، لإنه لا يعرف أي العناصر التي ستتفاعل معها

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

وهذه مشكلة كبيرة جدا، خصوصا في الجوالات والأجهزة الضعيفة والإنترنت البطيء.

وتخيل أن لدى أحد عملائك جوال ضعيف ذو انترنت بطيئ 🙃

الاستمرارية resumbility

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

لأجل ان تعمل فكرة الإستمرارية تحتاج ثلاثة أشياء أساسية

  1. وضح جميع المعلومات المطلوبة في الHTML نفسه، المعلومات هذه عبارة عن المعالجات وموقعها والstate
  2. وضع معالج أحداث عام، لأجل ان لا نحتاج أن نربط كل المعالجات بعناصر الHTML
  3. فنكشن بطريقة الfactory تستدعي الأحداث التي تفاعل معها المستخدم فقط !
<div q:host>
  <div q:host>
    <button on:click="./chunk-a.js#greet">Greet</button>
  </div>
  <div q:host>
    <button q:obj="1" on:click="./chunk-b.js#count[0]">10</button>
  </div>
</div>
<script>
  /* رقم 2 هنا  */
</script>
<script type="text/qwik">
  /* هنا توجد الحالات */
</script>

html

يلاحظ هنا ان لا يوجد فنكشنات في الاحداث ولكن اماكن ملفات، وكنتيجة لهذا فحين تتفاعل مع عنصر يقوم بجلب ملف الجافاسكربت المطلوب فقط، ولا يقوم بتحميل جميع الجافاسكربت الذي تحتاجه والذي لا تحتاجه

وأهم شي !

طريقة كتابة كود qwik جدا مألوفة اذا برمجت سابقا بreact او الjsx عموما

import { component$ } from '@builder.io/qwik'

export default component$(() => {
  return <section class="section bright">A Joke!</section>
})

للمزيد اضغط هنا

خلاصة

الفرق الأساسي بين الطريقتين هو

  • hydartion : تحمل جميع الجافاسكربت ثم تنفذه ، الذي يحتاجه المستخدم والذي لا يحتاجه
  • resumbility : تحمل فقط الجافاسكربت الذي يحتاجه المستخدم، أثناء التفاعل فقط

والذي طبق الresumibilty على أرض الواقع هو إطار qwik

في الجزء الثاني سننظر الى كود الإطار لنعلم كيف تم تنفيذه، ونرى التفاصيل بشكل أوضح.

مراجع

State as a Snapshot

Hydration is Pure Overhead

Why hydration is a workaround, not the solution.