نفخر اليوم بإطلاق Next.js 8 جاهزًا للإنتاج، متضمنًا:
- Next.js بدون خادم (Serverless)
- تخفيض كبير في استخدام الذاكرة أثناء البناء
- تكوين بيئة وقت البناء
- تحسينات في أداء الجلب المسبق (Prefetch)
- حجم HTML أولي أصغر
- تحسينات في الإدخالات عند الطلب
- استماع أسرع للبوابة في وضع التطوير
- تصدير ثابت أسرع
- إزالة التكرار في عنصر الرأس
- خيار تكوين crossOrigin جديد
- إزالة جافاسكريبت المضمنة
- مثال على مصادقة API
كما هو الحال دائمًا، حرصنا على ضمان أن تكون كل هذه المزايا متوافقة تمامًا مع الإصدارات السابقة. بالنسبة لمعظم تطبيقات Next.js، كل ما تحتاجه هو تشغيل:
npm i next@latest react@latest react-dom@latest
نشكر مجتمعنا وكل من راهن على نجاحنا. منذ آخر منشور مدونة لدينا، رأينا شركات مثل AT&T، ستاربكس وتويش يعيدون إطلاق مواقعهم وتطبيقاتهم الموجهة للجمهور باستخدام Next.js.
Next.js بدون خادم (Serverless)
يُخرج هدف Next.js بدون خادم دوال Serverless من الصفحات
يُحسن النشر بدون خادم الموثوقية والقابلية للتوسع بشكل كبير عن طريق تقسيم تطبيقك إلى أجزاء أصغر (تُسمى أيضًا lambdas). في حالة Next.js، تصبح كل صفحة في دليل pages
دالة بدون خادم (lambda).
هناك عدد من الفوائد للنشر بدون خادم. الرابط المشار إليه يتحدث عن بعضها في سياق Express، لكن المبادئ تنطبق عالميًا: يسمح النشر بدون خادم بنقاط فشل موزعة، قابلية توسع لا نهائية، وهو في غاية التكلفة الفعالة مع نموذج "الدفع مقابل ما تستخدمه".
لتمكين وضع بدون خادم في Next.js، أضف هدف البناء serverless
في next.config.js
:
module.exports = {
target: 'serverless',
};
سيُخرج الهدف serverless
دالة lambda واحدة لكل صفحة. هذا الملف مستقل تمامًا ولا يحتاج إلى أي تبعيات لتشغيله:
pages/index.js
=>.next/serverless/pages/index.js
pages/about.js
=>.next/serverless/pages/about.js
توقيع دالة Next.js بدون خادم مشابه لرد اتصال خادم Node.js HTTP:
type Function = (req: http.IncomingMessage, res: http.ServerResponse) => void;
- http.IncomingMessage
- http.ServerResponse
- يشير
void
إلى أن الدالة ليس لها قيمة إرجاع وهي مكافئة لـundefined
في جافاسكريبت. استدعاء الدالة سينهي الطلب.
يوفر Next.js واجهات برمجة تطبيقات منخفضة المستوى للنشر بدون خادم حيث أن منصات الاستضافة لها توقيعات دالة مختلفة. بشكل عام سترغب في تغليف مخرجات بناء Next.js بدون خادم بطبقة توافق.
على سبيل المثال إذا كانت المنصة تدعم فئة http.Server في Node.js:
const http = require('http');
const page = require('./.next/serverless/about.js');
const server = new http.Server((req, res) => page.render(req, res));
server.listen(3000, () => console.log('Listening on http://localhost:3000'));
ملخص
- واجهة برمجة تطبيقات منخفضة المستوى لتنفيذ النشر بدون خادم
- كل صفحة في دليل
pages
تصبح دالة بدون خادم (lambda) - ينشئ أصغر دالة بدون خادم ممكنة (50 كيلوبايت حجم zip الأساسي)
- مُحسّن لبداية سريعة باردة للدالة
- الدالة بدون خادم ليس لها أي تبعيات (يتم تضمينها في حزمة الدالة)
- يستخدم http.IncomingMessage و http.ServerResponse من Node.js
- اختياري باستخدام
target: 'serverless'
فيnext.config.js
- لا يزال الهدف
server
مدعومًا بالكامل ومُحافظ عليه publicRuntimeConfig
وserverRuntimeConfig
غير مدعومين في وضعserverless
. استخدم تكوين وقت البناء بدلاً من ذلك.
تخفيض كبير في استخدام الذاكرة أثناء البناء
لقد ساهمنا في webpack لتحسين أداء بناء Next.js (وبقية نظام webpack البيئي!) واستخدام الموارد.
أدى هذا الجهد إلى تحسين استخدام الذاكرة حتى 16 مرة أفضل دون أي تدهور في الأداء.
يتم تحرير الذاكرة بشكل أسرع بكثير ولم تعد العمليات تتعطل تحت ضغط كبير (العديد من الصفحات).
سنناقش بالتفصيل كيف حققنا هذا التحسين قريبًا. تابع مدونة Next.js.
تكوين بيئة وقت البناء
أثناء مراجعة تطبيقات Next.js، لاحظنا نمطًا متكررًا يتمثل في إضافة babel-plugin-transform-define
أو webpack.DefinePlugin
لتوفير قيم التكوين للتطبيق.
مع Next.js 8 نقدم مفتاحًا جديدًا في next.config.js
باسم env
لتوفير نفس الوظيفة بطريقة متوافقة مع الإصدارات السابقة:
module.exports = {
env: {
customKey: 'MyValue',
},
};
سيسمح لك هذا باستخدام process.env.customKey
في الكود الخاص بك. على سبيل المثال:
export default function IndexPage() {
return <h1>The value of customKey is: {process.env.customKey}</h1>;
}
سيتم استبدال process.env.customKey
بـ 'MyValue'
في وقت البناء.
تحسينات في أداء الجلب المسبق (Prefetch)
يسمح موجه Next.js لك بجلب الصفحات مسبقًا لتنقل أسرع:
import Link from 'next/link';
export default function IndexPage() {
return (
<>
<Link href="/about" prefetch>
<a>To About Page</a>
</Link>
</>
);
}
يعمل ذلك عن طريق جلب حزمة جافاسكريبت لكل رابط يحتوي على سمة prefetch
مسبقًا.
في الإصدارات السابقة لـ Next.js 8 كان هذا يعني إدراج وسم <script>
في مستند <body>
.
ومع ذلك، أدى هذا إلى بعض الحمل الزائد أثناء فتح الصفحات، وأبرزها أن مؤشر "تحميل" المتصفح سيظهر لفترة أطول مما تتوقع حتى لو كانت الصفحة قابلة للتفاعل بالفعل.
في Next.js 8 يستخدم prefetch
<link rel="preload">
بدلاً من وسم <script>
. كما أنه يبدأ الجلب المسبق فقط بعد onload
للسماح للمتصفح بإدارة الموارد.
بالإضافة إلى ذلك، يكتشف Next.js الآن اتصال الإنترنت 2G ووضع navigator.connection.saveData
لتعطيل الجلب المسبق على اتصالات الشبكة البطيئة.
حجم HTML أولي أصغر
بما أن Next.js يعرض HTML مسبقًا، فإنه يلف الصفحات في بنية افتراضية مع <html>
، <head>
، <body>
وملفات جافاسكريبت اللازمة لعرض الصفحة.
مع Next.js 7 قمنا بتحسين الحمولة الأولية إلى 1.50 كيلوبايت، مما كان انخفاضًا بنسبة 7.4٪ من الإصدار السابق.
تمكنا من تقليل حجم الحمولة الأولية أكثر إلى 1.16 كيلوبايت بانخفاض إضافي بنسبة 23٪:
7.0 | 8.0 | الفرق | |
---|---|---|---|
حجم المستند (عرض الخادم) | 1.50 كيلوبايت | 1.16 كيلوبايت | 23% أصغر |
الطرق الرئيسية التي قللنا بها الحجم هي:
- تمت إزالة سكريبت التهيئة المضمن للصفحة
- لم يعد يتم تضمين صفحة
/_error
في كل تحميل للصفحة
تحميل عند الطلب لـ /_error
عندما يحدث خطأ في الإنتاج، يتم عرض صفحة /_error
لإظهار أن خطأً قد حدث.
منذ الإصدار الأول لـ Next.js، كانت وسم سكريبت صفحة /_error
جزءًا من HTML الأولي، مما يعني أنه تم تحميلها حتى لو لم يتم استخدامها في حالة عدم وجود أخطاء وقت التشغيل.
بدءًا من Next.js 8، يتم تحميل صفحة /_error
عند الطلب عند حدوث خطأ.
مما يعني وجود كود أقل ليتم تحميله وتحليله وتنفيذه افتراضيًا.
تحسينات تجربة المطور (DX)
أحد الأهداف الأساسية لـ Next.js هو توفير أفضل أداء للإنتاج مع أفضل تجربة ممكنة للمطور. يتضمن هذا الإصدار العديد من التحسينات الدقيقة بناءً على ملاحظات المستخدمين.
تحسينات في الإدخالات عند الطلب
بشكل افتراضي، يقوم Next.js بتجميع الصفحات التي يتم تطويرها بشكل فعّال فقط. لا يقوم Next.js بتجميع جميع الصفحات في دليل الصفحات في كل مرة يتم فيها تشغيل next dev
. بدلاً من ذلك، يقوم بتجميع الصفحات عند الوصول إليها.
على سبيل المثال، عند زيارة http://localhost:3000/my-page
، يتم تجميع ملف pages/my-page.js
عند الطلب، ثم يتم عرض الصفحة.
يضمن ذلك أن المطور لا يضطر إلى انتظار تجميع جميع الصفحات عند إطلاق خادم التطوير، مما قد يستغرق وقتًا طويلاً في التطبيقات الكبيرة. يحافظ على استخدام الذاكرة منخفضًا والمجمع سريعًا حيث لا يلزم أن يأخذ المجمع جميع الصفحات في الاعتبار عند التجميع.
تدفق الإدخالات عند الطلب
عندما لا يتم الوصول إلى صفحة لمدة 25 ثانية، سيتم التخلص منها من ذاكرة التخزين المؤقت للمجمع للحفاظ على سرعة المجمع وتقليل استخدام الذاكرة.
الطريقة التي يتتبع بها Next.js الصفحات التي يتم الوصول إليها هي باستخدام آلية استطلاع. كل 5 ثوانٍ، يتم إرسال "on-demand-entries-ping" لجعل خادم تطوير Next.js على علم بأنه يتم الوصول إلى صفحة معينة.
منذ الإصدار الأول لهذه الميزة، تم إجراء الاستطلاع باستخدام مكالمة window.fetch
، مما يعني أنه في كل مرة يتم تشغيل الاستطلاع، سيظهر في أدوات مطوري المتصفح في علامة التبويب console
و network
.
إحدى الميزات الأكثر طلبًا هي القدرة على إخفاء هذه الطلبات من أدوات مطوري المتصفح حيث يمكن أن تضيف هذه الطلبات ضوضاء غير ضرورية.
يسعدنا الإعلان أنه في Next.js 8، تم استبدال الاستطلاع القائم على fetch
بنهج قائم على WebSockets، مما يعني أن الاستطلاعات لا تزال تحدث ولكنها مرئية فقط عند فحص اتصال WebSocket.
شكر خاص لـ JJ Kasper للتعاون في التحويل إلى WebSockets.
استماع أسرع للبوابة في وضع التطوير
عند بدء خادم تطوير Next.js، يجب عليه تشغيل بعض التجميع الأولي لتكون قادرًا على خدمة الطلبات، افتراضيًا، كان Next.js ينتظر انتهاء خطوة التجميع هذه قبل بدء خادم HTTP، مما يعني أنه إذا قمت بتشغيل next dev
ثم ذهبت إلى متصفحك، فقد يحدث أحيانًا أن تحصل على رسالة "لا يمكن الوصول إلى هذا الموقع" لأن خادم HTTP لم يكن يستمع للاتصالات بعد.
مع Next.js 8، سيكون خادم HTTP يستمع للاتصالات قبل بدء التجميع، مما يعني أنه إذا ذهبت إلى http://localhost:3000/
قبل انتهاء التجميع، سينتظر الطلب انتهاء التجميع الأولي قبل تقديم الطلب، بدلاً من الحاجة إلى تحديث الصفحة حتى تصبح متاحة.
شكر خاص لـ Brian Beck لتنفيذ هذه الميزة.
تصدير ثابت أسرع
يركز Next.js على فكرة العرض المسبق كوسيلة لتحقيق أداء عالٍ. يأتي العرض المسبق في شكلين:
- عرض الخادم حيث يؤدي كل طلب إلى عرض. نتيجة لذلك، لا يتعين على المستخدم النهائي الانتظار لتنزيل أي JS لبدء استهلاك البيانات
- العرض الثابت حيث نخرج ملفات ثابتة يمكن تقديمها مباشرة دون أي تنفيذ للكود على الخادم
بدءًا من Next.js 8، سيكون لعرض الثابت من خلال next export
تحسينات في السرعة إذا كان جهازك يحتوي على وحدات معالجة مركزية متعددة.
بناءً على الاختبارات باستخدام جهاز MacBook ب4 نوى معالجة مركزية، زادت سرعة التصدير من حوالي 25 صفحة في الثانية إلى 75 صفحة في الثانية عن طريق الاستفادة من جميع النوى لعرض الصفحات مسبقًا.
سيكتشف Next.js تلقائيًا عدد نوى وحدة المعالجة المركزية ويوزع الصفحات وفقًا لذلك، لا حاجة لأي تغييرات في الكود.
شكر خاص لـ Benjamin Kniffler لتنفيذ هذه الميزة.
إزالة التكرار في عنصر الرأس
الحاجة الشائعة عند بناء التطبيقات هي تحديث عنصر <head>
للصفحة. على سبيل المثال لتعيين <title>
أو <meta name="viewport">
للتصميم المتجاوب.
يكشف Next.js عن مكون مدمج لإدخال تغييرات على <head>
:
import Head from 'next/head';
export default function IndexPage() {
return (
<>
<Head>
<title>عنوان صفحتي</title>
</Head>
</>
);
}
يمكن حتى استخدام مكون <Head>
عدة مرات في مكونات مختلفة، على سبيل المثال يمكن لمكون التخطيط الخاص بك تعيين بعض وسوم الرأس الافتراضية.
ومع ذلك، قد ترغب في تجاوز وسوم الرأس الافتراضية بقيمة مختلفة، في الإصدارات القديمة من Next.js، سيؤدي هذا إلى تكرار الوسم في المخرجات، حيث لم تكن هناك طريقة لإزالة التكرار من الوسوم.
لهذا السبب، أصبح من الممكن الآن توفير خاصية key
لكل عنصر داخل مكون <Head>
والتي ستزيل تلقائيًا الوسوم بنفس قيمة key
.
عند تعيين key="viewport"
على وسمين، يتم عرض الأخير فقط.
import Head from 'next/head';
export default function IndexPage() {
return (
<>
<Head>
<title>عنوان صفحتي</title>
<meta
name="viewport"
content="initial-scale=1.0, width=device-width"
key="viewport"
/>
</Head>
<Head>
<meta
name="viewport"
content="initial-scale=1.2, width=device-width"
key="viewport"
/>
</Head>
</>
);
}
تحسينات الأمان
خيار تكوين crossOrigin
جديد
في Next.js 6 قدمنا خيار إضافة سمة crossOrigin
إلى <Head>
و <NextScript>
في pages/_document.js
، لكن هذا لم يغطي جميع حالات الاستخدام لتعيين cross-origin
.
لدى Next.js موجه جانب العميل يحقن وسوم <script>
ديناميكيًا، كانت هذه الوسوم تفتقد إلى سمة cross-origin
عند الحقن.
لضمان أن جميع وسوم <script>
تحتوي على cross-origin
، قدمنا خيار تكوين جديد في next.config.js
module.exports = {
crossOrigin: 'anonymous',
};
فائدة أخرى لإدخال هذا الخيار هي أن pages/_document.js
مخصص لم يعد ضروريًا لإعداد cross-origin
في تطبيقك.
لا يزال السلوك السابق مدعومًا ولكنه سيصدر تحذيرًا في التطوير لمساعدة المطورين في الانتقال إلى الخيار الجديد.
إزالة جافاسكريبت المضمنة (Removed inline Javascript)
عند استخدام Next.js 7 والإصدارات الأقدم، لتمكين سياسة أمان المحتوى (CSP)، كان على المستخدم تضمين script-src 'unsafe-inline'
في سياسته لأن Next.js كان ينشئ علامة <script>
مضمنة لنقل البيانات، على سبيل المثال، لنقل نتيجة getInitialProps
إلى جانب العميل.
مع Next.js 8 قمنا بتغيير علامة السكريبت المضمنة هذه إلى علامة JSON لنقل آمن إلى العميل. هذا يعني أنه لم تعد هناك نصوص برمجية مضمنة مقدمة من Next.js.
مع النظر بعناية يمكن الآن استخدام script-src 'self'
.
مثال على مصادقة واجهة برمجة التطبيقات (API Authentication)
واحد من أكثر الأمثلة المطلوبة على الإطلاق كان كيفية تنفيذ المصادقة في Next.js ضد واجهة برمجة تطبيقات خارجية، أي واجهة برمجة تطبيقات، بأي لغة برمجة.
مع إطلاق Next.js 8، نقدم أيضًا مثالًا جديدًا: with-cookie-auth
هذا المثال يوضح كيفية المصادقة ضد واجهة برمجة تطبيقات Node.js خارجية، ولكن المفاهيم المطبقة تعمل مع أي واجهة برمجة تطبيقات عديمة الحالة (stateless).
يستخدم المثال ملف تعريف الارتباط (cookie) لمشاركة الرمز المميز (token) بين العرض من جانب الخادم (server-side) والعرض من جانب العميل (client-side).
وبهذه الطريقة إذا تم عرض التطبيق على الخادم، يمكنه仍然 جلب البيانات المصادق عليها نيابة عن المستخدم.
شكر خاص لـ Juan Olvera الذي ساهم بالمثال.
المجتمع (Community)
منذ إطلاقه الأول، تم استخدام Next.js في كل شيء من شركات Fortune 500 إلى المدونات الشخصية. نحن متحمسون جدًا لرؤية النمو المستمر في اعتماد Next.js.
- لدينا أكثر من 600 مساهم قاموا بإرسال commit واحد على الأقل.
- على GitHub، حصل المشروع على أكثر من 34,400 نجمة.
- تم تقديم أكثر من 2600 طلب سحب (pull request) منذ الإصدار الأول.
يضم مجتمع Next.js أكثر من 4,570 عضوًا. انضم إلينا!