为 Duktape 添加 JavaScript 模块化加载能力

Duktape 是一个体积小巧、可移植性高、适合嵌入到各种环境中的 JavaScript 引擎。

最近需要将 protobuf.js 移植到 Duktape 里边运行起来,所以需要解决 JavaScript 模块化加载问题,也就是要支持 require, module.exports 语法。我们通过 modSearch 函数来实现模块化加载:

实现 modSearch 函数

Implementing a native modSearch() function这篇 guide 里边有说通过在 native 实现 modSearch 函数就可以在 JavaScript 里通过require的时候加载到别的模块。

我在 c 层实现 modSearch 函数如下:

//
//  main.c
//  duktape
//
//  Created by faywong on 16/3/18.
//  Copyright  2016年 faywong. All rights reserved.
//

#include <stdio.h>
#include "duktape.h"
#include "fileio.h"

duk_ret_t my_mod_search(duk_context *ctx) {
    /*
     *   index 0: id (string)
     *   index 1: require (object)
     *   index 2: exports (object)
     *   index 3: module (object)
     */
    printf("fun: %s in, id: %s\n", __FUNCTION__, duk_require_string(ctx, 0));

    const char *id = duk_require_string(ctx, 0);
    duk_pop_n(ctx, duk_get_top(ctx));

    const int FILE_PATH_LEN = 1024;
    char file[FILE_PATH_LEN];
    memset(file, 0, FILE_PATH_LEN);
    snprintf(file, FILE_PATH_LEN, "/Users/faywong/%s.js", id);

    duk_push_string_file(ctx, file);
    return 1;
}

/*
 * Register Duktape.modSearch
 */
void register_mod_search(duk_context *ctx) {
    duk_eval_string(ctx, "(function (fun) { Duktape.modSearch = fun; })");
    duk_push_c_function(ctx, my_mod_search, 4 /*nargs*/);
    duk_call(ctx, 1);
    duk_pop(ctx);
}

int main(int argc, const char * argv[]) {

    duk_context *ctx = duk_create_heap_default();

    if (ctx) {

        register_mod_search(ctx);

        register_fileio(ctx);

        duk_eval_file(ctx, "/Users/faywong/test.js");
        printf("result is: %s\n", duk_safe_to_string(ctx, -1));
        duk_pop(ctx);
    }

    return 0;
}

test.js 用以验证实现的模块化加载功能是否正常,内容如下:

var ByteBuffer = require('bytebuffer');
var test = new ByteBuffer(10);
print('step 1, ByteBuffer ok: ' + test.toString());
var ProtoBuf = require('protobuf');
print('step 2, ProtoBuf ok: ' + (typeof ProtoBuf));
print('step 3, typeof ProtoBuf.loadProtoFile: ' + (typeof ProtoBuf.loadProtoFile));
var builder = ProtoBuf.loadProtoFile('/Users/faywong/complex.proto');
print('step 4, typeof builder: ' + (typeof builder));

Game = builder.build("Game"),
Car = Game.Cars.Car;

// OR: Construct with values from an object, implicit message creation (address) and enum values as strings:
var car = new Car({
    "model": "Rustywq",
    "vendor": {
        "name": "Iron Inc.",
        "address": {
            "country": "US"
        }
    },
    "speed": "SUPERFAST" // also equivalent to "speed": 2
});

// OR: It's also possible to mix all of this!

// Afterwards, just encode your message:
var buffer = car.encode();

print('step 5, typeof buffer: ' + (typeof buffer) + ' toString(): ' + buffer.toString());
 

其中:

  • register_mod_search 函数用于向 Duktape 注册一个用于加载 JavaScript 模块的函数 my_mod_search,该函数有四个入参,分别为模块 id、发起 require 的模块、本模块的 exports 对象、本模块的 module 对象,该函数加载 /Users/faywong 目录下以 id 为主文件名(比如在 test.js 中 require 到的 bytebuffer, protobuf)的 JavaScript 文件并将文件内容返回给 Duktape
  • 为了方便,test.js 中 require 的其他 JavaScript 模块被笔者放在了自己的家目录下:
    /Users/faywong/bytebuffer.js
    /Users/faywong/protobuf.js
    /Users/faywong/test.js
时间: 2024-11-03 21:11:42

为 Duktape 添加 JavaScript 模块化加载能力的相关文章

浅析AMD CMD CommonJS规范--javascript模块化加载学习心得总结_javascript技巧

