الفرق بين المراجعتين لصفحة: «Next.js/script»

من موسوعة حسوب
أنشأ الصفحة ب'= التعامل مع السكربتات في Next.js = يُعد المكوّن<code>next/script</code> في Next.js امتدادًا للعنصر <code><script></code>...'
 
طلا ملخص تعديل
 
(5 مراجعات متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة)
سطر 1: سطر 1:
= التعامل مع السكربتات في Next.js =
<noinclude>{{DISPLAYTITLE:التعامل مع السكربتات في Next.js}}</noinclude>
يُعد المكوّن<code>next/script</code> في Next.js امتدادًا للعنصر <code><script></code> في HTML. ويتيح هذا المكوّن للمطورين تحديد أولوية تحميل السكربتات التي مصدرها طرف آخر في التطبيق خارج المكوّن <code>next/head</code> موفرًا بذلك الوقت ومحسنًا أداء التطبيق من ناحية التحميل.
يُعد المكوّن <code>next/script</code> في Next.js امتدادًا للعنصر <code>[[HTML/script|<script>]]</code> في [[HTML]]. ويتيح هذا المكوّن للمطورين تحديد أولوية تحميل السكربتات التي مصدرها طرف آخر خارجي في تطبيقاتهم موفرين بذلك الوقت ومحسنين أداء التطبيق من ناحية التحميل.
{| class="wikitable"
 
|+
== مقدمة ==
!النسخة
تستخدم مواقع ويب أحيانًا سكربتات يكتبها طرف آخر خارجي لإضافة وظائف مختلفة إلى تلك المواقع مثل التحليلات الإحصائية والإعلانات وأدوات دعم العملاء وإدارة القبولات. لكن قد يسبب ذلك مشاكل تؤثر على تجربة المستخدم والمطوّر:
!التغييرات فيما يتعلق بتحميل السكرتات
 
|-
* بطء تحميل بعض سكربتات الطرف الآخر مما ينعكس سلبًا على الأداء وعلى تجربة المستخدم وخاصة إن أعاقت عرض بعض الأجزاء وأخّرت تحميل محتوى أجزاء أخرى من الصفحة.
|<code>v11.0.0</code>
* صعوبة اختيار الموقع والوقت المناسب لتحميل السكربت في التطبيق للتأكد من تحميل الموقع وعرضه بالشكل الأمثل.
|ظهور المكوّن <code>next/script</code>.
|}
إليك طريقة استخدام المكوّن:<syntaxhighlight lang="javascript">
import Script from 'next/script'


export default function Home() {
تحمل المتصفحات عادةً عناصر محتوى العنصر <code><script></code> بناءً على ترتيب موقعها في صفحة HTML التي تحللها وبناءً على استخدام الخاصية async أو الخاصية defer معه إلا أن التحدي الأكبر في استعمال العنصر <code><script></code> الذي توفره HTML مباشرة يكمن في ما يلي:
  return (
    <>
      <Script src="https://www.google-analytics.com/analytics.js" />
    </>
  )
}
</syntaxhighlight>تستخدم مواقع ويب أحيانًا سكربتات يكتبها طرف آخر لإضافة وظائف مختلفة إلى هذه المواقع مثل التحليلات الإحصائية و الإعلانات وأدوات دعم العملاء وإدارة القبولات. لكن قد يسبب ذلك مشاكل تؤثر على تجربة المستخدم والمطوّر:


* بطئ تحميل بعض سكربتات الطرف الآخر مما ينعكس سلبًا على الأداء وعلى تجربة المستخدم وخاصة إن أعاقا تصيير بعض الأجزاء وأخّرت تحميل محتوى أجزاء أخرى من الصفحة.
* كلما كبر التطبيق وزاد تعقيده، زادت صعوبة إدارة تحميل السكربتات الخارجية.
* صعوبة اختيار الموقع المناسب للسكربت في التطبيق للتأكد من تحميل الموقع بالشكل الأمثل.
* تحسن خاصية الإرسال الدفقي streaming والانتظار suspense التي توفرها Next.js عملية تحميل الصفحة وعرضها تدريجيًا بمجرد ما يصبح المحتوى جاهزًا للعرض إلا أن هذه الآلية غير متوافقة مع استعمال العنصر <code><script></code> مع بعض خاصياته (مثل <code>defer</code>) دون إنجاز بعض الأمور.


