mJS code style and convention (importing & other)

#1

Hi there!

I was constantly annoyed by the mjs syntax of importing and some other standard for JS things, but in mJS they are implemented so strange that I have to create a little polyfill to work around.

So, if any of you want to use mJS like a normal people I suggest to try my way)

The result init.js for blink demo with some logs looks like this:

As you see, you can use usual setInterval and require like NodeJS and you could feel free to choose any module’s local name as you want, but first you have to load (why load? why not include like C or just import? :confused: ) polyfill to enable new fuctions.

For internal libraries usage you have to convert module in standard way like this:
45736423

Or just clone lib content or add your own library with correct module.exports

And this is the polyfill source code:

let module = {exports: null};

function require(path) {
    // noinspection JSUnresolvedFunction
    load(path);
    // console.log('Load path:', path, JSON.stringify(module.exports));
    return module.exports;
}

let console = {log: print};

// noinspection JSUnresolvedFunction
load('api_timer.js');

function setInterval(fn, timeout) {
    return Timer.set(timeout, Timer.REPEAT, fn, null);
}
function setTimeout(fn, timeout) {
    return Timer.set(timeout, 0, fn, null);
}
function clearTimeout(id) {
    return Timer.del(id);
}
function clearInterval(id) {
    return clearTimeout(id);
}
#3

Add a repo with converted libs and code example: https://github.com/Asondo/mjs-polyfill

#4

That’s a nice polyfill indeed, it makes sense to include it by default.
Please sign the CLA (https://github.com/cesanta/mongoose-os#how-to-contribute ) and make a PR against https://github.com/mongoose-os-libs/mjs - add polyfill.js to https://github.com/mongoose-os-libs/mjs/tree/master/fs

Thank you!

#5

What about load('api_timer.js') inside polyfill? It shouldn’t be there by default, but then it would be strange to require timers in init.js to implement standard setInterval. Maybe check it only inside of setTimeout/setInterval methods? Is there any potential possibility that the library name (api_timer) will be changed and polyfill will throw an excepion?

#6

PR done.

With the timer acted like this:

// Load Timer lib only on demand & cache result
let __timer = null;

function __getTimer() {
    if (!__timer) {
        // TODO: add module.export to api_timer & use require with caching
        // noinspection JSUnresolvedFunction
        load('api_timer.js');

        __timer = Timer;
    }

    return __timer;
}
#7

Add caching required modules & normalise path string to require without .js, in future it may help with importing more complex external packages (if they will be implemented), but now it is just more convenient and similar to NodeJS and WebStorm autocompletion

function __resolvePath(p) {
    let sf = '.js';
    let f = p.length - 3;
    let e = p.indexOf(sf, f < 0 ? 0 : f);
    if (e === -1) {
        return p + sf;
    }

    return p;
}

function require(path) {
    // Add .js if not set
    path = __resolvePath(path);

    // Prevent duplicate load, return from cache
    let c = module._cache[path];
    if (c !== undefined) {
        return c;
    }

    // noinspection JSUnresolvedFunction
    load(path);

    // Add module to cache
    c = module._cache[path] = module.exports;
    // clean exports data to prevent modules duplication
    module.exports = null;

    return c;
}
#8

Merged. Thank you so much.