الفرق بين المراجعتين ل"Next.js/dynamic import"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
ط (مراجعة)
سطر 1: سطر 1:
 
<noinclude>{{DISPLAYTITLE:الإدراج الديناميكي في Next.js}}</noinclude>
 
<noinclude>{{DISPLAYTITLE:الإدراج الديناميكي في Next.js}}</noinclude>
تدعم Next.js إدراج الوحدات البرمجية ديناميكيًا <code>[https://github.com/tc39/proposal-dynamic-import ()import]</code> والعمل معها بما يتوافق مع معيار ES2020 للغة JavaScript، كما يعمل هذا الإدراج عند التصيير من جانب الخادم SSR.
+
تدعم Next.js الإدراج الكسول أو المتأني للمكتبات الخارجية عبر <code>import()‎</code> وللمكونات [[React]] عبر <code>next/dynamic</code> إذ يساعد التحميل المؤجل أو المتأني على تحسين أداء التطبيق عند تحميله أول مرة وذلك بتقليل شيفرة JavaScript الضروري لعرض الصفحات، أما المكتبات أو المكونات المؤجلة، فستُحمل وتضاف في حزمة [[JavaScript]] المُجمعة عند الحاجة إليها فقط.
  
ننجز في المثال التالي بحثًا ضبابيًا باستخدام الوحدة البرمجية <code>fuse.js</code> التي نحمّلها ديناميكيًا في المتصفح بعد أن يبدأ المستخدم في الكتابة ضمن مربع البحث:<syntaxhighlight lang="javascript">
+
المكون <code>next/dynamic</code> هو توسيع للمكون [[React/code splitting#.D8.A7.D9.84.D8.AF.D8.A7.D9.84.D8.A9 React.lazy|<code>React.lazy</code>]] والمكون <code>[[React/react api#.D8.A7.D9.84.D8.AA.D8.B9.D9.84.D9.8A.D9.82 .28Suspense.29|Suspense]]</code>، وتستطيع المكونات تأخير عملية الترطيب حتى ينتهي التعليق <code>Suspense</code>.
import { useState } from 'react'
 
 
 
const names = ['Tim', 'Joe', 'Bel', 'Max', 'Lee']
 
 
 
export default function Page() {
 
  const [results, setResults] = useState()
 
 
 
  return (
 
    <div>
 
      <input
 
        type="text"
 
        placeholder="Search"
 
        onChange={async (e) => {
 
          const { value } = e.currentTarget
 
          // Dynamically load fuse.js
 
          const Fuse = (await import('fuse.js')).default
 
          const fuse = new Fuse(names)
 
  
          setResults(fuse.search(value))
+
== مثال  ==
        }}
+
في المثال التالي، استخدام next/dynamic يمنع من إضافة مكون الرأس header في حزمة JavaScript الأولية المجمعة للصفحة، وستعرض الصفحة التعليق Suspense أولًا ثم ستعرض المكون Header عندما يُحمل ويصبح جاهزًا.<syntaxhighlight lang="javascript">
      />
 
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
 
    </div>
 
  )
 
}
 
</syntaxhighlight>يمكن التفكير بالإدراج الديناميكي على أنه طريقة إلى تقسيم شيفرتك إلى أجزاء يمكن التحكم بها. وتستطيع من خلاله أن تدرج أيضًا مكوّنات React، لكن عليك في هذه الحالة استخدامه بالاشتراك مع <code>next/dynamic</code> للتأكد من عمله كأي مكوّن React آخر، وسنرى لاحقًا في هذه الصفحة تفاصيل أكثر عن هذا الموضوع.
 
 
 
== الاستخدامات الرئيسية ==
 
ستُحمَّل الوحدة البرمجية <code>components/hello/..</code> ديناميكيًا في الصفحة في المثال التالي:<syntaxhighlight lang="javascript">
 
 
import dynamic from 'next/dynamic'
 
import dynamic from 'next/dynamic'
  
const DynamicComponent = dynamic(() => import('../components/hello'))
+
const DynamicHeader = dynamic(() => import('../components/header'), {
 +
  loading: () => 'Loading...',
 +
})
  
function Home() {
+
export default function Home() {
   return (
+
   return <DynamicHeader />
    <div>
 
      <Header />
 
      <DynamicComponent />
 
      <p>HOME PAGE is here!</p>
 
    </div>
 
  )
 
 
}
 
}
 
+
</syntaxhighlight><blockquote>'''ملاحظة''': يجب أن يُكتب المسار <code>import('path/to/component')</code> إلى الوحدة البرمجية صراحة، ولا يجوز أن يكون قالب نصي أو متغير. كما ينبغي أن تكون الدالة <code>()import</code> ضمن الاستدعاء <code>()dynamic</code> كي تتمكن من مطابقة معرّفات وحدات أو تجمّعات webpack إلى الاستدعاء <code>()dynamic</code> وإعادة تحميلها قبل التصيير. فمن غير الممكن استخدام <code>()dynamic</code> داخل شيفرة تصيير React، بل ينبغي أن تُذكر في أعلى مستوى للوحدة للبرمجية حتى يعمل التحميل المسبق preloading، كما هو الحال مع <code>React.lazy</code>.</blockquote>
export default Home
 
</syntaxhighlight>يُعاد المكوّن <code>DynamicComponent</code> افتراضيًا من قبل الوحدة <code>components/hello/..</code>، ويعمل كمكوّن React نمطي، إذ يمكنكك تمرير الخاصيات إليه بشكل اعتيادي.<blockquote>'''ملاحظة''': يجب أن يُكتب المسار <code>import('path/to/component')</code> إلى الوحدة البرمجية صراحة، ولا يجوز أن يكون قالب نصي أو متغير. كما ينبغي أن تكون الدالة <code>()import</code> ضمن الاستدعاء <code>()dynamic</code> كي تتمكن من مطابقة معرّفات وحدات أو تجمّعات webpack إلى الاستدعاء <code>()dynamic</code> وإعادة تحميلها قبل التصيير. فمن غير الممكن استخدام <code>()dynamic</code> داخل شيفرة تصيير React، بل ينبغي أن تُذكر في أعلى مستوى للوحدة للبرمجية حتى يُعاد تحميل الوحدة، كما هو الحال مع <code>React.lazy</code>.</blockquote>
 
  
 
== الاستخدام مع الدوال المُصدَّرة المسماة ==
 
== الاستخدام مع الدوال المُصدَّرة المسماة ==
يمكنك استخدام التصدير المُسمّى named import أيضًا إن لم يُصدَّر المكوّن الديناميكي افتراضيًا. لنتأمل الوحدة <code>components/hello.js/..</code> التي تصدّر الدالة المسمّاة <code>Hello</code>:<syntaxhighlight lang="javascript">
+
لإدراج مكوّن ديناميكيًا من تصدير مسمى named export، يمكنك إعادته من وعد [[JavaScript/Promise|<code>Promise</code>]] تُعيده الدالة <code>[https://github.com/tc39/proposal-dynamic-import#example ()import]</code> كالتالي:<syntaxhighlight lang="javascript">
 +
// components/hello.js
 
export function Hello() {
 
export function Hello() {
 
   return <p>Hello!</p>
 
   return <p>Hello!</p>
 
}
 
}
</syntaxhighlight>ولإدراج المكوّن <code>Hello</code> ديناميكيًا، يمكنك إعادته من وعد Promise تُعيده الدالة <code>()import</code> كالتالي:<syntaxhighlight lang="javascript">
+
 
 +
// pages/index.js
 
import dynamic from 'next/dynamic'
 
import dynamic from 'next/dynamic'
  
سطر 60: سطر 30:
 
   import('../components/hello').then((mod) => mod.Hello)
 
   import('../components/hello').then((mod) => mod.Hello)
 
)
 
)
 
function Home() {
 
  return (
 
    <div>
 
      <Header />
 
      <DynamicComponent />
 
      <p>HOME PAGE is here!</p>
 
    </div>
 
  )
 
}
 
 
export default Home
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== الاستخدام مع مكوّن تحميل مخصص ==
+
== الاستخدام دون تصيير من جانب الخادم SSR ==
يمكن إضافة مكوّن تحميل اختياري <code>loading</code> لتصيير حالة التحميل أثناء تحميل المكوّن الديناميكي. إليك مثالًا:<syntaxhighlight lang="javascript">
+
لتحميل مكون ديناميكيًا من طرف العميل، تستطيع استخدام الخيار <code>ssr</code> لتعطيل التصير من طرف الخادم، وهذا مفيد في الحالات التي يعتمد فيها مكون أو مكتبة على إحدى واجهات المتصفح browser API مثل <code>window</code>:<syntaxhighlight lang="javascript">
 
import dynamic from 'next/dynamic'
 
import dynamic from 'next/dynamic'
  
const DynamicComponentWithCustomLoading = dynamic(
+
const DynamicHeader = dynamic(() => import('../components/header'), {
  () => import('../components/hello'),
+
   ssr: false,
   { loading: () => <p>...</p> }
+
})
)
+
</syntaxhighlight>
  
function Home() {
+
== الاستخدام مع مكتبات خارجية ==
  return (
+
يستخدم المثال التالي المكتبة الخارجية fuse.js للبحث، وستُحمل المكتبة فقط في المتصفح عندما يبدأ المُستخدم الكتابة في حقل البحث:<syntaxhighlight lang="javascript">
    <div>
+
import { useState } from 'react'
      <Header />
 
      <DynamicComponentWithCustomLoading />
 
      <p>HOME PAGE is here!</p>
 
    </div>
 
  )
 
}
 
  
export default Home
+
const names = ['Tim', 'Joe', 'Bel', 'Lee']
</syntaxhighlight>
 
  
== الاستخدام دون تصيير من جانب الخادم ==
+
export default function Page() {
قد لا ترغب دائمًا بإدراج وحدة برمجية من جانب الخادم، كأن تستخدم مكتبة تعمل على المتصفح فقط. ألق نظرة على المثال التالي:<syntaxhighlight lang="javascript">
+
  const [results, setResults] = useState()
import dynamic from 'next/dynamic'
 
  
const DynamicComponentWithNoSSR = dynamic(
 
  () => import('../components/hello3'),
 
  { ssr: false }
 
)
 
 
function Home() {
 
 
   return (
 
   return (
 
     <div>
 
     <div>
       <Header />
+
       <input
       <DynamicComponentWithNoSSR />
+
        type="text"
       <p>HOME PAGE is here!</p>
+
        placeholder="Search"
 +
        onChange={async (e) => {
 +
          const { value } = e.currentTarget
 +
          // Dynamically load fuse.js
 +
          const Fuse = (await import('fuse.js')).default
 +
          const fuse = new Fuse(names)
 +
 
 +
          setResults(fuse.search(value))
 +
        }}
 +
       />
 +
       <pre>Results: {JSON.stringify(results, null, 2)}</pre>
 
     </div>
 
     </div>
 
   )
 
   )
 
}
 
}
  
export default Home
 
</syntaxhighlight>
 
 
== الاستخدام مع الخيار suspense ==
 
يتيح لك هذا الخيار <code>suspense</code> التحميل الكسول للمكوّن كما هو الحال مع <code>React.lazy</code> و <code><Suspense></code> في النسخة 18 من React. يعمل هذا الخيار في كلا الواجهتين باستخدام خيار التراجع <code>fallback</code> فقط. لم يُدعم التصيير من جانب الخادم بشكل كامل، والعمل جارٍ على تطويره.<syntaxhighlight lang="javascript">
 
import dynamic from 'next/dynamic'
 
 
const DynamicLazyComponent = dynamic(() => import('../components/hello4'), {
 
  suspense: true,
 
})
 
 
function Home() {
 
  return (
 
    <div>
 
      <Suspense fallback={`loading`}>
 
        <DynamicLazyComponent />
 
      </Suspense>
 
    </div>
 
  )
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  

مراجعة 14:21، 24 ديسمبر 2022

تدعم Next.js الإدراج الكسول أو المتأني للمكتبات الخارجية عبر import()‎ وللمكونات React عبر next/dynamic إذ يساعد التحميل المؤجل أو المتأني على تحسين أداء التطبيق عند تحميله أول مرة وذلك بتقليل شيفرة JavaScript الضروري لعرض الصفحات، أما المكتبات أو المكونات المؤجلة، فستُحمل وتضاف في حزمة JavaScript المُجمعة عند الحاجة إليها فقط.

المكون next/dynamic هو توسيع للمكون React.lazy والمكون Suspense، وتستطيع المكونات تأخير عملية الترطيب حتى ينتهي التعليق Suspense.

مثال

في المثال التالي، استخدام next/dynamic يمنع من إضافة مكون الرأس header في حزمة JavaScript الأولية المجمعة للصفحة، وستعرض الصفحة التعليق Suspense أولًا ثم ستعرض المكون Header عندما يُحمل ويصبح جاهزًا.

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  loading: () => 'Loading...',
})

export default function Home() {
  return <DynamicHeader />
}

ملاحظة: يجب أن يُكتب المسار import('path/to/component') إلى الوحدة البرمجية صراحة، ولا يجوز أن يكون قالب نصي أو متغير. كما ينبغي أن تكون الدالة ()import ضمن الاستدعاء ()dynamic كي تتمكن من مطابقة معرّفات وحدات أو تجمّعات webpack إلى الاستدعاء ()dynamic وإعادة تحميلها قبل التصيير. فمن غير الممكن استخدام ()dynamic داخل شيفرة تصيير React، بل ينبغي أن تُذكر في أعلى مستوى للوحدة للبرمجية حتى يعمل التحميل المسبق preloading، كما هو الحال مع React.lazy.

الاستخدام مع الدوال المُصدَّرة المسماة

لإدراج مكوّن ديناميكيًا من تصدير مسمى named export، يمكنك إعادته من وعد Promise تُعيده الدالة ()import كالتالي:

// components/hello.js
export function Hello() {
  return <p>Hello!</p>
}

// pages/index.js
import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)

الاستخدام دون تصيير من جانب الخادم SSR

لتحميل مكون ديناميكيًا من طرف العميل، تستطيع استخدام الخيار ssr لتعطيل التصير من طرف الخادم، وهذا مفيد في الحالات التي يعتمد فيها مكون أو مكتبة على إحدى واجهات المتصفح browser API مثل window:

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  ssr: false,
})

الاستخدام مع مكتبات خارجية

يستخدم المثال التالي المكتبة الخارجية fuse.js للبحث، وستُحمل المكتبة فقط في المتصفح عندما يبدأ المُستخدم الكتابة في حقل البحث:

import { useState } from 'react'

const names = ['Tim', 'Joe', 'Bel', 'Lee']

export default function Page() {
  const [results, setResults] = useState()

  return (
    <div>
      <input
        type="text"
        placeholder="Search"
        onChange={async (e) => {
          const { value } = e.currentTarget
          // Dynamically load fuse.js
          const Fuse = (await import('fuse.js')).default
          const fuse = new Fuse(names)

          setResults(fuse.search(value))
        }}
      />
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
    </div>
  )
}

المصادر