يُسهّل المكوّن على المطوّرين وضع سكربت من مصدر آخر في أي مكان من التطبيق دون الحاجة إلى التفكير باستراتيجيات أنسب لتحميله.
يحل مكوّن السكربت الذي توفره Next.js عبر <code>next/script</code> تلك المشاكل عبر توفير واجهة API تبين كيفية تحميل السكربتات الخارجية، إذ يوفر مجموعة من آليات التحميل الجاهزة التي يمكن استخدامها لتحسين تحميل طابور السكربتات مع دعم الإرسال الدفقي streaming، وتضمن هذه الآليات استخدام أفضل ما في مكتبة ريآكت React وما توفره واجهات الويب Web API لتحميل السكربتات بأقل تأثير على أداء الصفحة.


== استخدام المكوّن Script في Next.js ==
== استخدام المكون Script ==
أدرج المكوّن <code>next/script</code> إن اردت استخدام سكربت من طرف آخر:<syntaxhighlight lang="javascript">
أدرج المكوّن <code>next/script</code> إن اردت استخدام سكربت من طرف آخر بالشكل التالي:<syntaxhighlight lang="javascript">
import Script from 'next/script'
import Script from 'next/script'
</syntaxhighlight>
</syntaxhighlight>


=== الخاصية <code>strategy</code> ===
=== تحميل سكربت على في صفحة ===
يتيح لك استخدام المكوّن تحديد توقيت استخدام السكربتات من خلال الخاصية <code>strategy</code> :<syntaxhighlight lang="javascript">
إن أردت تحميل سكربت في صفحة محددة ضمن تطبيقك، فاستورد <code>next/script</code> داخل مكون الصفحة مباشرة واستعلمه مباشرةً:<syntaxhighlight lang="javascript">
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />
import Script from 'next/script'
</syntaxhighlight>هنالك ثلاث استراتيجيات مختلفة لتحميل السكربتات يمكن استخدامها:


* <code>beforeInteractive</code>: تحميل السكربت قبل أن تغدو الصفحة تفاعلية مع المستخدم.
export default function Dashboard() {
* <code>afterInteractive</code>: (الطريقة الافتراضية) تحميل السكربت بعد أن تغدو الصفحة تفاعلية مباشرة.
  return (
* <code>lazyOnload</code>: تحميل السكربت أثناء فترة التوقف عن العمل idle.
    <>
* <code>worker</code>:(تجريبية) تحميل السكربت في عامل ويب web worker.
      <Script src="https://example.com/script.js" />
 
    </>
==== استخدام استراتيجية beforeInteractive ====
  )
تُدفع السكربتات التي تحمّل وفق هذه الاستراتيجية ضمن شيفرة HTML التي يوّلدها الخادم وتُنفَّذ قبل عملية التجميع الذاتي لشيفرة JavaScript. يجدر بك استخدام هذه الاستراتيجية مع السكربتات الحيوية التي ينبغي إحضارها وتنفيذها قبل أن يتمكن المستخدم من التفاعل مع الصفحة. تعمل هذه الاستراتيجية داخل الملف "document.js_" فقط، وقد صُمِّمت لتحميل السكربتات التي يحتاجها الموقع بأكمله (أي عندما يُفترض تحميل السكربت عند تحميل أي صفحة في التطبيق من جانب الخادم).
}
</syntaxhighlight>سيُحمَّل السكربت ويُنفَّذ بمجرد زيارة المتصفح تلك الصفحة فقط وتحميلها.


إن سبب عمل الاستراتيجية <code>beforeInteractive</code> ضمن الملف <code>document.js_\</code> هو دعم التدفق المستمر والتفاعلي للبيانات، فمن المستحيل أن تضمن توقيت تنفيذ سكربتات <code>beforeInteractive</code> أو ترتيبها خارج هذا الملف.<syntaxhighlight lang="javascript">
=== تحميل سكربت في كل الصفحات ===
// In _document.js
أما إن أردت تحميل سكربت خارجي في كل الصفحات أي على مستوى كل التطبيق، فاستورد <code>next/script</code> مباشرةً ضمن الملف <code>pages/_app.js</code>:<syntaxhighlight lang="javascript">
import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
import Script from 'next/script'


