A fast and easy library to add a Javascript runtime into your Zig project.
With this library you can:
Features:
Currently only v8 is supported as a Javascript engine, but other engines might be added in the future.
This library is fully single-threaded to matches the nature of Javascript and avoid any cost of context switching for the Javascript engine.
Integrate a Javascript engine into a Zig project is not just embeding an external library and making language bindings. You need to handle other stuffs:
This library takes care of all this, with no overhead thanks to Zig awesome compile time capabilities.
In your Zig project, let's say you have this basic struct that you want to expose in Javascript:
const Person = struct {
first_name: []u8,
last_name: []u8,
age: u32,
// Constructor
// if there is no 'constructor' defined 'new Person()' will raise a TypeError in JS
pub fn constructor(first_name: []u8, last_name: []u8, age: u32) Person {
return .{
.first_name = first_name,
.last_name = last_name,
.age = age,
};
}
// Getter, 'get_<field_name>'
pub fn get_age(self: Person) u32 {
return self.age;
}
// Setter, 'set_<field_name>'
pub fn set_age(self: *Person, age: u32) void {
self.age = age;
}
// Method, '_<method_name>'
pub fn _lastName(self: Person) []u8 {
return self.last_name;
}
};
You can generate the corresponding Javascript functions at comptime with:
const jsruntime = @import("jsruntime");
pub const Types = jsruntime.reflect(.{Person});
And then use it in a Javascript script:
// Creating a new instance of Person
let p = new Person('John', 'Doe', 40);
// Getter
p.age; // => 40
// Setter
p.age = 41;
p.age; // => 41
// Method
p.lastName(); // => 'Doe'
Let's add some inheritance (ie. prototype chain):
const User = struct {
proto: Person,
role: u8,
pub const prototype = *Person;
pub fn constructor(first_name: []u8, last_name: []u8, age: u32, role: u8) User {
const proto = Person.constructor(first_name, last_name, age);
return .{ .proto = proto, .role = role };
}
pub fn get_role(self: User) u8 {
return self.role;
}
};
pub const Types = jsruntime.reflect(.{Person, User});
And use it in a Javascript script:
// Creating a new instance of User
let u = new User('Jane', 'Smith', 35, 1); // eg. 1 for admin
// we can use the User getters/setters/methods
u.role; // => 1
// but also the Person getters/setters/methods
u.age; // => 35
u.age = 36;
u.age; // => 36
u.lastName(); // => 'Smith'
// checking the prototype chain
u instanceof User == true;
u instanceof Person == true;
User.prototype.__proto__ === Person.prototype;
A Javascript shell is provided as an example in src/main_shell.zig
.
$ make shell
zig-js-runtime - Javascript Shell
exit with Ctrl+D or "exit"
>
zig-js-runtime is written with Zig 0.13.0
. You have to
install it with the right version in order to build the project.
To be able to build the v8 engine, you have to install some libs:
For Debian/Ubuntu based Linux:
sudo apt install xz-utils \
python3 ca-certificates git \
pkg-config libglib2.0-dev clang
For MacOS, you only need Python 3.
The project uses git submodule for dependencies.
The make install-submodule
will init and update the submodules in the vendor/
directory.
make install-submodule
The command make install-v8-dev
uses zig-v8
dependency to build v8 engine lib.
Be aware the build task is very long and cpu consuming.
Build v8 engine for debug/dev version, it creates
vendor/v8/$ARCH/debug/libc_v8.a
file.
make install-v8-dev
You should also build a release vesion of v8 with:
make install-v8
You can run make install
and make install-dev
to install deps all in one.
Some Javascript features are not supported yet:
You can test the zig-js-runtime library by running make test
.