Skip to content

Limitations in Electron

Chung Leong edited this page Apr 25, 2024 · 3 revisions

Electron no longer supports external buffers (see issue). This makes it impossible to expose memory from within a Zig module to JavaScript code. Global variables will therefore not be accessible:

const std = @import("std");

pub const constant_number: i32 = 1234;
pub var variable_number: i32 = 4567;

pub fn printVariable() void {
    std.debug.print("variable_number = {d} (Zig)\n", .{variable_number});
}

pub fn changeVariable() void {
    variable_number = 1999;
}
require('node-zigar');
const test = require('../zig/test.zig');

console.log(test.constant_number);
console.log(test.variable_number);
1234
undefined

The option omitVariables is by default true on Electron. If you override the default and make it false, JavaScript would be able to see the initial value of the variable. It would not be able to actually alter the variable. Nor would it see any subsequent changes done on the Zig side:

require('node-zigar/cjs');
const test = require('../zig/test.zig?omit-variables=0');

console.log(`variable_number = ${test.variable_number} (JavaScript)`);
console.log('setting variable to 8888 in JavaScript');
test.variable_number = 8888;
test.printVariable();
console.log('setting variable to 1999 in Zig');
test.changeVariable();
test.printVariable();
console.log(`variable_number = ${test.variable_number} (JavaScript)`);
variable_number = 4567 (JavaScript)
setting variable to 8888 in JavaScript
variable_number = 4567 (Zig)
setting variable to 1999 in Zig
variable_number = 1999 (Zig)
variable_number = 8888 (JavaScript)

Node-zigar resorts to making a copy of the memory when it's blocked from creating an external buffer. This strategy does not impact pointers. Zig code would still receive the right addresses. For example, this example from the previous section works correctly in Electron:

const std = @import("std");

var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var allocator = gpa.allocator();

pub fn floatToString(num: f64) ![]const u8 {
    return std.fmt.allocPrint(allocator, "{d}", .{num});
}

pub fn freeString(str: []const u8) void {
    allocator.free(str);
}
const { floatToString, freeString } = require('./data-transfer-example-2.zig');

const array = floatToString(Math.PI);
console.log(array.string);
freeString(array);
3.141592653589793

The pointer that freeString() receives is the one returned by floatToString().

Clone this wiki locally