How to use a Javascript library in Swift

Bruno Miguêns
4 min readMay 28, 2019

--

Made in 🇵🇹

If you find any mistake, error, misleading information or writing mistakes feel free to comment. Any feedback is welcome. 🙂

This article has a particular purpose, to share with you some of the struggles that I found and solutions that I came up, so let’s start!

Recently while developing a personal project I came across the need of reading data from a CSON file, which is a weird thing to do due to the fact nobody uses this kind of files (unpopular opinion 😬) at least in mobile development.

The simple task of reading a file containing some data become a huge issue especially because there are no CSON parsers for Swift and my options were either create my parser or use a JavaScript (JS) library to do so. Guess what? JS library it is 😎.

CSON is JSON without the curly braces. It instead relies on indentation to determine the hierarchy of your data.

Check this article to know more about CSON.

Probably every iOS developer knows Swift can run JS code smoothly by using JavaScriptCore (JSC), that’s right if you set some helpers otherwise is a pain, especially trying to understand where and why is JS code failing.

For the rest of this article, I’ll assume you have at least heard about JSC although if you never heard anything check this excellent NSHipster article to guide you throw the necessary knowledge.

As I said before, one of the significant barriers was checking logs or exceptions. Thankfully JSContext has a very convenient handler to deal with exceptions.

Another great life-saving tip is configuring a handler for console log, unfortunately, this one we have to do a workaround to make it work.

Essentially we need to create a variable that holds the console log function, create a swift handler and set the handler inside our JSContext as an object.

By this point, we have enough information being print out from the JS execution, so there’s no need for guessing when something is braking or not functioning correctly.

Let’s go back to the beginning of the article and talk about how to import an entire JS library.

After some hours of searching, I’ve come across a convenient npm library, probably very known in JS community, Browserify, check their website to know more about it.

Browserify lets you use require ... the same way you'd use it in Node. ...

Mainly we want to download all the required modules and/or dependencies used in our library and bundles them into a file, with this, we only have to integrate one file into the project making our lives a lot easier.

Why would you do that?

Well is not that weird, some JS libraries have many dependencies, in our case the library had CoffeeScript has a dependency so imagine importing the entire thing manually 😖.

To automate and guarantee the library works appropriately, we'll need to download the dependencies using npm and then use Browserify to bundle them into one file.

We’ll use a small library, cson-parser made by Groupon, so, let’s install Browserify, download the library (with their dependencies) and bundle the files.

By using npm to download our cson-parser, we're making sure every dependency is being locally stored, using the --save option for that.

In our shell script, we have two strange things --standalone and CSON > ....

Why we need those?

Well in our case the library has exported some modules using module.exports that we need, the --standalone option has the purpose to export the models to a global variable. The CSON > ... is just the global variable name that we call to interact with the library.

With all the tools and dependencies set, we can start taking care of the implementation, follow the next steps.

Let’s create our JSContext and set our exception and console log handlers.

Nothing new here, so let’s move on.

Load our parser bundle file.

Use the Browserify as explained before to obtain the CSON parser bundle.

Load the sample CSON file and convert it to a Dictionary, to check if the parser has successfully achieved the job.

Every time you run an evaluateScript() you'll get a discardable JSValue?, we’re able to convert it to a wide variety of types and objects (String, Dictionary, Date and many more).

You probably noticed a call to a setObject(:forKeyedSubscript:) with parseStringData as a key and our CSON content as an object, imagine the encoding work that we had to our evaluate script to make sure that no " , ' or any other character, is left without encoding and still don’t break anything in the JS execution.

So, the simplest way to avoid encoding our content is using the property parseStringData to save the content and add it to the script like this evaluateScript("CSON.parse(parseStringData)").

Data parsed and converted into a Dictionary, so we can compare to our sample file.

In the image above, we can confirm that our JS code has successfully parsed our file and returned exactly the data inside the CSON sample file.

Check our Swift Playground file and try it out!

I’m thrilled that you are still alive and read all the article, hope you enjoyed and perhaps learn/discovered something new.

Leave a comment for errors, suggestions, or whatever you like, we’re all always learning, and the feedback is always welcome. See you the next time. ✌️

--

--