这是一篇关于javascript模块化AMD,CMD,CommonJS的学习总结,作为记录也给同样对三种方式有疑问的童鞋们,有不对或者偏差之处,望各位大神指出,不胜感激. 本篇默认读者大概知道require,seajs的用法(AMD,CMD用法),所以没有加入使用语法. 1.为何而生:  这三个规范都是为javascript模块化加载而生的,都是在用到或者预计要用到某些模块时候加载该模块,使得大量的系统巨大的庞杂的代码得以很好的组织和管理.模块化使得我们在使用和管理代码的时候不那么混乱,而且也方

前端性能优化:Javascript的加载顺序

文章简介:35条Javascript最佳实践. 相信很多与页面打过交道的同学都对 Yahoo 的 Best Practices for Speeding Up Your Web Site 不陌生.而这 35 条最佳实践中,对 Javascript 的加载顺序的要求是:Put Scripts at the Bottom.因为根据HTTP/1.1 specification 看来,在同一时间加载两个文件是最理想的,而 Javascript 脚本会阻碍平行下载.Steve 说那是 2008 – 200

JavaScript异步加载浅析_javascript技巧

前言 关于JavaScript脚本加载的问题,相信大家碰到很多.主要在几个点-- 1> 同步脚本和异步脚本带来的文件加载.文件依赖及执行顺序问题 2> 同步脚本和异步脚本带来的性能优化问题 深入理解脚本加载相关的方方面面问题,不仅利于解决实际问题,更加利于对性能优化的把握并执行.   先看随便一个script标签代码-- 复制代码 代码如下: <script src="js/myApp.js"></script> 如果放在<head>上面

浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入_javascript技巧

在<浏览器环境下JavaScript脚本加载与执行探析之defer与async特性>中,我们研究了延迟脚本(defer)和异步脚本(async)的执行时机.浏览器支持情况.浏览器bug以及其他的细节问题.而除了defer和async特性,动态脚本和Ajax脚本注入也是两种常用的创建无阻塞脚本的方法.总的来看,这两种方法都能达到脚本加载不影响页面解析和渲染的作用,但是在不同的浏览器中,这两种技术所创建的脚本的执行时机还是有一定差异,今天我们再来探讨一下通过动态脚本技术和Ajax注入的脚本在这些方

浏览器环境下JavaScript脚本加载与执行探析之defer与async特性_javascript技巧

defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异步脚本"的作用.然而,以defer为例,一些细节问题可能开发者却并不一定熟悉,比如:有了defer特性的脚本会延迟到什么时候执行:内部脚本和外部脚本是不是都能够支持defer:defer后的脚本除了会延迟执行之外,还有哪些特殊的地方等等.本文结合已有的一些文章以及MDN文档中对两个特性的阐述,对de

如何实现JavaScript动态加载CSS和JS文件_javascript技巧

项目中需要用到动态加载CSS 文件,整理了一下,顺便融合了动态加载JS 的功能写成了一个对象,先上代码: var dynamicLoading = { css: function(path){ if(!path || path.length === 0){ throw new Error('argument "path" is required !'); } var head = document.getElementsByTagName('head')[0]; var link =

探析浏览器执行JavaScript脚本加载与代码执行顺序_javascript技巧

本文主要基于向HTML页面引入JavaScript的几种方式,分析HTML中JavaScript脚本的执行顺序问题 1. 关于JavaScript脚本执行的阻塞性 JavaScript在浏览器中被解析和执行时具有阻塞的特性,也就是说,当JavaScript代码执行时,页面的解析.渲染以及其他资源的下载都要停下来等待脚本执行完毕①.这一点是没有争议的,并且在所有浏览器中的行为都是一致的,原因也不难理解:浏览器需要一个稳定的DOM结构,而JavaScript可能会修改DOM(改变DOM结构或修改某个

javascript动态加载二_javascript技巧

在上一篇javascript动态加载中,提到了使用同步加载策略这一个方式来实现如 复制代码 代码如下: Using("jquery"); Using("User"); $("#ID").click(function(){ var user = new User(); user.name = "xx"; user.show(); }); 由于JS是单线程的,所以同步策略带来的坏处不少,比如阻止之后的代码运行.造成浏览器假死等问题

混合开发(一)——WebView开发高级技巧之加载网页以及JavaScript,加载进度条

混合开发(一)--WebView开发高级技巧之加载网页以及JavaScript,加载进度条 现在关于混合开发也越来越多了,很多人喜欢跟随,比如HB,比如RN,其实这东西很早就有这么一个概念了,而且说实话,这方面的需求目前来讲,还是只针对一个别的应用的,不过日后会发展成什么样,那我就不知道了,不过在此之前,我们的WebView,还是用的比较多的,包括他浏览新闻,以及加载一些动作,也就是加载JS,这样的话,我们就可以拿出来讲一讲了,说真的,学习android也挺久的了,感觉很多东西,一出来的时候都哇