export default function Document() {
export default function MyApp({ Component, pageProps }) {
   return (
   return (
     <Html>
     <>
       <Head />
       <Script src="https://example.com/script.js" />
      <body>
       <Component {...pageProps} />
        <Main />
     </>
        <NextScript />
        <Script
          src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"
          strategy="beforeInteractive"
        ></Script>
       </body>
     </Html>
   )
   )
}
}
</syntaxhighlight>من السكربتات التي ينبغي تحملها وفق هذه الاستراتيجية نجد:
</syntaxhighlight>سيُحمَّل السكرتب ويُنفَّف بمجرد زيارة أي صفحة في تطبيقكـ وستتأكد Next.js من تحميل السكربت '''مرة واحدة فقط''' حتى لو تنقل المستخدم بين عدة صفحات مختلفة.


* مكتشفات المؤتمِتات Bot detectors
'''ملاحظة''': نادرًا ما ستحتاج إلى تحميل سكربت على مستوى التطبيق كله في كل صفحاته، وننصح دومًا بتجنب هذا السلوك والاقتصار على تحميل السكربتات الخارجية على مستوى الصفحات فقط لتقليل أي أثر سلبي يصيب الأداء.
* مديرو قبول ملفات تعريف الارتباط.


==== استخدام استراتيجية afterInteractive ====
=== الخاصية <code>strategy</code> ===
تُدفع بالسكربتات التي تستخدم هذه الاستراتيجية إلى جانب العميل وتُنفَّذ بعد أن ترطِّب Next.js الصفحة (بعد أن تحلل شيفرة JavaScript). ينبغي استخدام هذه الاستراتيجية مع السكربتات التي لا نحتاج إلى تحميلها بأقصى سرعة ويمكن أن نحضرها وننفذها بعد أن تغدو الصفحة تفاعلية مع المستخدم:<syntaxhighlight lang="javascript">
رغم أن السلوك الافتراضي للسكربت الذي توفره Next.js يسمح لك بتحميل سكربتات خارجية في أي صفحة إلا أنه يوفر لك وسيلة لتحديد استراتيجية التحميل تلك وذلك عبر الخاصية <code>strategy</code> التي تأخذ إحدى القيم التالية التي تمثل آليات التحميل:
<Script
* <code>beforeInteractive</code>: تحميل السكربت قبل أن تغدو الصفحة تفاعلية مع المستخدم.
  strategy="afterInteractive"
* <code>afterInteractive</code>: (الطريقة الافتراضية) تحميل السكربت بعد أن تغدو الصفحة تفاعلية مباشرة.
  dangerouslySetInnerHTML={{
* <code>lazyOnload</code>: تحميل السكربت لاحقًا أثناء فترة خمول المتصفح idle.
    __html: `
* <code>worker</code>:  (تجريبية) تحميل السكربت عبر عامل ويب web worker.
    (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
إن أردت معرفة معلومات أكثر حول كل آلية وحالات استخدامها، فارجع إلى توثيق [[Next.js/next script|next/script]].
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer', 'GTM-XXXXXX');
  `,
  }}
/>
</syntaxhighlight>من السكربتات التي تُعد أمثلة جيدة عن هذه الحالة نجد:


* مديرو الوسوم Tag managers
'''ملاحظة''': بمجرد تحميل المتصفح للسكربت <code>next/script</code>، فإنه يبقى في شجرة DOM دون إمكانية إعادة تنفيذه إن جرى الوصول له.  
* المحللات Analytics
 
==== استخدام الاستراتيجية lazyOnload ====
تُحمّل السكربتات وفق هذه الاستراتيجية بعد إحضار كل الموارد وأثناء وقت الراحة (التوقف عن العمل). ينبغي استخدام هذه الاستراتيجية في الخلفية أو للسكربتات ذات الأولوية المنخفضة التي لا حاجة لتحميها مباشرة قبل أو بعد أن تغدو الصفحة تفاعلية:<syntaxhighlight lang="javascript">
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />
</syntaxhighlight>من السكربتات التي تُعد أمثلة جيدة عن هذه الحالة نجد:
 
* الإضافات التي تدعم المحادثات.
* أدوات الارتباط بمواقع التواصل الاجتماعي.


