הוספת Babel לפרויקט Webpack
כמו שראיתם בפוסט הקודם בסידרה אנחנו יכולים להשתמש ב Webpack כדי להפוך את הקוד שלנו להרבה יותר קל לתחזוקה - במקום להשתמש ב HTML כדי לטעון קבצי JavaScript, באמצעות וובפאק אנחנו טוענים קבצי JavaScript מתוך קבצי JavaScript וכך הופכים את סדר התלויות בין הקבצים למפורש.
וזה נחמד והכל אבל יכול להיות הרבה יותר טוב: כי אם וובפאק כבר רץ על כל הקבצים שלי, למה שלא ישכתב אותם קצת כדי שיעבדו ביותר דפדפנים? כי למרות שבתור מתכנתים אנחנו משתמשים בדפדפן הכי חדש ובטוחים שגם כל המשתמשים שלנו ככה, המציאות היא שמשתמשים לא תמיד בוחרים את הכלים שלכם ויש הרבה מהם שלא שידרגו מערכת הפעלה כבר שנים.
1. מהו Babel
בעולם ה JavaScript פיצ'רים חדשים נכנסים לשפה כל הזמן, וגירסאות חדשות של דפדפנים יוצאות כל הזמן כדי לתמוך בפיצ'רים החדשים האלה, אבל עדיין אין לנו דרך להכריח את כל האנשים להתקין את הגירסאות הכי חדשות של כל הדפדפנים. לכן חלק לא מבוטל מהמשתמשים שלכם ימשיכו להריץ דפדפן שלא יודע מה ההבדל בין let ל const ולא שמע שאפשר להגדיר מחלקות עם המילה class.
בייבל הוא כלי שיודע לתרגם קוד מודרני שאתם כותבים לקוד ישן שהדפדפן של הגולשים שלכם יכול להבין. יש תרגומים קלים ויש יותר קשים, ואתם יכולים לשחק עם הכלי ולראות אותו בפעולה אונליין באתר שלהם בכתובת:
דוגמא קטנה לקסמים של בייבל אפשר למצוא כשנדביק את הקוד הבא בפאנל השמאלי באתר שלהם:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
equals(other) {
return this.x === other.x && this.y === other.y;
}
}
const c1 = new Point(10, 10);
const c2 = new Point(10, 10);
console.log(c1.equals(c2));
ומיד בפאנל הימני נקבל את הגירסא הארוכה יותר (אבל שעובדת ברוב הדפדפנים):
"use strict";
function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var Point =
/*#__PURE__*/
function () {
function Point(x, y) {
_classCallCheck(this, Point);
this.x = x;
this.y = y;
}
_createClass(Point, [{
key: "equals",
value: function equals(other) {
return this.x === other.x && this.y === other.y;
}
}]);
return Point;
}();
var c1 = new Point(10, 10);
var c2 = new Point(10, 10);
console.log(c1.equals(c2));
וגם אם אנחנו לא מצליחים לקרוא את הקוד מהפאנל הימני, דפדפנים דווקא כן מצליחים. בצורה כזאת אנחנו יכולים לכתוב את הקוד שמסתדר לנו ובייבל יתרגם את זה אוטומטית כך שלגולשים שלנו לא תהיה בעיה להריץ את הקוד גם בדפדפן הישן שלהם.
2. הגדרת דפדפני יעד עם Browserlist
בשילוב וובפאק ובייבל אצלנו על המכונה אנחנו נבקש מ Webpack להריץ את Babel על כל אחד מהקבצים בפרויקט תוך כדי תהליך שילוב הקבצים וכך קובץ הפלט שנקבל בתיקיית dist יכיל רק קוד שדפדפנים ישנים מוכנים להריץ. אבל רגע, מה זה בעצם דפדפנים ישנים? האם כרום 72 הוא ישן? ומה עם אקספלורר 11? ואיזה גירסא של ספארי נחשבת ישנה?
בייבל די גמיש ויודע להתאים את הפלט לדפדפנים שאנחנו נבחר לכוון אליהם. המשחק כאן הוא עדין כי כל התאמה מגדילה את הקוד והופכת אותו למסורבל יותר, ולכן אנחנו רוצים להתאים לרוב הדפדפנים של הגולשים שלנו ומעדיפים לא להתאים לדפדפנים שאף אחד כבר לא משתמש בהם. בייבל יכול להשתמש בכלי שנקרא browserlist כדי להחליט מהם דפדפני היעד, ו browserlist נעזר בקובץ הגדרות כדי לתת לנו לבחור דפדפנים בצורה שמתאימה לנו.
את browserlist נתקין עם:
$ npm install --save-dev browserslist
ולאחר מכן נריץ אותו כדי לראות את הדפדפנים בהם בייבל יתמוך:
$ npx browserslist
והתוצאה אצלי:
and_chr 75
and_ff 67
and_qq 1.2
and_uc 12.12
android 67
baidu 7.12
chrome 75
chrome 74
chrome 73
edge 18
edge 17
firefox 68
firefox 67
firefox 60
ie 11
ie_mob 11
ios_saf 12.2-12.3
ios_saf 12.0-12.1
ios_saf 11.3-11.4
kaios 2.5
op_mini all
op_mob 46
opera 62
opera 60
safari 12.1
safari 12
samsung 9.2
samsung 8.2
אנחנו יכולים לעדכן את הגירסאות באמצעות יצירת קובץ הגדרות בשם .browserslistrc
. הקובץ מורכב משורות שכל אחת מגדירה עוד קבוצה של דפדפנים שנרצה לתמוך בה, לדוגמא:
> 5% in IL
שאומר שאנחנו רוצים לתמוך רק בדפדפנים שיש להם מעל 5% נתח שוק כאן בארץ, כלומר:
and_chr 75
chrome 75
chrome 74
ios_saf 12.2-12.3
או הגירסא הבאה שמוסיפה תמיכה גם בשתי הגירסאות האחרונות של Internet Explorer:
> 5% in IL
last 2 ie versions
והתוצאה היא רשימת הדפדפנים:
and_chr 75
chrome 75
chrome 74
ie 11
ie 10
ios_saf 12.2-12.3
בגדול ברירת המחדל של Browserslist תתאים לרוב המצבים ולכן מומלץ להשאיר את הקובץ עם השורה היחידה:
defaults
ולהוסיף דפדפנים כשעולה הצורך.
3. עדכון הגדרות Webpack כדי להפעיל גם את Babel
עכשיו שאנחנו מבינים מה Babel עושה ואיך הוא עושה את זה אפשר להמשיך ולחבר אותו ל Webpack. נתקין את Babel והפלאגין המתאים לוובפאק באמצעות:
npm install -D babel-loader @babel/core @babel/preset-env
ונעדכן את קובץ ההגדרות webpack.config.js כך שיכיל את התוכן הבא:
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
}
};
התוספת מתחילה במפתח module ובתוכו המפתח rules. אלה הכללים שאומרים ל Webpack מה לעשות עבור כל מודול, כלומר עבור כל קובץ JavaScript שמצאנו. המפתח test הוא החשוב ביותר באוביקט, והוא זה שמציין על איזה סוגי קבצים בכלל הפקודה הזאת משפיעה. במקרה שלנו הביטוי הרגולארי מציין קבצים שמסתיימים בסיומת js או mjs.
במפתח הבא, exclude, אנחנו משתמשים כדי לציין קבצים שבשום מקרה לא נרצה להפעיל עליהם את הקוד בכלל הנוכחי. אני רשמתי שם את הספריות node_modules
ו bower_components
שכן אלה תיקיות שבדרך כלל יישמרו בהם קבצי קוד שלקחתי מהאינטרנט, ואני סומך על מי שנתן לי את הספריות שכבר הפעיל את בייבל איפה שהיה צריך.
המפתח האחרון use הוא שקובע מה עושים על כל הקבצים האלה שהתאימו לשאילתה. הכתיב בדוגמא מפעיל עליהם את babel-loader, שזה רכיב שמחבר בין babel ל webpack. אופציית ה preset שהעברתי היא שגורמת לבייבל להסתכל על הקובץ .browserslistrc
שיצרנו מוקדם יותר בפוסט ולפיו להחליט לאיזה דפדפנים לכוון.
דוגמת הקוד משיעור זה זמינה אונליין בתיקיית הדוגמאות בקישור:
https://github.com/tocodeil/webpack-course-demos/tree/master/02-babel