PharoJS is a Pharo to JavaScript compiler and infrastructure for remote test and debugging. The goal is to enable developing apps in Pharo while deploying them on top of a JavaScript engine. It is a general purpose solution. For example, PharoJS can be used to develop client side web applications. It can also be used to support cross-platform mobile apps based on Phone Gap.

Download and Install

PharoJS is freely available under MIT License. Install can be done inside Pharo 4.0 by evaluating the following in a playground:

Gofer it
smalltalkhubUser: 'noury' project: 'PharoJS';
addPackage: #ConfigurationOfPharoJS ;
loadStable.

This will install the latest stable version.

Interactive Code Evaluation

First launch PharoJS workspace, by evaluating the following expression in a plain workspace or GT playground:


workspace := JbWorkspaceForWeb open.

This will open pink workspace, this is the current PharoJS workspace. It also launches a server on Pharo side and opens a web browser that is connected to the server. Now, you can evaluate a simple Smalltalk expression such as 1+2, and see it performing on the web browser (see Figure 1).

To use Pharo objects, you need to send their classes (except Object) and superclasses to the JavaScript interpreter. For example, consider the JbCounter class provided with PharoJS. To transfer it to JavaScript world, you need to go back to the plain Pharo workspace and evaluate:


workspace javaScriptBridge loadClass: JbCounter.

You’ll see on the web browser that the JbCounter javascript code was generated and loaded. Now, you can play with the JbCoutner in the PharoJS (pink) workspace, and evaluate expressions such as:


counter := JbCounter new.
counter count.
counter increment.

Note: When you load a class, you need obviously to load also all classes it uses, and its superclass. But, here the superclass is JbObject which is the root class of PharoJS classes. It is loaded by default when you open the workspace, because the code to support the PharoJS workspace is written in PharoJS itself :-)

Running Tests on a Web browser

You can write tests in Pharo that evaluate expressions using a JavaScript interpreter. So, you can write and perform assertions in Smalltalk that check the results of code evaluated by the JavaScript interpreter. Here is an example.

Create a JbJavaScriptCounterTest test class as a subclass of JbBridgeTest. Add the following setUp method.

setUp
super setUp.
bridge loadClass: JbCounter.
bridge eval: 'counter := JbCounter new'.

The bridge is the connection with a web browser that will serve as our JavaScript interpreter. It converts the JbCounter from Smalltalk to JavaScript before sending it to the interpreter (loadClass: message).

The bridge also allows evaluating Smalltalk expressions on the web browser. It converts the string with Smalltalk code to JavaScript and perform it on the web browser.

Let’s write a test method. Consider the following one:
testAfter20IncrementCountIs20
bridge eval: '20 timesRepeat: [counter increment]'.
self assertSmalltalk: 'counter count' equalsJson: '20'

We first make the bridge evaluate an expression on the browser (eval: message). Then we check that the Smalltalk expression counter count when evaluated on the web browser (after conversion to JavaScript of course) result into an expected Json string.

The full code of the test is available in the Example category of the PharoJS project. You can run it using the TestRunner of Pharo. You’ll see the web browser blinking openning/closing a tab or a window for every test method.

Exporting code to a JavaScript file

Once development is finish, you generate a JavaScript to use for production. To do so, you need to provide all classes of your app in a collection as a parameter of the following message:

JbSmalltalkToJavaScriptExporter exportAppClasses: {JbCounter} packages: #() inNewFileNamed: 'counter.js'

Then integrate the counter.js file with the GUI. Basically, this boils down to importing the javascript file in a html file by adding the following line.

HowTO

How do you integrate HTML/CSS files from a web designer into a PharoJS application?

Export your PharoJS project as a javascript file that you import into your HTML file like any JS file. Of course, your PharoJS code must reference DOM objects. You can get DOM objects in PharoJS by simply using the javascript document objet. Here is an example, assuming that I have in my HTML an object say a DIV <div id=”someId”>…</div>, I can obtain its reference in PharoJS using the following expression.
document native_getElementById: 'someId'

The Pharo code related to a project will have an entry point which is a subclass of JbApplication. Export to Javascript can be achieved using class methods for export, as following:

JbDemoApplication exportToFile: 'demo.js'

The exported code, ends with sending the start message to the app (JbDemoApplication start) which by default sends the start message to a new instance. Typically, you override the instance side start method. HTML widget typically trigger javascript code that sends messages to any class from PharoJS (eg <div onclick=”JbDemoApplication._doSomething()”>) . To avoid collisions, methods from Pharo are prefixed with an underscore when converted to javascript. Besides, columns in keyword selectors are replaced with underscores too (eg  Pharo message JbDemoApplication doSomethingWith: 3 and: 12 converts to javascript JbDemoApplication._doSomethingWith_and_(3, 12)).

The start method of an app may also introduce extra globals that will be referenced in the HTML or any other pure JS library. This can be done using  the follwing message, that is understood by any PharoJS object

install: anObject asGlobalNamed: jsName

How do you integrate JavaScript libraries into PharoJS?

Your JS file from PharoJS should be imported together with other JS libraries in your HTML. In your PharoJS code, you need to global objects introduced by your libraries as entry points to JS libraries. All you need is to declare them using

JbProxy class>>#installJavaScriptGlobals: collectionOfJsGlobalNames.

 

Contact

For questions, please post them as comments to the current page. For further more information, please get in touch with Noury.

7 thoughts on “PharoJS: Develop in Pharo, Run on JavaScript

  1. Hello Noury,
    While loading in the bleeding edge Configuration, I got a UHE. JbProxy>>installJavaScriptGlobals: does not exist. I used jbProxy>>installJavascriptGlobals: instead.

    Regards,

    Georges

    Reply
  2. PharoJS looks great. Is there any active development on this?
    Is it at a beta stage yet, or more alpha?

    It would be great to know what remains to be done?
    Thank you.

    Reply
  3. Would this be possible to use for making multiplayer games? I am currently using websocket in pharo for this purpose.

    Reply
  4. Running some of the tests I get:

    “MessageNotUnderstood: JbProxy class>>bridge:”

    I’ll try to fix it myself but just wanted to let you know

    Reply

Leave a reply to Georges Cancel reply

required

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>