=== التحميل الجانبي للسكربت باستخدام عامل ويب (استراتيجية تجريبية) ===
=== التحميل الجانبي للسكربت باستخدام عامل ويب (استراتيجية تجريبية) ===
<blockquote>ملاحظة: لا تزال هذه الاستراتيجية تجريبية وغير مستقرة وقد تسبب أخطاءً غير متوقعة في تطبيق لذك استخدمها بحذر.</blockquote>يُحدد موقع السكربتات التي تستخدم هذه الاستراتيجية وتُنفَّذ بواسطة [https://partytown.builder.io/ Partytown]، وقد يُحسِّن ذلك أداء الموقع بتخصيص الخيط الأساسي لتنفيذ التطبيق لبقية الشيفرة.
<blockquote>'''ملاحظة''': لا تزال هذه الاستراتيجية تجريبية وغير مستقرة وقد تسبب أخطاءً غير متوقعة بالإضافة إلى أنها لا تعمل مع المجلد <code>/app</code> لذك استخدمها بحذر.</blockquote>يُحدَّد موقع السكربتات التي تستخدم هذه الاستراتيجية وتُنفَّذ بواسطة عامل ويب مع [https://partytown.builder.io/ Partytown]، وقد يُحسِّن ذلك أداء الموقع بتخصيص الخيط الأساسي main thread لتنفيذ شيفرة التطبيق الأساسية فقط، ولا تزال هذه الاستراتيجية تجريبية، ولا يمكن استخدامها دون تمكين الراية <code>nextScriptWorkers</code> في الملف <code>next.config.js</code>:<syntaxhighlight lang="javascript">
 
لا تزال هذه الاستراتيجية تجريبية ولا يمكن استخدامها دون تمكين الراية <code>nextScriptWorkers</code> في الملف <code>next.config.js</code>:<syntaxhighlight lang="javascript">
module.exports = {
module.exports = {
   experimental: {
   experimental: {
سطر 105: سطر 66:
   },
   },
}
}
</syntaxhighlight>نفّذ بعد ذلك أحد الأمرين <code>npm run dev</code> أو <code>yarn dev</code> وسترشدك خلال عملية تثبيت الحزم اللازمة لإتمام الأمر:<syntaxhighlight lang="bash">
</syntaxhighlight>نفّذ بعد ذلك أحد الأمرين <code>npm run dev</code> أو <code>yarn dev</code> وسترشدك Next.js إلى عملية تثبيت الحزم اللازمة لإتمام الأمر:<syntaxhighlight lang="bash">
npm run dev
npm run dev


سطر 115: سطر 76:
#
#
# ...
# ...
</syntaxhighlight>بعد أن يكتمل التثبيت، اجعل <code>strategy="worker"</code> لكي يُنسخ Partytown تلقائيًا إلى تطبيقك لتبدأ بتحميل السكربت جانبيًا ضمن خيط عامل ويب.<syntaxhighlight lang="javascript">
</syntaxhighlight>بعد أن يكتمل التثبيت، سيؤدي استخدام <code>strategy="worker"</code> إلى نسخ ما يلزمك من مكتبة Partytown تلقائيًا إلى تطبيقك التي تبدأ بتحميل السكربت جانبيًا ضمن خيط عامل ويب أثناء عمل تطبيقك في المتصفح.<syntaxhighlight lang="javascript">
<Script src="https://example.com/analytics.js" strategy="worker" />
import Script from 'next/script'
</syntaxhighlight>ينبغي الإشارة إلى بعض التنازلات أو الآثار الجانبية لتحميل سكربتات طرف آخر في عامل ويب. يمكنك العودة إلى [https://partytown.builder.io/trade-offs توثيق Partytown] لمعلومات أكثر


==== تهيئة الاستراتيجية  <code>worker</code> للعمل ====
export default function Home() {
على الرغم من عدم حاجة هذه الاستراتيجة إلى إعدادات خاصة لتعمل، يدعم Partytown استخدام كائن تهيئة config object لتعديل بعض إعداداته بما في ذلك نمط التنقيح <code>debug</code> وتوجيه الأحداث forwarding events ومسببات الأحداث triggers.
 
إن رغبت في إضافة إعدادات أخرى، بإمكانك تضمينها داخل المكوّن <code></ Head></code> الذي يُستخدم في ملف  [[Next.js/custom document|<code>document.js_</code>]] مخصص:<syntaxhighlight lang="javascript">
import { Html, Head, Main, NextScript } from 'next/document'
 
export default function Document() {
   return (
   return (
     <Html>
     <>
       <Head>
       <Script src="https://example.com/script.js" strategy="worker" />
        <script
     </>
          data-partytown-config
          dangerouslySetInnerHTML={{
            __html: `
              partytown = {
                lib: "/_next/static/~partytown/",
                debug: true
              };
            `,
          }}
        />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
     </Html>
   )
   )
}
}
</syntaxhighlight>لا بد من تحقيق الشروط التالية إن أردت تعديل إعدادات :
</syntaxhighlight>ينبغي الإشارة إلى وجود بعض الآثار الجانبية لتحميل سكربتات خارجية في عامل ويب، وبإمكانك العودة إلى [https://partytown.builder.io/trade-offs توثيق Partytown] لمعلومات أكثر.
 
=== السكربتات السطرية Inline Scripts ===
# استخدام السمة <code>data-partytown-config</code> لإلغاء الإعدادات الافتراضية التي تستخدمها  Next.js.
يدعم المكوّن <code></ Script></code> السكربتات السطرية أو تلك التي لا تحمّل من ملفات خارجية. إذ يمكن كتابتها ضمن القوسين المعقوصين داخل المكوّن:<syntaxhighlight lang="javascript">
# استخدام الخاصية التالية وقيمتها <code>"/lib: "/_next/static/~partytown</code> ضمن كائن التهيئة لكي يعرف Partytown أين تخزّن Next.js الملفات الساكنة الضرورية. وهذا الأمر غير ضروري إن أردت تخزين ملفات مكتبة Partytown في مجلد مستقل.  
<Script id="show-banner">
 
<blockquote>إن كنت تستخدم asset prefix وأردت تعديل إعدادات Partytown الافتراضية، عليك تضمينها كجزء من مسار الخاصية  <code>lib</code>.</blockquote>للاطلاع على مزيد من إعدادت التهيئة لمكتبة Partytown راجع التوثيق الخاص بها.
 
=== السكربتات السطرية في Next.js ===
يدعم المكوّن <code></ Script></code> السكربتات السطرية أو تلك التي لا تحمّل من ملفات خارجية. إذ يمكن كتابتها ضمن القوسين المعقوصين للمكوّن:<syntaxhighlight lang="javascript">
<Script id="show-banner" strategy="lazyOnload">
   {`document.getElementById('banner').classList.remove('hidden')`}
   {`document.getElementById('banner').classList.remove('hidden')`}
</Script>
</Script>
</syntaxhighlight>أو من خلال استعمال الخاصية <code>dangerouslySetInnerHTML</code>: <syntaxhighlight lang="javascript">
</syntaxhighlight>أو من خلال استعمال الخاصية <code>dangerouslySetInnerHTML</code>: <syntaxhighlight lang="javascript">
<Script
<Script
   id="show-banner"
   id="show-banner"
سطر 167: سطر 99:
   }}
   }}
