החיים אחרי בייבל
את AMD הכרתי באמצעות require.js שהיתה להיט באזור שנת 2012 (מה שנקרא, עובד ב IE6) וכנראה גם קצת קודם. מה ש require עשתה היה לאפשר לכם לכתוב בתוך קובץ JavaScript אחד פקודה שתטען קובץ JavaScript אחר. נכון, לפני require היתה את dojo שעבדה על אותו מנגנון אבל זה כבר למתקדמים.
ל Require היה כלי אופטימיזציה שלוקח קבצים שכתובים ב AMD ומאחד אותם יחד לקובץ אחד וככה מצליח לשפר את זמן טעינת העמוד, כי צריך לשלוח פחות קבצים לדפדפן. אחרי זה הגיעו grunt, gulp, webpack ו babel ואנחנו עברנו להשתמש בכתיב ה import/export ולהריץ קוד על קבצי ה JavaScript בתוך שלב האופטימיזציה.
הרצת הקוד איפשרה ליצור תחבירים חדשים כמו TypeScript ו JSX, שמתקמפלים ל JavaScript ומספקים חוויה טובה יותר למתכנתים. בגלל שממילא הרצנו וובפאק לא היתה עלות לשימוש בכלים אלה. בסך הכל עוד פלאגין להתקין.
נגלגל קדימה ל 2022 והעולם השתנה שוב. היום דפדפנים תומכים תמיכה מלאה ב ES Modules ובטעינת קובץ JavaScript מתוך קובץ אחר. בנוסף תקן HTTP/2 תומך ב Server Push שאומר שאין ייתרון מבחינת ביצועים ל Bundling.
וככה אנחנו קמים בוקר אחד ומגלים שזה הזנב שמקשקש בכלב - שה JSX, שמכרו לנו אותו כמו תוספת חביבה שלא עולה כלום, נשאר הסיבה היחידה להמשיך להשתמש בכל הקונסטרוקציה של וובפאק ו babel. והגלגל מתחיל להסתובב שוב.
הספריה htm מציעה למי שרוצה לוותר על שלב הקומפילציה דרך החוצה, באמצעות תחביר שנראה מאוד דומה ל JSX אבל עובד בדפדפן. שילוב של htm עם כל שאר החידושים בעולם ה web מאפשר בניה של אפליקציית ריאקט מלאה בלי קומפילציה. בואו נראה איך זה עובד.
1. קוד הפרויקט
אני כותב קובץ בשם index.html עם התוכן הבא:
<!DOCTYPE html>
<html lang="en">
<head><title>Hello World</title></head>
<body>
<main id="app"></main>
<script type="importmap">
{
"imports": {
"htm/react": "https://ga.jspm.io/npm:htm@3.1.1/react/index.module.js",
"react": "https://ga.jspm.io/npm:react@18.1.0/dev.index.js",
"react-dom": "https://ga.jspm.io/npm:react-dom@18.1.0/dev.index.js"
},
"scopes": {
"https://ga.jspm.io/": {
"htm": "https://ga.jspm.io/npm:htm@3.1.1/dist/htm.module.js",
"object-assign": "https://ga.jspm.io/npm:object-assign@4.1.1/index.js",
"scheduler": "https://ga.jspm.io/npm:scheduler@0.20.2/dev.index.js",
"scheduler/tracing": "https://ga.jspm.io/npm:scheduler@0.20.2/dev.tracing.js"
}
}
}
</script>
<!-- ES Module Shims: Import maps polyfill for modules browsers without import maps support (all except Chrome 89+) -->
<script async src="https://ga.jspm.io/npm:es-module-shims@1.5.1/dist/es-module-shims.js" crossorigin="anonymous"></script>
<script type="module" src="src/main.js"></script>
</body>
</html>
החלק הראשון אמור להיות לכם מוזר - המנגנון נקרא Import Maps והוא אמור לאפשר בעתיד ניהול תלויות מסודר מתוך ES Modules. כרגע, הבעיה עם תלויות היא שכשאתם כותבים:
import React from 'react';
לדפדפן אין מושג מאיפה להביא את react. ב node או webpack אנחנו משתמשים בקובץ package.json בשביל למפות את השם הזה לקובץ אמיתי, ובתוך דפדפן Import Maps הוא הצעה אחת למימוש כזה מנגנון. אפשר לקרוא עליו כאן: https://github.com/WICG/import-maps
הדבר החשוב הוא שכרגע יש פוליפיל שעובד והרבה כלים שיודעים לקחת קובץ package.json ולהפוך אותם ל Import Maps, וגם ממשק גרפי אונלייני לבניית Import Maps שאפשר למצוא בקישור הזה: https://generator.jspm.io/#.
לכן החלק של ה Import Maps מקביל ל package.json שיהיה לנו בפרויקט webpack קלאסי.
חוץ ממנו יש סקריפט בשם main שמוגדר כמודול והוא נקודת הכניסה ליישום.
בקובץ src/main.js
אני כותב את התוכן הבא:
import { html } from 'htm/react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(html`<${App} />`, document.querySelector('#app'));
ופה אנחנו מתחילים לראות את ספריית htm בפעולה. אפשר לראות שהקוד אינו JSX אבל הוא כן מאוד דומה בזכות השימוש ב Template Strings. אגב, חוץ מזה אפשר היה בקלות לטעות ולחשוב שאנחנו בפרויקט וובפאק. כל ה import-ים עובדים רגיל לגמרי.
הקובץ השלישי הוא src/App.js
(ולא jsx, כי אין יותר jsx) והוא מקבל את התוכן הבא:
import { html } from 'htm/react';
import React from "react";
export default function App() {
const [count, setCount] = React.useState(0);
function inc() {
setCount(c => c + 1);
}
return (
html`<div>
<p>Welcome To The Future</p>
<button onClick=${inc}>Value: ${count}. Click To Increase</button>
</div>
`
);
}
הכל כאן ריאקט רגיל לגמרי, חוץ מה JSX שהפך ל Template Strings שמאוד דומים לו.
2. הרצה
שלושת הקבצים האלה, בלי וובפאק, בלי node.js, בלי בייבל ובלי שום טרנספילציה, רק שלושה קבצים - מספיקים בשביל לקבל יישום ריאקט בדפדפן. אני מפעיל שרת מקומי על פורט 8080 עם הפקודה:
$ npx http-server
נכנס מהדפדפן לשרת מקומי עם הפורט המתאים ומקבל כפתור שמראה כמה פעמים לחצתי עליו.
3. מחשבות לעתיד
כמה מחשבות והערות אחרי כתיבת הקוד הזה:
האתר ga.jspm.io הוא זה שמגיש את קבצי ה JavaScript בפועל והוא מתפקד בתור CDN. זה מאוד מזכיר את החיים בפיתוח ווב לפני עשר שנים, כשבשביל להשתמש בספריה היינו פשוט מדביקים את הלינק אליה ל html. אני מתאר לעצמי שהרבה אנשים יעדיפו עדיין לשמור את כל התלויות האלה אצלם בפרויקט או על cdn בשליטתם, וזה בסדר - ל Import Maps לא אכפת מאיפה הוא מביא את המודולים.
יהיה מעניין לראות אם לאורך זמן אפשר יהיה למצוא הצדקה ל webpack ו babel, כשרוב מה שהם עושים אפשר לעשות היום ישירות בדפדפן. נכון - scss זה חמוד ול TypeScript יש יתרונות, אבל המחיר של הכלים האלה מתחיל להיות משמעותי ככל שהאלטרנטיבה הפשוטה יותר יכולה לתת מענה מלא לרוב הצרכים.