javascript - 如何在 perl 的 JE 引擎中实现 "JS' s require"函数?

标签 javascript node.js perl

JE是一个用纯 perl 编写的很好的 JavaScript 引擎。完美执行普通 JS 代码,他将 perl 子程序绑定(bind)到 JS 函数的能力非常棒。

require 函数中缺少什么,在“node.js”中实现了什么,并执行与 perl 的 require 类似的任务。

很高兴知道如何在 perl 中实现此类功能并将其绑定(bind)到 JE,例如在简单的骨架中:

use 5.016;
use warnings;
use Path::Tiny;

use JE::Destroyer;
use JE;

my $jslib = path("./jslib");

my $j = new JE;
$j->new_function("say", sub { say @_ });  # the "say" in the JS
$j->new_function("require", sub {         # the "require"

    my $source = $jslib->child($_[0])->slurp_utf8; #read the source from some file
    #how to implement the require ?
    #e.g. what JE object should be created and what to bind to it?

});

知道 node.jsrequire 函数是如何在 C 中实现的,以及如何在 perl 中实现吗?

编辑

对于添加更扩展骨架的更精确示例:

  • 文件./reqtest.js(主程序)
console.log("start");
p = require('adder');
console.log(p.add(2,3));
  • 文件 ./node_modules/adder.js(在“node_modules”中 - 用于 node.js 测试)
exports.add = function() {
    var sum = 0, i = 0, args = arguments, l = args.length;
    while (i < l) {
        sum += args[i++];
    }
    return sum;
};

运行上面的作为

node reqtest.js

打印

start
5

因此,它正确地需要 adder.js 并返回对象,但是 使用以下 perl/JE 脚本运行它:

use 5.016;
use warnings;
use JE::Destroyer;
use JE;
use Scalar::Util qw( weaken );
use Path::Tiny;
use PIR;

my $script = path("reqtest.js")->slurp_utf8;

my $j = new JE;
$j->{console} = {};
$j->{console}->new_function("log", sub { say @_ });
{
    weaken(my $j = $j);
    $j->new_function(require => sub {
        my $source = get_source($_[0]);
        $j->eval($source) if $source;
    });
}

$j->eval($script);#eval the main script

JE::Destroyer::destroy($j);
undef $j;

#extremelly simplyfied
sub get_source {
    my $name = shift;
    return path("node_modules")->child("$name.js")->slurp_utf8;
}

仅打印:

start

因此,require 的“简单$j->eval($source) 实现不遵循CommonJS 模块规范- 它需要更多东西

最佳答案

经过一番研究,我创建了以下(极其简化的)解决方案:

use 5.016;
use warnings;
use JE::Destroyer;
use JE;
use Scalar::Util qw( weaken );
use Path::Tiny;

my $script = path("reqtest.js")->slurp_utf8;

my $j = new JE;
$j->{console} = {};
$j->{console}->new_function("log", sub { say @_ });
{
    weaken(my $j = $j);   #based on ikegami's previous answer
    $j->new_function(require => sub {
        my $source = get_source($_[0]);
        my $code = new JE::Object::Function $j, qw(exports), $source;
        my $exports = $j->{Object};
        $code->($exports);
        return $exports;
    });
}

$j->eval($script);#eval the main script

JE::Destroyer::destroy($j);
undef $j;

# extremelly simplyfied code search
# the real code-search for the requide("some") should try the following
# some.js some/index.js some.json some/index.json
# for the defined search-paths.
sub get_source {
    my $name = shift;
    return path("node_modules")->child("$name.js")->slurp_utf8;
}

上面是 CommonJS 要求的最短可能实现,并且打印与问题中示例的 node.js 相同

start
5

当然,需要很多额外的工作(例如代码缓存)之类的,但最小的框架是可行的。

关于javascript - 如何在 perl 的 JE 引擎中实现 "JS' s require"函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30982898/

相关文章:

Javascript更改服务器给我的时间以匹配另一个时区

javascript - 如何添加Validate()函数?

javascript - 如何删除范围变量中存在的重复项

javascript - 通过 WebCryptoAPI 而不是浏览器化 Node 加密模块在浏览器中生成 ECDH key

javascript - 有没有办法在两个 JavaScript Node 运行之间共享和编辑全局变量?

regex - 我可以在 VIM 或 Perl 的单个正则表达式中替换多个项目吗?

javascript - 为什么 iframe 字体大小根本没有改变?

node.js - 使脚本与浏览器和 Node (npm)一起工作

perl - Perl 数据结构的简单、现代、健壮、透明的持久性

perl - 如何将事务与 Stomp 和 ActiveMQ(和 Perl)一起使用?