/>
/>
</syntaxhighlight>لا بد من استخدام الخاصية <code>id</code> في السكربتات السطرية لتتبع Next.js السكربت وتحسن أداءه.
</syntaxhighlight>لا بد من استخدام الخاصية <code>id</code> في السكربتات السطرية كي تتبع Next.js السكربت وتحسن أداءه.
 
=== تنفيذ مهام إضافية مع السكربت ===
تتطلب بعد السكربتات التي يقدمها طرف آخر خارجي تنفيذ شيفرة [[JavaScript]] عند وقوع أحداث معينة مثلًا بعد أن ينتهي تحميل السكربت، وذلك لتنفيذ مهام إضافية تكمِّل عمل السكربت والأحداث التي يدعمها سكربت Next.js تتمثل في الخاصيات التالية:


=== تنفيذ الشيفرة بعد التحميل <code>onLoad</code> في Next.js ===
* <code>onLoad</code>: تأخذ دالة تُستدعى بعد انتهاء تحميل السكربت.
<blockquote>لا تستخدم كلتا الخاصيتين <code>onLoad</code> و <code>onError</code> مع استراتيجية التحميل <code>beforeInteractive</code></blockquote>تتطلب بعد السكربتات التي يقدمها طرف آخر تنفيذ شيفرة JavaScript بعد أن ينتهي تحميل تلك السكربتات، وذلك كي تنسخ محتوى أو تستدعي دالة. فإن كنت تستخدم إحدى استراتيجيتي التحميل <code>afterInteractive</code> أو <code>lazyOnload</code> بإمكانك تنفيذ الشيفرة بعد تحميلها من خلال استخدام الخاصية <code>onLoad</code>:<syntaxhighlight lang="javascript">
* <code>onReady</code>: تأخذ دالة تُستدعى بعد انتهاء تحميل السكربت وفي كل مرة يضاف فيها المكون mounted.
import { useState } from 'react'
* <code>onError</code>: تأخذ دالة تُنفَّذ إن فشل تحميل السكربت. 
<syntaxhighlight lang="javascript">
import Script from 'next/script'
import Script from 'next/script'


