Coder Social home page Coder Social logo

Question: Module support about php-v8 HOT 5 CLOSED

phpv8 avatar phpv8 commented on July 22, 2024
Question: Module support

from php-v8.

Comments (5)

pinepain avatar pinepain commented on July 22, 2024

Hi Sebastian, thanks for writing!

It would be nice to see your wrapper as I also have a one, though, it's heavily in progress at this time and I don't publish it to github yet.

As to modules, there are two types of it from API perspective: native and source-based module. With a native one it's pretty simple: you return some value for require() call.

With source-based you may follow simple path: populate context's global object with necessary exports, require, module variable and then return modules.exports result or you can do like node.js does - wrap module source code and evaluate it with passing necessary values for exports, require, module and so on.

As for caching, it's pretty trivial, just maintain an array of normalized module name to what it exports and on consecutive calls return that value. This is how node.js does afair.

Here is very basic require() implementation I use in one of tests - tests/V8FunctionTemplate_require_implementation.phpt

from php-v8.

pinepain avatar pinepain commented on July 22, 2024

Closing this issue for now as it not much to do at this time with it. If you feels there is something we missed here - please, drop a comment or feels free to open a new issue.

I'm also working on a library for php-v8 which also provides node-like modules functionality, however, no ETA at this time.

from php-v8.

aight8 avatar aight8 commented on July 22, 2024

Sorry for the late response. Thanks for the explanation, I see it's little bit more work than expected. I saw the the parallel v8 extension for php that they had a hook function which get the requested module as string passed and you have to return the code/path (don't know anymore). But I thought v8 do a little bit more since it's "module" flag.

I will post the wrapper ASAP here.

from php-v8.

pinepain avatar pinepain commented on July 22, 2024

The simplest implementation for require() is available in tests/V8FunctionTemplate_require_implementation.phpt:26:41. While php-v8 is more low-level than v8js, there is a bit more to do pass data back to v8 runtime, but basically, if you replace tests/V8FunctionTemplate_require_implementation.phpt:33:37 with calling your external function, you should get very similar behavior to v8js.

I guess something like this should do the job:

Note, this is meta-code which may need to be polished in order to work

use V8\Value;
use V8\Context;
use V8\NumberValue;
use V8\StringValue;
use V8\ObjectValue;
use V8\Script;
use V8\ScriptOrigin;
use V8\FunctionTemplate;
use V8\FunctionCallbackInfo;

interface ModuleLoaderInterface {
    public function load(string $name, Context $context) : Value;
}

class ModuleLoader implements ModuleLoaderInterface {
    public function load(string $name, Context $context): Value
    {
        $isolate = $context->GetIsolate();

        $module_is_native = 'TODO'; // figure it out

        // here you can actually evaluate your script
        if ($module_is_native) {
            // in real life you will normally build necessary v8 value and return it
            return new NumberValue($isolate, 42);
        }

        $path = $name;
        $source = 'TODO'; // you will actually get it somehow from your db, filesystem or so

        $wrapped_source =
            "(function (exports, require, module, __filename, __dirname) {\n" .
            $source . // you will actually get it somehow from your db, filesystem or so
            "\n});";

        $script = new Script($context, new StringValue($isolate, $wrapped_source), new ScriptOrigin($path, -1));

        $func = $script->Run($context);

        $exports = new ObjectValue($context);
        $module_obj = new ObjectValue($context);  // you actually have to build it properly - https://nodejs.org/api/modules.html#modules_the_module_object
        $require = $context->GlobalObject()->Get($context, new StringValue($isolate, 'require');
        $filename = new StringValue($isolate, $path);
        $dirname = new StringValue($isolate, dirname($path));

        // exports, require, module, __filename, __dirname
        $arguments = [$exports, $require, $module_obj, $filename, $dirname];

        return $func->Call($context, $func, $arguments);
    }
}

$loader = new ModuleLoader();

$require_func_tpl_cache = new FunctionTemplate($isolate, function (FunctionCallbackInfo $info) use (&$loaded_cache, &$code, $loader) {
    $context = $info->GetContext();
    $module = $info->Arguments()[0]->ToString($context)->Value();
    if (!isset($loaded_cache[$module])) {
        $loaded_cache[$module] = $loader->load($module, $context);
    }
    $info->GetReturnValue()->Set($loaded_cache[$module]);
});

or even

class CacheableModuleLoader implements ModuleLoaderInterface
{
    /**
     * @var Value[]
     */
    private $cache = [];
    /**
     * @var ModuleLoaderInterface
     */
    private $loader;

    public function __construct(ModuleLoaderInterface $loader)
    {
        $this->loader = $loader;
    }

    public function load(string $name, Context $context): Value
    {
        if (!isset($this->cache[$name])) {
            $this->cache[$name] = $this->loader->load($name, $context);
        }
        
        return $this->cache[$name];
    }
}

$loader = new CacheableModuleLoader(new ModuleLoader());

$require_func_tpl_cache = new FunctionTemplate($isolate, function (FunctionCallbackInfo $info) use (&$loaded_cache, &$code, $loader) {
    $context = $info->GetContext();
    $module = $info->Arguments()[0]->ToString($context)->Value();
    
    $info->GetReturnValue()->Set($loader->load($module, $context));
});

from php-v8.

pinepain avatar pinepain commented on July 22, 2024

Thank you for bringing up this question. I plan to release higher level wrapper for php-v8 which should include modules support, so I'm closing this issue for now.

from php-v8.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.