תוכן עניינים
הידעתם? ג'אווה סקריפט היא השפה הפופולארית ביותר כבר 5 שנים ברציפות.
אבל אתם בטח יודעים את זה אחרי שקראתם את הפוסט של שלומקה על סקר המפתחים של Stack Overflow.
כמעט לא ניתן למצוא היום אתר שלא עושה שימוש בסיסי לפחות בשפה ורוב האתרים עושים שימוש נרחב בשפה – בין היתר על ידי שימוש בפריימוורקים וספריות כדוגמת Angular, React, Vue וכו'.
הספריות הללו לוקחות על עצמן את האחריות הכבדה שברנדור ה – HTML ואם לומר את האמת – הן עושות את זה דיי טוב.
אבל – לרנדור ה – HTML בדפדפן יש השלכות:
זמן טעינה איטי יותר
רנדור ראשוני של התוכן (כלומר ה – HTML) בצד-לקוח איטי בהרבה מאשר בצד-שרת ויש "דף לבן" עד שמסתיים תהליך ההורדה של הקוד והביצוע שלו.
קוד מקור בלתי נראה
מכיוון שרנדור ה – HTML נעשה בצד-הלקוח, קוד המקור הראשוני לא מייצג את קוד המקור בפועל.
זה עשוי להביא לפגיעה בקידום – הנראות של קוד האתר נפגעת. נכון, מנוע החיפוש של גוגל מסוגל לצפות במרבית התוכן שמרונדר בצד-לקוח (תוכן דינמי),
אבל מעבר לכך שמנועי חיפוש רבים לא, גם גוגל מעדיפה שתרנדרו את האתרים שלכם בצד השרת מטעמי ביצועים.
קבלו את הדוגמה ממדריך Angular:
https://angular.io/resources/live-examples/toh-6/ts/eplnkr.html
אם נסתכל על קוד המקור (בקובץ index.html), אפשר לראות שבתוך תגית ה – body יש רק אלמנט אחד:
<my-app></my-app>
הדרך האידיאלית להתמודד עם הבעיות האלו היא לבצע חלוקת תפקידים:
- את המסמך הראשוני, יש לרנדר בצד-שרת
- עדכונים למסמך יש לרנדר בצד-לקוח
אבל איך אפשר לעשות את זה, אם הספריות הפופולריות ביותר, Angular ו – React, לוקחות על עצמן את הרנדור?
התשובה היא להריץ את הספריות הללו גם בשרת (כדי לרנדר את המסמך הראשוני) וגם בדפדפן (כדי לעדכן את המסמך).
V8: להריץ Javascript בשרת
V8 הוא מנוע ג'אווהסקריפט בקוד פתוח שנבנה על-ידי גוגל;
גם הדפדפן של גוגל (כרום) וגם סביבת הפיתוח Node.js מתבססות על המנוע בשביל להריץ ג'אווהסקריפט.
ואכן Node.js היא הפתרון הפופולרי ביותר לרנדור מסמך HTML בצד השרת על-ידי שימוש בג'אווהסקריפט – הרי זה ממש המטרה שלשמה היא נוצרה.
למפתחים ב – Angular יש את Angular Universal – רנדור Angular בצד-שרת שנבנתה עבור שרת Node.js.
בעצם, שימוש ב – Node.js מאפשר רנדור של כל ספריית ג'אווהסקריפט בצד השרת.
אבל מה איתנו – מפתחי PHP?! האם נותרנו מאחור?
התשובה מורכבת. אמנם יש פתרון – הרי בשביל מה אני כותב את הפוסט הזה? אבל הפתרון מעט מסורבל וקשה להבנה.
למזלכם – אני פה כדי לעשות את זה קל להבנה ופשוט לעיכול! הכירו:
V8Js – הרחבה ל – PHP שמריצה Javascript
V8Js מטמיעה את מנוע הג'אווהסקריפט של גוגל V8 ב – PHP ובעצם מאפשרת למפתחים להריץ קוד JS בארגז חול – כלומר ללא חשש שהקוד יפגע בתוכנית האם שרצה.
ההרחבה כתובה בקוד-פתוח ומציעה מספר מצומצם יחסית של פקודות – נעבור עליהן בהמשך המאמר.
אוקיי, אני חושב שמיצינו את ההקדמה והגיע הזמן לדבר האמיתי.
וודאו שאתם מצויידים ב – PHP 5.3.3 ומעלה, הגרסה הנמוכה ביותר שתומכת בהרחבה.
עם זאת, קחו בחשבון שבמאמר אני עושה שימוש ב – PHP 7 ולכן (ובלי קשר) אני ממליץ לכם להשתדרג. אבל למה שתקשיבו לי? אם יש מישהו להקשיב לו זה שלומקה שרשם מאמר על PHP 7
איך להתקין V8Js
אצלנו במשרד, אנחנו עובדים לרוב עם מערכת ההפעלה Windows לפיתוח ולכן מדריך ההתקנה מתייחס למערכת ההפעלה הזו.
עם זאת, החדשות הטובות עבור משתמשי לינוקס- ההתקנה הרבה יותר פשוטה בשבילכם! מקור טוב ניתן למצוא כאן.
משתמשי ווינדוס – יש לי חדשות טובות ורעות: הטובות הן שאני אדריך אתכם צעד-צעד איך להתקין את ההרחבה.
הרעות – זה הולך להיות מסורבל. שנתחיל?
שלב ראשון: איסוף מידע
כדי להתקדם, עלינו לברר שני דברים:
האם Thread Safety מופעל?
כדי לבדוק, יש לכם שתי אפשרויות:
- צרו קובץ PHP בשם
phpinfo.php
שמכיל קריאה לפונקציהphpinfo()
וחפשו "Thread Safety" - בשורת הפקודות (CMD), רשמו :
php -i | findstr "Thread"
אם רשום Disabled אזי Thread Safety מכובה, אחרת הוא מופעל (Enabled).
גרסת PHP
כדי לבדוק מהי גרסת ה – PHP, יש לכם שתי אפשרויות:
- פתחו שנית את הקובץ
phpinfo.php
, גרסת ה – PHP תופיע בראש העמוד - בשורת הפקודות (CMD) רשמו:
php -v
* אם השימוש בשורת הפקודות לא עובד ומתקבלת שגיאה, עליכם לנווט אל התיקייה שבה מותקן PHP
x86 או x64?
כדי לבדוק, פתחו את "המחשב שלי" ("מחשב זה", "This Computer"), לחצו קליק ימני ובחרו במאפיינים / Properties ובדקו מה מופיע תחת "System Type" / "סוג מערכת".
ככה זה נראה ב – Windows 10:
אוקיי אוקיי! יש לנו את כל מה שאנחנו צריכים – שימו גיטרות! (או: עברו לשלב השני)
שלב שני: להוריד את הקבצים הדרושים
התקנת הרחבות PHP בווינדוס יכולה להיעשות בשתי דרכים:
- לקמפל את ההרחבה לתוך PHP
- לטעון קבצי DLL
האפשרות השנייה היא גם הקלה יותר.
אם תיאלצו מסיבה כזו ואחרת לבחור באפשרות הראשונה, ניתן למצוא מידע נוסף בתיעוד הרשמי של PHP: התקנת הרחבה ל – PHP בווינדוס (אנגלית).
את ההרחבה עצמה ניתן להוריד כאן.
לפני שאתם ממשיכים לאפשרות הזאת – שווה לבדוק האם האפשרות השנייה רלוונטית עבורכם!
משתמש בשם Jan-E בפורום ApacheLounge משחרר גרסאות PHP שמכילות את קבצי ה – DLL של הספריה V8Js:
https://www.apachelounge.com/viewtopic.php?t=6359
ניתן לחלץ מההורדות שלו את קבצי ההרחבה של V8Js ולהוסיף אותם להתקנת ה- PHP שלכם. בואו נראה איך עושים את זה:
רשימת הקישורים מחולקת לפי גרסאות: PHP 5.3, PHP 5.4, PHP 5.5, PHP 5.6, PHP 7.0 ו – PHP 7.1.
בחרו את הקישור הרלוונטי עבורכם – לדוגמה, אם גרסת ה – PHP שלכם היא 7.0 x86 ו Thread Safety מכובה, הלינק הרלוונטי עבורכם הוא:
https://phpdev.toolsforresearch.com/php-7.0.17-nts-Win32-VC14-x86.zip
nts משמעותו Non Thread Safety.
אבל רגע! מה קורה אם גרסת ה – PHP שלכם היא 7.0.13?
במקרה כזה, נסו להתאים את הקישור לגרסה המתאימה:
https://phpdev.toolsforresearch.com/php-7.0.13-nts-Win32-VC14-x86.zip
חלק מהגרסאות עדיין זמינות להורדה. אם הגרסה שלכם לא, תיאלצו לבחור בין שדרוג גרסת ה – PHP לבין קמפול ההרחבה.
שלב שלישי: חילוץ הקבצים המתאימים
את הקבצים הבאים יש לחלץ לתיקייה בה מותקנת PHP:
v8.dll
- icui18n.dll (רק ב – php 7)
- icuuc.dll (רק ב – php 7)
את הקובץ הבא יש לחץ לתיקייה ext
שנמצאת בתוך התיקייה בה מותקנת PHP:
php_v8js.dll
שלב רביעי: הוספת ההרחבה
כעת, פתחו את הקובץ php.ini
וחפשו "Windows Extensions".
מתחת להרחבה האחרונה הוסיפו את השורה הבאה:
extension=php_v8js.dll
בנוסף, וודאו שתיקיית ההרחבות מוגדרת – חפשו:
extension_dir = "ext"
אם השורה כתובה בהערה (מתחילה בנקודה-פסיק) מחקו את הנקודה-פסיק:
שלב חמישי: אתחול השרת
הגענו לרגע האמת – אתחלו את השרת!
כדי לבדוק אם ההתקנה עברה בהצלחה:
פתחו את הקובץ phpinfo.php
וחפשו "v8js".
אם המסך הבא מופיע, ההתקנה עברה בהצלחה:
או:
פתחו את שורת הפקודות והריצו את הפקודה הבאה:
php -i | findstr "v8js"
אם המסך הבא מופיע, ההתקנה עברה בהצלחה:
כמובן שהערכים עצמם עשויים להשתנות בהתאם לגרסה המותקנת.
אם ההתקנה לא עברה בהצלחה, נסו לעבור על המדריך מהתחלה.
רוב הסיכויים שהקבצים שהורדתם לא מתאימים לגרסת ה – PHP שמותקנת.
עדיין לא הצלחתם? כתבו לי בתגובות ואנסה לעזור!
ולברי המזל שהגיעו עד הלום, שנריץ קצת ג'אווהסקריפט בשרת, עם PHP?!
בקטנה: שלום עולם
בואו נתחיל בדוגמה קלילה.
צרו קובץ חדש בשם HelloWorld.php.
בשלב הראשון ניצור מופע מסוג V8Js
:
1 2 3 |
<?php $v8 = new V8Js; |
בואו נתעמק בממשק של V8Js
:
executeString
הפונקציה מקבלת קוד ג'אווהסקריפט (מחרוזת;string) ומחזירה את התוצאה של הרצת הקוד.
חשוב להבין שאנחנו לא נמצאים בסביבת דפדפן ולכן משתנים כמו window
או document
לא קיימים כאן!
מה כן זמין עבורנו?
הדפסה: print
או var_dump
הפונקציה print
מקבילה לפקודה echo
– מדפיסה מחרוזת.
הפונקציה var_dump
זהה למקבילתה ב – PHP.
סיום הריצה: exit
הפונקציה exit
מקבילה לפקודה exit
ומסיימת את ריצת הסקריפט.
לדוגמה הבסיסית שלנו, זה מספיק. בואו נראה איך בפועל זה נראה (נסו לנחש מה יודפס):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php $v8 = new V8Js; $script = [ 'var message = "שלום עולם";', 'print(message);', 'exit();', 'print("התוכנית נגמרה?");' ]; try { $result = $v8->executeString(implode(PHP_EOL, $script)); } catch(Exception $e) { echo '<h1>' . $e->getMessage() . '</h1>'; echo '<pre>' . $e->getTraceAsString() . '</pre>'; exit; } |
אוקיי, קצת סדר בבלאגן:
המשתנה $script
מכיל מערך פקודות ג'אווהסקריפט.
לאחר מכן נעשה ניסיון להריץ את המחרוזת (הפונקציה implode
הופכת מערך למחרוזת).
מכיוון שהמחרוזת תקינה ולא נזרקה חריגה, הרצת הקובץ HelloWorld.php
תדפיס על המסך שלכם שלום עולם!
המחרוזת "התוכנית נגמרה?" לא תופיע כי היא נקראה לאחר הפונקציה exit
, שכזכור מסיימת את ריצת הסקריפט.
כמו שאמרתי, אי אפשר להשתמש במשתני דפדפן כמו window
או document
, אם ננסה:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php $v8 = new V8Js; $script = [ 'var message = document.getElementById("my-app");', 'var_dump(message);', ]; try { $result = $v8->executeString(implode(PHP_EOL, $script)); } catch(V8JsScriptException $e) { echo '<h1>' . $e->getMessage() . '</h1>'; echo '<pre>' . $e->getTraceAsString() . '</pre>'; exit; } ?> |
נקבל שגיאה שאומרת לנו בדיוק את זה:
V8Js::compileString():1: ReferenceError: document is not defined
טעינת מודולים
מי שעובד עם מודולים, ישמח לשמוע שV8Js
מאפשרת הגדרת טעינת מודולים.
מה הכוונה? כאשר המנוע ייתקל בפקודה require
, הוא יקרא לפונקציה שהוגדרה כדי לטעון בפועל את המודול.
זה נשמע מסובך, אבל בפועל זה משחק ילדים:
1 2 3 4 5 6 7 8 9 10 11 |
var React = require("react"); var Example = React.createClass({ render: function() { return React.createElement( 'div', null, 'This is Example' ); } }); |
אם ננסה להריץ את הקובץ דרך V8Js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php $v8 = new V8Js; print_r($v8); $script = [ file_get_contents('./scripts/example.js'), ]; try { $result = $v8->executeString(implode(PHP_EOL, $script)); } catch(V8JsScriptException $e) { echo '<h1>' . $e->getMessage() . '</h1>'; echo '<pre>' . $e->getTraceAsString() . '</pre>'; exit; } |
נקבל שגיאה – מכיוון שטרם הגדרנו module loader:
V8Js::compileString():1: No module loader
אז בואו נגדיר אחד!
setModuleLoader
הפונקציה setModuleLoader
מקבלת כפרמטר פונקציה (callable
) –
שמקבלת מחרוזת שמייצגת את המודול שניסינו לטעון וצריכה להחזיר קוד ג'אווהסקריפט מוכן להפעלה.
ניתן ליישם בכל דרך שרוצים בהתאם לפרוייקט עליו אתם עובדים. דוגמה ליישום:
1 2 3 4 5 6 7 |
<?php $v8 = new V8Js; $v8->setModuleLoader(function($path) { return file_get_contents('./scripts/' . $path . '.js'); }); |
כעת, בכל פעם שבסקריפט תהיה קריאה ל – require, ה – Module Loader יחפש את הספריה בתיקייה scripts.
כך לדוגמה, כאשר נרשום:
require('react')
הפונקציה תקבל כפרמטר את המחרוזת react
ותנסה להחזיר את הקובץ שנמצא בנתיב ./scripts/react.js
כעת, אם נריץ את הקובץ React.php
עם ה – Module Loader שהגדרנו:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php $v8 = new V8Js; $v8->setModuleLoader(function($path) { return file_get_contents('./scripts/' . $path . '.js'); }); $script = [ file_get_contents('./scripts/example.js'), ]; try { $result = $v8->executeString(implode(PHP_EOL, $script)); } catch(V8JsScriptException $e) { echo '<h1>' . $e->getMessage() . '</h1>'; echo '<pre>' . $e->getTraceAsString() . '</pre>'; exit; } |
כעת המשתנה Example
מוכן לשימוש ללא כל שגיאה!
כדי לרנדר אלמנט של React
בשרת עלינו להשתמש בספרייה ReactDomServer
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php $v8 = new V8Js; $v8->setModuleLoader(function($path) { return file_get_contents('./scripts/' . $path . '.js'); }); $script = [ 'var ReactDOMServer = require("ReactDomServer")', file_get_contents('./scripts/example.js'), 'ReactDOMServer.renderToString(React.createElement(Example))' ]; try { $result = $v8->executeString(implode(PHP_EOL, $script)); echo $result; } catch(V8JsScriptException $e) { echo '<h1>' . $e->getMessage() . '</h1>'; echo '<pre>' . $e->getTraceAsString() . '</pre>'; exit; } |
וזהו זה! אם תיגשו לקובץ React.php
תוכלו לראות על המסך את ההודעה: This is example.
אבל יותר חשוב, אם תסתכלו על קוד המקור, יתגלה לפניכם הקוד שרינדרנו בשרת:
<div data-reactroot="" data-reactid="1" data-react-checksum="-1940384550">This is Example</div>
ואם הגעתם עד לפה, אני שמח להגיד שהשגתי את מטרתי: הראתי לכם איך להריץ Javascript בשרת עם PHP – ולצאת מזה בחיים!
איך למנוע שגיאות ב – 60 שניות
כמו שכבר אמרתי, V8
לא יודעת איך להתמודד עם משתני דפדפן.
הדבר הנכון ביותר לעשות הוא הפרדה בין סקריפט שבו אנחנו מבצעים הגדרה של פונקציות, משתנים וכו' לבין סקריפט שמבצע שינויים ב – DOM.
אבל, בפועל לא תמיד הדבר אפשרי ולכן תזכרו תמיד שניתן להגדיר בעצמכם את משתני הדפדפן, כדי למנוע שגיאות.
דוגמה טובה היא הפונקציה console.log
שנעשה בה שימוש רווח ולא זמינה ב – V8
.
כדי להימנע משגיאות, נגדיר אותה:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php $v8 = new V8Js; $v8->setModuleLoader(function($path) { return file_get_contents('./scripts/' . $path . '.js'); }); $script = [ 'var console = {log: function() {}}', file_get_contents('./scripts/app.js') ]; try { $result = $v8->executeString(implode(PHP_EOL, $script)); } catch(V8JsScriptException $e) { echo '<h1>' . $e->getMessage() . '</h1>'; echo '<pre>' . $e->getTraceAsString() . '</pre>'; exit; } |
שימו לב שאתם משתמשים ביכולת הזו בחכמה – ולא מייצרים שגיאות לוגיות!


תגובה אחת
איתן
11 באפריל 2017 - 5:55מעניין מאוד. תודה!