export default function Home() {
export default function Page() {
  const [stripe, setStripe] = useState(null)
 
   return (
   return (
     <>
     <>
       <Script
       <Script
        id="stripe-js"
         src="https://example.com/script.js"
         src="https://js.stripe.com/v3/"
         onLoad={() => {
         onLoad={() => {
           setStripe({ stripe: window.Stripe('pk_test_12345') })
           console.log('Script has loaded')
         }}
         }}
       />
       />
سطر 189: سطر 122:
   )
   )
}
}
</syntaxhighlight>وقد يساعدك أحيانًا التقاط الأخطاء الناتجة عن فشل التحميل ومعالجتها باستخدام الخاصية <code>onError</code>:<syntaxhighlight lang="javascript">
</syntaxhighlight>عد إلى توثيق الواجهة البرمجية [[Next.js/next script|next/script]] لمعلومات أوسع حول معالجة كل حدث من تلك الأحداث.
=== استخدام سمات إضافية ===
هنالك العديد من سمات شجرة DOM الخاصة بالعنصر <code>[[HTML/script|<script>]]</code> ولكن لا يستخدمها المكوّن <code></ Script></code> مثل <code>nonce</code> أو [[HTML/data|سمات البيانات المخصصة]]، لذا ستُحوَّل تلقائيًا أي سمات إضافية إلى العنصر <code><script></code> النهائي المحسّن والذي سيُضمَّن في صفحة HTML.<syntaxhighlight lang="javascript">
import Script from 'next/script'
import Script from 'next/script'


