טיפ נקסט: שימו לב ל import-ים
ב next.js בגירסה ה Page Router יש לנו שלוש אפשרויות לטעון ספריות חיצוניות, ואני חושש שההבדל ביניהן לא תמיד מספיק ברור.
1. שימוש בספריה חיצונית בקובץ נפרד
דרך ראשונה היא לקרוא ל import מתוך קובץ של Page, לדוגמה בפרויקט next חדש אני כותב בקובץ index.tsx את הקוד הבא:
import _ from 'lodash';
import moment from 'moment';
// export const getServerSideProps = (async () => {
// const _ = (await import('lodash')).default;
// return { props: { name: foo(), number: _.random(100) } }
// });
export default function Home(props: any) {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div
className={`${styles.page} ${geistSans.variable} ${geistMono.variable}`}
>
<main className={styles.main}>
<p>Hello {_.head([1, 2, 3])}</p>
<p>{moment("20111031", "YYYYMMDD").fromNow()}</p>
</main>
</div>
</>
);
}
בבנייה של הקוד עם npm run build אני מקבל בתיקיית chunks את:
$ ls -1 .next/static/chunks
29107295-e679c2f4ae05922d.js
75fc9c18-25d3a9414ec027b7.js
framework-88d0cc4abe8a5763.js
main-22f485a16e76a198.js
pages
polyfills-42372ed130431b0a.js
webpack-69db33922baa0ba7.js
שימו לב לשני הקבצים ששמותיהם הם מספרים, אלה הספריות lodash ו moment. הם נכנסו לפרויקט בתור קבצים נפרדים, וזה נחמד כי דפדפן יכול לשמור כל אחד מהם בנפרד ב cache, ולטעון אותם רק מהדפים שבאמת צריכים אותם.
2. שימוש בספריה חיצונית מתוך app
בפרויקט next יש גם קובץ כללי בשם _app.tsx
. ספריות שאנחנו טוענים ממנו יאוחדו לקובץ אחד שייטען בכל אחד מהדפים ביישום. אני מחזיר את index.tsx למצבו ההתחלתי ומעדכן הפעם את _app.tsx
לתוכן הבא:
import "@/styles/globals.css";
import type { AppProps } from "next/app";
import _ from 'lodash';
import moment from 'moment';
export default function App({ Component, pageProps }: AppProps) {
return <div>
<p>Hello {_.head([1, 2, 3])}</p>
<p>{moment("20111031", "YYYYMMDD").fromNow()}</p>
<Component {...pageProps} />;
</div>
}
מבחינת העמוד דברים נראים אותו דבר יש לי את אותם טקסטים בדיוק (כן במקום אחר אבל זה לא חשוב כרגע), אבל מה שכן חשוב זה ה JavaScript שנוצר:
$ ls -l .next/static/chunks
total 816
-rw-r--r-- 1 ynonp staff 181258 נוב 4 19:42 framework-88d0cc4abe8a5763.js
-rw-r--r-- 1 ynonp staff 113610 נוב 4 19:42 main-22f485a16e76a198.js
drwxr-xr-x 5 ynonp staff 160 נוב 4 19:42 pages
-rw-r--r-- 1 ynonp staff 112594 נוב 4 19:42 polyfills-42372ed130431b0a.js
-rw-r--r-- 1 ynonp staff 1553 נוב 4 19:42 webpack-69db33922baa0ba7.js
הפעם אין צ'אנקים עבור הספריות החיצוניות ובמקומים בתוך תיקיית pages אני מקבל:
$ ls -l .next/static/chunks/pages
total 272
-rw-r--r-- 1 ynonp staff 129509 נוב 4 19:42 _app-852f41acee199ae3.js
-rw-r--r-- 1 ynonp staff 232 נוב 4 19:42 _error-8c2b6ff87cd513a2.js
-rw-r--r-- 1 ynonp staff 1385 נוב 4 19:42 index-de2181fd4b2adca1.js
כלומר קובץ אחד בשם _app-852f41acee199ae3.js
שמכיל את שתי הספריות. הקובץ הזה ייטען בכל אחד מהדפים ביישום ודפדפן לא יוכל לשמור אותו ב cache, כי כל שינוי באחד המרכיבים שלו יגרום ליצירה מחדש של כל הקובץ.
3. שימוש בספריה חיצונית רק מתוך קוד צד שרת
אופציה שלישית היא לטעון את הספריה החיצונית ולהשתמש בה רק בפונקציה getServerSideProps
מתוך אחד הדפים. אני מחזיר את _app.tsx
לצורתו המקורית וחוזר ל index.tsx
ועכשיו זה יהיה תוכנו:
import _ from 'lodash';
import moment from 'moment';
export const getServerSideProps = (async () => {
return {
props: {
one: _.head([1, 2, 3]),
two: moment("20111031", "YYYYMMDD").fromNow(),
}
}
});
export default function Home(props: any) {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div
className={`${styles.page} ${geistSans.variable} ${geistMono.variable}`}
>
<main className={styles.main}>
<p>{props.one}</p>
<p>{props.two}</p>
</main>
</div>
</>
);
}
הפעם אלה הצ'אנקים שנוצרו בבנייה:
ynonp@Ynons-MacBook-Air ~/tmp/perf (main*?) $ ls -l .next/static/chunks
total 816
-rw-r--r-- 1 ynonp staff 181258 נוב 4 19:46 framework-88d0cc4abe8a5763.js
-rw-r--r-- 1 ynonp staff 113610 נוב 4 19:46 main-22f485a16e76a198.js
drwxr-xr-x 5 ynonp staff 160 נוב 4 19:46 pages
-rw-r--r-- 1 ynonp staff 112594 נוב 4 19:46 polyfills-42372ed130431b0a.js
-rw-r--r-- 1 ynonp staff 1459 נוב 4 19:46 webpack-59041051e025bed2.js
ynonp@Ynons-MacBook-Air ~/tmp/perf (main*?) $ ls -l .next/static/chunks/pages
total 24
-rw-r--r-- 1 ynonp staff 400 נוב 4 19:46 _app-f45d290ef4eb0435.js
-rw-r--r-- 1 ynonp staff 232 נוב 4 19:46 _error-8c2b6ff87cd513a2.js
-rw-r--r-- 1 ynonp staff 1480 נוב 4 19:46 index-f051a589b07bc05e.js
הפעם אף קובץ בתיקיית chunks לא כולל את ספריית moment או את ספריית lodash. ספריות אלה נטענות ונמצאות בשימוש רק בצד השרת, והגודל הכולל של כל ה JavaScript שנשלח לדפדפן הוא כ 20% פחות.
שורה תחתונה בעבודה עם next גם בגירסת ה Pages Router אנחנו יכולים להוריד משמעותית את כמות ה JavaScript שנשלחת לדפדפן באמצעות העברת הקוד לצד שרת, או להשתמש נכון יותר ב Cache באמצעות העברת הספריות לקבצים של הדפים. הקובץ app צריך להיות ממש המוצא האחרון כיוון שקוד שאני כותב בו יישלח לכל הדפים במרוכז.