为 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
目录
相关文章
|
3月前
|
缓存 JavaScript 前端开发
高效打造跨平台桌面应用:Electron加载服务器端JS
【9月更文挑战第17天】Electron 是一个基于 Chromium 和 Node.js 的开源框架,允许使用 HTML、CSS 和 JavaScript 构建跨平台桌面应用。加载服务器端 JS 可增强应用灵活性,实现代码复用、动态更新及实时通信。通过 HTTP 请求、WebSocket 或文件系统可实现加载,但需注意安全性、性能和兼容性问题。开发者应根据需求选择合适方法并谨慎实施。
144 3
|
3月前
|
JavaScript UED
js之模块化(2)
js之模块化(2)
|
4月前
|
JavaScript 前端开发 编译器
解锁JavaScript模块化编程新纪元:从CommonJS的基石到ES Modules的飞跃,探索代码组织的艺术与科学
【8月更文挑战第27天】随着Web应用复杂度的提升,JavaScript模块化编程变得至关重要,它能有效降低代码耦合度并提高项目可维护性及扩展性。从CommonJS到ES Modules,模块化标准经历了显著的发展。CommonJS最初专为服务器端设计,通过`require()`同步加载模块。而ES Modules作为官方标准,支持异步加载,更适合浏览器环境,并且能够进行静态分析以优化性能。这两种标准各有特色,但ES Modules凭借其更广泛的跨平台兼容性和现代语法逐渐成为主流。这一演进不仅标志着JavaScript模块化的成熟,也反映了整个JavaScript生态系统的不断完善。
53 3
|
16天前
|
缓存 前端开发 JavaScript
优化CSS和JavaScript加载
Next.js和Nuxt.js在优化CSS和JavaScript加载方面提供了多种策略和工具。Next.js通过代码拆分、图片优化和特定的CSS/JavaScript优化措施提升性能;Nuxt.js则通过代码分割、懒加载、预渲染静态页面、Webpack配置和服务端缓存来实现优化。两者均能有效提高应用性能。
|
3月前
|
JavaScript 前端开发 开发者
js之模块化(1)
js之模块化(1)
|
2月前
|
缓存 JavaScript 前端开发
Node.js模块化的基本概念和分类及使用方法
Node.js模块化的基本概念和分类及使用方法
36 0
|
3月前
|
JavaScript
js之模块化(3)
js之模块化(3)
|
4月前
|
编解码 缓存 算法
Three.js如何降低3D模型的大小以便更快加载
为加快600MB的3D模型在Three.js中的加载速度,可采用多种压缩方法:1) 减少顶点数,使用简化工具或LOD技术;2) 压缩纹理,降低分辨率或转为KTX2等格式;3) 采用高效文件格式如glTF 2.0及draco压缩;4) 合并材质减少数量;5) 利用Three.js内置优化如BufferGeometry;6) 按需分批加载模型;7) Web Workers后台处理;8) 多模型合并减少绘制;9) 使用Texture Atlas及专业优化工具。示例代码展示了使用GLTFLoader加载优化后的模型。
449 12
|
4月前
|
前端开发 JavaScript
前端必会的JavaScript模块化
【8月更文挑战第3天】JavaScript模块化
31 1
|
4月前
|
前端开发 JavaScript Linux
【Azure 应用服务】在Azure App Service for Linux环境中,部署的Django应用,出现加载css、js等静态资源文件失败
【Azure 应用服务】在Azure App Service for Linux环境中,部署的Django应用,出现加载css、js等静态资源文件失败