export default function Home() {
export default function Page() {
   return (
   return (
     <>
     <>
       <Script
       <Script
        id="will-fail"
         src="https://example.com/script.js"
         src="https://example.com/non-existant-script.js"
         id="example-script"
         onError={(e) => {
        nonce="XUENAJFW"
          console.error('Script failed to load', e)
         data-test="script"
         }}
       />
       />
     </>
     </>
سطر 207: سطر 141:
</syntaxhighlight>
</syntaxhighlight>


=== استخدام سمات إضافية ===
== أمثلة ==
لا يمكن استخدام العديد من سمات شجرة DOM الخاصة بالعنصر <code><script></code> مع المكوّن <code></ Script></code> مثل <code>nonce</code> أو سمات البيانات المخصصة. عند تضمين أية سمات إضافية ستُنقل تلقائيًا إلى العنصر <code><script></code> النهائي المحسّن والذي سيُنفّذ عند عرض الصفحة.<syntaxhighlight lang="javascript">
import Script from 'next/script'


export default function Home() {
* [https://github.com/vercel/next.js/tree/canary/examples/script-component Script Component]
  return (
* [https://github.com/vercel/next.js/tree/canary/examples/with-google-tag-manager Google Tag Manager]
    <>
* [https://github.com/vercel/next.js/tree/canary/examples/with-google-analytics Google Analytics]
      <Script
* [https://github.com/vercel/next.js/tree/canary/examples/with-facebook-pixel Facebook Pixel]
        src="https://www.google-analytics.com/analytics.js"
* [https://github.com/vercel/next.js/tree/canary/examples/with-clerk Clerk]
        id="analytics"
* [https://github.com/vercel/next.js/tree/canary/examples/with-segment-analytics Segment Analytics]
        nonce="XUENAJFW"
        data-test="analytics"
      />
    </>
  )
}
</syntaxhighlight>


== المصادر ==
== المصادر ==


* الصفحة [https://nextjs.org/docs/basic-features/script Script Component] من توثيق Next.js الرسمي
* الصفحة [https://nextjs.org/docs/basic-features/script Script Component] من توثيق Next.js الرسمي.
[[تصنيف:Next.js|{{SUBPAGENAME}}]]
[[تصنيف:Next.js Basic Features|{{SUBPAGENAME}}]]

المراجعة الحالية بتاريخ 17:19، 3 يناير 2023

يُعد المكوّن next/script في Next.js امتدادًا للعنصر <script> في HTML. ويتيح هذا المكوّن للمطورين تحديد أولوية تحميل السكربتات التي مصدرها طرف آخر خارجي في تطبيقاتهم موفرين بذلك الوقت ومحسنين أداء التطبيق من ناحية التحميل.

مقدمة

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

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

تحمل المتصفحات عادةً عناصر محتوى العنصر <script> بناءً على ترتيب موقعها في صفحة HTML التي تحللها وبناءً على استخدام الخاصية async أو الخاصية defer معه إلا أن التحدي الأكبر في استعمال العنصر <script> الذي توفره HTML مباشرة يكمن في ما يلي:

  • كلما كبر التطبيق وزاد تعقيده، زادت صعوبة إدارة تحميل السكربتات الخارجية.
  • تحسن خاصية الإرسال الدفقي streaming والانتظار suspense التي توفرها Next.js عملية تحميل الصفحة وعرضها تدريجيًا بمجرد ما يصبح المحتوى جاهزًا للعرض إلا أن هذه الآلية غير متوافقة مع استعمال العنصر <script> مع بعض خاصياته (مثل defer) دون إنجاز بعض الأمور.

يحل مكوّن السكربت الذي توفره Next.js عبر next/script تلك المشاكل عبر توفير واجهة API تبين كيفية تحميل السكربتات الخارجية، إذ يوفر مجموعة من آليات التحميل الجاهزة التي يمكن استخدامها لتحسين تحميل طابور السكربتات مع دعم الإرسال الدفقي streaming، وتضمن هذه الآليات استخدام أفضل ما في مكتبة ريآكت React وما توفره واجهات الويب Web API لتحميل السكربتات بأقل تأثير على أداء الصفحة.

استخدام المكون Script

أدرج المكوّن next/script إن اردت استخدام سكربت من طرف آخر بالشكل التالي:

import Script from 'next/script'

تحميل سكربت على في صفحة

إن أردت تحميل سكربت في صفحة محددة ضمن تطبيقك، فاستورد next/script داخل مكون الصفحة مباشرة واستعلمه مباشرةً:

import Script from 'next/script'

export default function Dashboard() {
  return (
    <>
      <Script src="https://example.com/script.js" />
    </>
  )
}

سيُحمَّل السكربت ويُنفَّذ بمجرد زيارة المتصفح تلك الصفحة فقط وتحميلها.

تحميل سكربت في كل الصفحات

أما إن أردت تحميل سكربت خارجي في كل الصفحات أي على مستوى كل التطبيق، فاستورد next/script مباشرةً ضمن الملف pages/_app.js:

import Script from 'next/script'

export default function MyApp({ Component, pageProps }) {
  return (
    <>
      <Script src="https://example.com/script.js" />
      <Component {...pageProps} />
    </>
  )
}

سيُحمَّل السكرتب ويُنفَّف بمجرد زيارة أي صفحة في تطبيقكـ وستتأكد Next.js من تحميل السكربت مرة واحدة فقط حتى لو تنقل المستخدم بين عدة صفحات مختلفة.

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

الخاصية strategy

رغم أن السلوك الافتراضي للسكربت الذي توفره Next.js يسمح لك بتحميل سكربتات خارجية في أي صفحة إلا أنه يوفر لك وسيلة لتحديد استراتيجية التحميل تلك وذلك عبر الخاصية strategy التي تأخذ إحدى القيم التالية التي تمثل آليات التحميل:

  • beforeInteractive: تحميل السكربت قبل أن تغدو الصفحة تفاعلية مع المستخدم.
  • afterInteractive: (الطريقة الافتراضية) تحميل السكربت بعد أن تغدو الصفحة تفاعلية مباشرة.
  • lazyOnload: تحميل السكربت لاحقًا أثناء فترة خمول المتصفح idle.
  • worker: (تجريبية) تحميل السكربت عبر عامل ويب web worker.

إن أردت معرفة معلومات أكثر حول كل آلية وحالات استخدامها، فارجع إلى توثيق next/script.

ملاحظة: بمجرد تحميل المتصفح للسكربت next/script، فإنه يبقى في شجرة DOM دون إمكانية إعادة تنفيذه إن جرى الوصول له.

التحميل الجانبي للسكربت باستخدام عامل ويب (استراتيجية تجريبية)

ملاحظة: لا تزال هذه الاستراتيجية تجريبية وغير مستقرة وقد تسبب أخطاءً غير متوقعة بالإضافة إلى أنها لا تعمل مع المجلد /app لذك استخدمها بحذر.

يُحدَّد موقع السكربتات التي تستخدم هذه الاستراتيجية وتُنفَّذ بواسطة عامل ويب مع Partytown، وقد يُحسِّن ذلك أداء الموقع بتخصيص الخيط الأساسي main thread لتنفيذ شيفرة التطبيق الأساسية فقط، ولا تزال هذه الاستراتيجية تجريبية، ولا يمكن استخدامها دون تمكين الراية nextScriptWorkers في الملف next.config.js:

module.exports = {
  experimental: {
    nextScriptWorkers: true,
  },
}

نفّذ بعد ذلك أحد الأمرين npm run dev أو yarn dev وسترشدك Next.js إلى عملية تثبيت الحزم اللازمة لإتمام الأمر:

npm run dev

# سترى إرشادات كالتالي
#
# Please install Partytown by running:
#
#         npm install @builder.io/partytown
#
# ...

بعد أن يكتمل التثبيت، سيؤدي استخدام strategy="worker"‎ إلى نسخ ما يلزمك من مكتبة Partytown تلقائيًا إلى تطبيقك التي تبدأ بتحميل السكربت جانبيًا ضمن خيط عامل ويب أثناء عمل تطبيقك في المتصفح.

import Script from 'next/script'

export default function Home() {
  return (
    <>
      <Script src="https://example.com/script.js" strategy="worker" />
    </>
  )
}

ينبغي الإشارة إلى وجود بعض الآثار الجانبية لتحميل سكربتات خارجية في عامل ويب، وبإمكانك العودة إلى توثيق Partytown لمعلومات أكثر.

السكربتات السطرية Inline Scripts

يدعم المكوّن </ Script> السكربتات السطرية أو تلك التي لا تحمّل من ملفات خارجية. إذ يمكن كتابتها ضمن القوسين المعقوصين داخل المكوّن:

<Script id="show-banner">
  {`document.getElementById('banner').classList.remove('hidden')`}
</Script>

أو من خلال استعمال الخاصية dangerouslySetInnerHTML:

<Script
  id="show-banner"
  dangerouslySetInnerHTML={{
    __html: `document.getElementById('banner').classList.remove('hidden')`,
  }}
/>

لا بد من استخدام الخاصية id في السكربتات السطرية كي تتبع Next.js السكربت وتحسن أداءه.

تنفيذ مهام إضافية مع السكربت

تتطلب بعد السكربتات التي يقدمها طرف آخر خارجي تنفيذ شيفرة JavaScript عند وقوع أحداث معينة مثلًا بعد أن ينتهي تحميل السكربت، وذلك لتنفيذ مهام إضافية تكمِّل عمل السكربت والأحداث التي يدعمها سكربت Next.js تتمثل في الخاصيات التالية:

  • onLoad: تأخذ دالة تُستدعى بعد انتهاء تحميل السكربت.
  • onReady: تأخذ دالة تُستدعى بعد انتهاء تحميل السكربت وفي كل مرة يضاف فيها المكون mounted.
  • onError: تأخذ دالة تُنفَّذ إن فشل تحميل السكربت.
import Script from 'next/script'

export default function Page() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        onLoad={() => {
          console.log('Script has loaded')
        }}
      />
    </>
  )
}

عد إلى توثيق الواجهة البرمجية next/script لمعلومات أوسع حول معالجة كل حدث من تلك الأحداث.

استخدام سمات إضافية

هنالك العديد من سمات شجرة DOM الخاصة بالعنصر <script> ولكن لا يستخدمها المكوّن </ Script> مثل nonce أو سمات البيانات المخصصة، لذا ستُحوَّل تلقائيًا أي سمات إضافية إلى العنصر <script> النهائي المحسّن والذي سيُضمَّن في صفحة HTML.

import Script from 'next/script'

export default function Page() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        id="example-script"
        nonce="XUENAJFW"
        data-test="script"
      />
    </>
  )
}

أمثلة

المصادر