איך Webpack עוזר לשמור נכסים במטמון
הדבר הבא (אחרי אופטימיזציה של גודל האפליקציה) משפר את זמן הטעינה של האפליקציה שנשמר במטמון. אפשר להשתמש בו כדי להשאיר חלקים מהאפליקציה ולהימנע מהורדה מחדש שלהם בכל פעם.
שימוש בניהול גרסאות של חבילות ובכותרות של מטמון
הגישה הנפוצה של שמירה במטמון היא:
אומרים לדפדפן לשמור קובץ למשך זמן רב מאוד (למשל, שנה):
# Server header Cache-Control: max-age=31536000
אם לא ידוע לך מה
Cache-Control
עושה, אפשר לעיין במאמר פרסום מצוין בשמירה במטמון שיטות.ולשנות את שם הקובץ לאחר השינוי כדי לאלץ את ההורדה מחדש:
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
הגישה הזו מנחה את הדפדפן להוריד את קובץ ה-JS, לשמור אותו במטמון ולהשתמש ברכיב עותק שנשמר במטמון. הדפדפן יתחבר לרשת רק אם שם הקובץ משתנה (או אם חולפת שנה).
ב-webpack עושים את אותו הדבר, אבל במקום מספר הגרסה מציינים את
לבצע גיבוב (hash) של קובץ. כדי לכלול את הגיבוב בשם הקובץ, משתמשים ב-
[chunkhash]
:
// webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.[chunkhash].js' // → bundle.8e0d62a03.js
}
};
אם אתם צריכים
שם הקובץ כדי לשלוח אותו ללקוח, יש להשתמש ב-HtmlWebpackPlugin
או
WebpackManifestPlugin
.
HtmlWebpackPlugin
הוא
פשוטה יותר, אבל פחות גמישה. במהלך ההידור, הפלאגין הזה יוצר
קובץ HTML שכולל את כל המשאבים שעברו הידור. אם לוגיקת השרת שלכם לא
הוא מורכב, הוא אמור להספיק לכם:
<!-- index.html -->
<!DOCTYPE html>
<!-- ... -->
<script src="bundle.8e0d62a03.js"></script>
WebpackManifestPlugin
היא גישה גמישה יותר שמועילה אם יש לכם חלק מורכב בשרת.
במהלך ה-build, היא יוצרת קובץ JSON עם מיפוי בין שמות הקבצים
בלי גיבוב (hash) ושמות קבצים עם גיבוב. משתמשים בקובץ ה-JSON הזה בשרת כדי לגלות
עם איזה קובץ לעבוד:
// manifest.json
{
"bundle.js": "bundle.8e0d62a03.js"
}
קריאה נוספת
- ג'ייק ארצ'יבלד על שמירה במטמון בצורה הטובה ביותר שיטות
חילוץ יחסי תלות וזמן ריצה לקובץ נפרד
יחסי תלות
יחסי התלות של אפליקציות משתנים בדרך כלל בתדירות נמוכה יותר מקוד האפליקציה בפועל. אם עוברים דירה בקובץ נפרד, הדפדפן יוכל לשמור אותם במטמון בנפרד – ולא תוריד אותם מחדש בכל פעם שקוד האפליקציה ישתנה.
כדי לחלץ את יחסי התלות למקטע נפרד, מבצעים שלושה שלבים:
מחליפים את שם קובץ הפלט ב-
[name].[chunkname].js
:// webpack.config.js module.exports = { output: { // Before filename: 'bundle.[chunkhash].js', // After filename: '[name].[chunkhash].js' } };
כשאפליקציית Webpack יוצרת את האפליקציה, היא מחליפה את
[name]
עם שם של מקטע. אם לא נוסיף את החלק של[name]
, נוסיף להבחין בין מקטעים באמצעות הגיבוב שלהם – זה די קשה!ממירים את השדה
entry
לאובייקט:// webpack.config.js module.exports = { // Before entry: './index.js', // After entry: { main: './index.js' } };
בקטע הקוד הזה, "main" הוא שם של מקטע. השם הזה יוחלף ב המקום
[name]
משלב 1.בשלב זה, אם אתם בונים את האפליקציה, המקטע הזה יכלול את כל קוד האפליקציה – כמו שלא עשינו את השלבים האלה. אבל זה ישתנה תוך זמן קצר.
ב-webpack 4, מוסיפים את האפשרות
optimization.splitChunks.chunks: 'all'
בהגדרת ה-webpack:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
האפשרות הזו מפעילה פיצול קוד חכם. באמצעותו, Webpack יחלץ את קוד הספק אם הוא גדול מ-30kB (לפני ההקטנה ו-gzip). הוא גם מחלץ את הקוד המשותף - האפשרות הזו שימושית אם ה-build שלכם מייצר כמה חבילות (למשל, אם מפצלים את האפליקציה למסלולים).
ב-webpack 3, מוסיפים את
CommonsChunkPlugin
:// webpack.config.js (for webpack 3) module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin({ // A name of the chunk that will include the dependencies. // This name is substituted in place of [name] from step 1 name: 'vendor', // A function that determines which modules to include into this chunk minChunks: module => module.context && module.context.includes('node_modules'), }) ] };
הפלאגין הזה משתמש בכל המודולים שכוללים את
node_modules
ו- מעביר אותן לקובץ נפרד בשםvendor.[chunkhash].js
.
אחרי השינויים האלה, כל build ייצור שני קבצים במקום אחד: main.[chunkhash].js
ו
vendor.[chunkhash].js
(vendors~main.[chunkhash].js
ל-webpack 4). במקרה של Webpack 4,
יכול להיות שחבילת הספקים לא תיווצר אם יחסי התלות קטנים – וזה בסדר:
$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
Asset Size Chunks Chunk Names
./main.00bab6fd3100008a42b0.js 82 kB 0 [emitted] main
./vendor.d9e134771799ecdf9483.js 47 kB 1 [emitted] vendor
הדפדפן ישמור את הקבצים האלה במטמון בנפרד, ויוריד מחדש רק את הקוד שמשתנה.
קוד זמן ריצה של Webpack
לצערי, לא מספיק לחלץ את קוד הספק בלבד. אם תנסה משנים משהו בקוד האפליקציה:
// index.js
…
…
// E.g. add this:
console.log('Wat');
תוכלו לראות שהגיבוב (hash) vendor
גם ישתנה:
Asset Size Chunks Chunk Names
./vendor.d9e134771799ecdf9483.js 47 kB 1 [emitted] vendor
↓
Asset Size Chunks Chunk Names
./vendor.e6ea4504d61a1cc1c60b.js 47 kB 1 [emitted] vendor
הסיבה לכך היא שבחבילת ה-webpack, חוץ מקוד המודולים, יש סביבת זמן ריצה – קטע קוד קטן שמנהל את הפעלת המודול. כשמפצלים את הקוד לכמה קבצים, קטע הקוד הזה מתחיל לכלול מיפוי בין מזהי מקטעי נתונים הקבצים התואמים:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
ה-Webpack כולל את זמן הריצה הזה במקטע האחרון שנוצר: vendor
במקרה שלנו. בכל פעם שמקטע משתנה, גם קטע הקוד הזה משתנה,
וגורמת לשינוי בכל המקטע של vendor
.
כדי לפתור את הבעיה, נעביר את סביבת זמן הריצה לקובץ נפרד. ב-webpack 4:
באמצעות הפעלת האפשרות optimization.runtimeChunk
:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
runtimeChunk: true
}
};
ב-webpack 3 יוצרים מקטע ריק נוסף עם CommonsChunkPlugin
:
// webpack.config.js (for webpack 3)
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => module.context && module.context.includes('node_modules')
}),
// This plugin must come after the vendor one (because webpack
// includes runtime into the last chunk)
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
// minChunks: Infinity means that no app modules
// will be included into this chunk
minChunks: Infinity
})
]
};
אחרי השינויים האלה, כל build ייצור שלושה קבצים:
$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
Asset Size Chunks Chunk Names
./main.00bab6fd3100008a42b0.js 82 kB 0 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 1 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
כוללים אותם ב-index.html
בסדר הפוך – וזהו:
<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
<script src="./vendor.26886caf15818fa82dfa.js"></script>
<script src="./main.00bab6fd3100008a42b0.js"></script>
קריאה נוספת
- מדריך בנושא חבילת אינטרנט לשמירה במטמון לטווח ארוך
- מסמכי Webpack על סביבת זמן ריצה של חבילת אינטרנט מניפסט
- "להפיק את המרב CommonsChunkPlugin"
- איך פועלים
optimization.splitChunks
ו-optimization.runtimeChunk
זמן ריצה מוטבע של webpack כדי לשמור בקשת HTTP נוספת
כדי לשפר את השירות, כדאי לנסות להטביע את זמן הריצה של ה-webpack ב-HTML תשובה. כלומר, במקום זאת:
<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
עושים זאת:
<!-- index.html -->
<script>
!function(e){function n(r){if(t[r])return t[r].exports;…}} ([]);
</script>
סביבת זמן הריצה קטנה, והוספה של בקשת ה-HTTP תעזור לך לשמור בקשת HTTP. חשוב עם HTTP/1; פחות חשוב עם HTTP/2 אבל עדיין עשוי להפעיל ).
כך עושים את זה.
אם יוצרים קוד HTML באמצעות ה-HtmlWebpackPlugin
אם משתמשים HtmlWebpackPlugin כדי ליצור בקובץ HTML, InlineSourcePlugin הוא כל מה שצריך:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
inlineSource: 'runtime~.+\\.js',
}),
new InlineSourcePlugin()
]
};
אם יוצרים HTML באמצעות לוגיקת שרת מותאמת אישית
באמצעות Webpack 4:
מוסיפים את
WebpackManifestPlugin
כדי לדעת את השם שנוצר למקטע סביבת זמן הריצה:// webpack.config.js (for webpack 4) const ManifestPlugin = require('webpack-manifest-plugin'); module.exports = { plugins: [ new ManifestPlugin() ] };
build עם הפלאגין הזה ייצור קובץ שנראה כך:
// manifest.json { "runtime~main.js": "runtime~main.8e0d62a03.js" }
בתוך שורה נוחה, התוכן של מקטע סביבת זמן הריצה צריך להיות מוטמע. לדוגמה עם Node.js ו-Express:
// server.js const fs = require('fs'); const manifest = require('./manifest.json'); const runtimeContent = fs.readFileSync(manifest['runtime~main.js'], 'utf-8'); app.get('/', (req, res) => { res.send(` … <script>${runtimeContent}</script> … `); });
או באמצעות webpack 3:
כדי שהשם של סביבת זמן הריצה יהיה סטטי, מציינים את הערך
filename
:module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'runtime', minChunks: Infinity, filename: 'runtime.js' }) ] };
יש בתוך השורה את התוכן ב-
runtime.js
בצורה נוחה. לדוגמה עם Node.js ו-Express:// server.js const fs = require('fs'); const runtimeContent = fs.readFileSync('./runtime.js', 'utf-8'); app.get('/', (req, res) => { res.send(` … <script>${runtimeContent}</script> … `); });
טעינה מדורגת של קוד שלא צריך כרגע
לפעמים דף כולל חלקים חשובים יותר ופחות חשובים:
- אם אתם טוענים דף של סרטון ב-YouTube, הסרטון חשוב לכם יותר מאשר תגובות. כאן, הסרטון חשוב יותר מהתגובות.
- אם אתם פותחים מאמר באתר חדשות, אכפת לכם יותר מהטקסט של מאשר על מודעות. כאן, הטקסט חשוב יותר ממודעות.
במקרים כאלה, כדי לשפר את ביצועי הטעינה הראשונית, צריך להוריד רק
את הדברים החשובים ביותר תחילה, וטעינה מדורגת של החלקים הנותרים מאוחר יותר. אפשר להשתמש ב
הפונקציה import()
וגם
code-splitting בשיטה הזו:
// videoPlayer.js
export function renderVideoPlayer() { … }
// comments.js
export function renderComments() { … }
// index.js
import {renderVideoPlayer} from './videoPlayer';
renderVideoPlayer();
// …Custom event listener
onShowCommentsClick(() => {
import('./comments').then((comments) => {
comments.renderComments();
});
});
import()
מציין שרוצים לטעון מודול ספציפי באופן דינמי. מתי
Webpack רואה את import('./module.js')
, הוא מעביר את המודול הזה
chunk:
$ webpack
Hash: 39b2a53cb4e73f0dc5b2
Version: webpack 3.8.1
Time: 4273ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./main.f7e53d8e13e9a2745d6d.js 60 kB 1 [emitted] main
./vendor.4f14b6326a80f4752a98.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
ומוריד אותה רק כשהביצוע מגיע לפונקציה import()
.
הפעולה הזו תקטין את החבילה main
, וכך תשפר את זמן הטעינה הראשונית.
אפילו יותר מכך, השמירה במטמון תשפר – אם תשנו את הקוד במקטע הראשי,
שמקטע התגובות לא יושפע.
קריאה נוספת
- מסמכי Webpack עבור
import()
פונקציה - הצעת JavaScript ליישום של
import()
תחביר
פיצול הקוד לנתיבים ולדפים
אם לאפליקציה יש כמה מסלולים או דפים, אבל יש רק קובץ JS אחד עם
את הקוד (מקטע main
יחיד), סביר להניח שאתם מציגים בייטים נוספים
בכל בקשה. לדוגמה, כשמשתמש מבקר בדף הבית של האתר:
הוא לא צריך לטעון את הקוד כדי לעבד מאמר שנמצא אבל הם יטען אותו. בנוסף, אם המשתמש תמיד מבקר רק בבית ואתם מבצעים שינוי בקוד המאמר, ה-webpack יבטל את התוקף של את כל החבילה – והמשתמש יצטרך להוריד מחדש את האפליקציה כולה.
אם פיצלנו את האפליקציה לדפים (או למסלולים, אם זו אפליקציה עם דף אחד), המשתמש יוריד רק את הקוד הרלוונטי. בנוסף, הדפדפן ישמור במטמון את קוד האפליקציה טוב יותר: אם משנים את הקוד של דף הבית, ה-webpack יבטל רק את התוקף של של המקטע התואם.
לאפליקציות בדף יחיד
כדי לפצל אפליקציות בדף יחיד לפי מסלולים, צריך להשתמש ב-import()
(מידע נוסף זמין בקטע "קוד טעינה מדורגת"
שאתם לא צריכים כרגע"). אם אתם משתמשים ב-framework,
יכול להיות שיש לו פתרון קיים:
- "קוד
פיצול"
במסמכים של
react-router
(לתגובה) - "טעינה מושהית
"מסלולים" ב-
המסמכים של
vue-router
(ל-Vue.js)
לאפליקציות מסורתיות עם דפים מרובים
כדי לפצל אפליקציות מסורתיות לפי דפים, משתמשים בערך של webpack נקודות. אם לאפליקציה יש שלושה סוגי דפים: דף הבית, דף המאמר ודף חשבון המשתמש, צריכות להיות שלוש רשומות:
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
עבור כל קובץ רשומה, Webpack יבנה עץ תלות נפרד ויייצר חבילה שכוללת רק מודולים שנעשה בהם שימוש באותה רשומה:
$ webpack
Hash: 318d7b8490a7382bf23b
Version: webpack 3.8.1
Time: 4273ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./home.91b9ed27366fe7e33d6a.js 18 kB 1 [emitted] home
./article.87a128755b16ac3294fd.js 32 kB 2 [emitted] article
./profile.de945dc02685f6166781.js 24 kB 3 [emitted] profile
./vendor.4f14b6326a80f4752a98.js 46 kB 4 [emitted] vendor
./runtime.318d7b8490a7382bf23b.js 1.45 kB 5 [emitted] runtime
לכן, אם רק דף המאמר משתמש ב-Lodash, החבילות home
ו-profile
לא תכלול אותה, והמשתמש לא יצטרך להוריד את הספרייה הזו כאשר
נכנסים לדף הבית.
עם זאת, לעצי תלות נפרדים יש חסרונות. אם נעשה שימוש בשתי נקודות כניסה
Lodash, ולא העברת את יחסי התלות שלך לחבילת ספקים,
המקומות האלה יכללו עותק של Lodash. כדי לפתור את הבעיה, ב-webpack 4 מוסיפים את
את האפשרות optimization.splitChunks.chunks: 'all'
בהגדרת חבילת האינטרנט:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
האפשרות הזו מפעילה פיצול קוד חכם. אם תבחרו באפשרות הזו, ה-webpack יתבצע באופן אוטומטי לחפש קוד נפוץ ולחלץ אותו לקבצים נפרדים.
לחלופין, ב-webpack 3,משתמשים ברכיב CommonsChunkPlugin
– הוא יעביר יחסי תלות נפוצים לקובץ חדש שצוין:
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2 // 2 is the default value
})
]
};
אפשר לשחק עם הערך של minChunks
כדי למצוא את המשחק הטוב ביותר. באופן כללי,
מומלץ לשמור על גודל קטן, אבל להגדיל אם מספר המקטעים יגדל. עבור
לדוגמה, עבור 3 מקטעים, minChunks
יכול להיות 2, אבל עבור 30 מקטעים, הוא יכול להיות 8
– כי אם תשאירו את הערך 2, יותר מדי מודולים ייכנסו לקובץ המשותף,
ניפוח יותר מדי.
קריאה נוספת
- מסמכי Webpack על הקונספט של כניסה נקודות
- מסמכי תיעוד בנושא חבילות אינטרנט CommonsChunkPlugin
- "להפיק את המרב CommonsChunkPlugin"
- איך פועלים
optimization.splitChunks
ו-optimization.runtimeChunk
שיפור מזהי המודולים
במהלך יצירת הקוד, ה-webpack מקצה לכל מודול מזהה. לאחר מכן, המזהים האלה
יהיה בשימוש ב-require()
שניות בתוך החבילה. בדרך כלל המזהים מוצגים בפלט ה-build
ממש לפני נתיבי המודול:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./main.4e50a16675574df6a9e9.js 60 kB 1 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
↓ כאן
[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
[4] ./comments.js 58 kB {0} [built]
[5] ./ads.js 74 kB {1} [built]
+ 1 hidden module
כברירת מחדל, המזהים מחושבים באמצעות מונה (כלומר, במודול הראשון יש את המזהה 0, לסרטון השני יש מזהה 1, וכן הלאה). הבעיה היא שכשמוסיפים מודול חדש, הוא עשוי להופיע באמצע רשימת המודולים ומשנה את כל 'המודולים הבאים' מזהים:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.5c82c0f337fcb22672b5.js 22 kB 0 [emitted]
./main.0c8b617dfc40c2827ae3.js 82 kB 1 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
↓ הוספנו מודול...
[4] ./webPlayer.js 24 kB {1} [built]
↓ וראו מה הוא עשה! למשתמש comments.js
יש עכשיו מזהה 5 במקום 4
[5] ./comments.js 58 kB {0} [built]
↓ ל-ads.js
יש עכשיו מזהה 6 במקום 5
[6] ./ads.js 74 kB {1} [built]
+ 1 hidden module
הפעולה הזו תבטל את כל המקטעים שכוללים מודולים עם מזהים שהשתנו או שתלויים בהם.
גם אם הקוד שלהם בפועל לא השתנה. במקרה שלנו, המקטע 0
(המקטע
עם comments.js
) והמקטע main
(המקטע עם קוד האפליקציה האחר) מקבל
בוטלה – אבל רק main
הייתה צריכה להיות.
כדי לפתור את הבעיה, משנים את אופן החישוב של מזהי המודולים באמצעות
HashedModuleIdsPlugin
היא מחליפה מזהים המבוססים על מונה בגיבובים של נתיבי מודולים:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.6168aaac8461862eab7a.js 22.5 kB 0 [emitted]
./main.a2e49a279552980e3b91.js 60 kB 1 [emitted] main
./vendor.ff9f7ea865884e6a84c8.js 46 kB 2 [emitted] vendor
./runtime.25f5d0204e4f77fa57a1.js 1.45 kB 3 [emitted] runtime
↓ כאן
[3IRH] ./index.js 29 kB {1} [built]
[DuR2] (webpack)/buildin/global.js 488 bytes {2} [built]
[JkW7] (webpack)/buildin/module.js 495 bytes {2} [built]
[LbCc] ./webPlayer.js 24 kB {1} [built]
[lebJ] ./comments.js 58 kB {0} [built]
[02Tr] ./ads.js 74 kB {1} [built]
+ 1 hidden module
בגישה זו, המזהה של מודול משתנה רק אם משנים את השם או מעבירים אותו של מודל טרנספורמר. מודולים חדשים לא ישפיעו על מודולים אחרים המזהים.
כדי להפעיל את הפלאגין, מוסיפים אותו לקטע plugins
בהגדרות האישיות:
// webpack.config.js
module.exports = {
plugins: [
new webpack.HashedModuleIdsPlugin()
]
};
קריאה נוספת
- מסמכי תיעוד בנושא חבילות אינטרנט HashedModuleIdsPlugin
סיכום
- שמירת החבילה במטמון והבחנה בין הגרסאות באמצעות שינוי שם החבילה
- מפצלים את החבילה לקוד האפליקציה, לקוד ספק ולזמן ריצה
- בתוך השורה של סביבת זמן הריצה לשמירת בקשת HTTP
- טעינה מדורגת של קוד לא קריטי באמצעות
import
- צריך לפצל את הקוד לפי מסלולים או דפים כדי למנוע טעינה של דברים מיותרים