phpv8/v8js

Support for ES Modules

joehoyle opened this issue ยท 6 comments

I believe recent versions of V8 have native support for ESM modules (https://v8.dev/features/modules). I don't think this is bridged to V8Js via the setModuleLoader though (which perhaps just does something like provide a require function declaration to the JS runtime).

Reading https://stackoverflow.com/questions/52023157/how-would-one-enable-and-use-es6-modules-in-the-v8-javascript-engine, it looks like this is a new set of APIs on the V8 API. So, would this be possible to integrate into v8js?

NodeJS uses the ".mjs" file extension, the package.json "type" field, or the --input-type flag. How this can be implemented? V8Js::executeModule()?
And if after that I call V8Js::executeScript()? It's possible? Every module has their unique context. They will share the context of the scripts that are executed with V8JS::executeScript() like browsers do?

Just throwing some thoughts about how this can be implemented! ๐Ÿ˜„

It feels like the only way to implement it natively would be to essentially treat the initial executed code as a module itself, so that import would work similar to require Perhaps wrapping the executed code with an internal entry script of sorts.

I managed to get something working a year or two back, albeit using babel to transpile code before executing. Just not in a native way.

@chrisbckr This was part of the original test I played around with:

<?php
// requires babel standalone from here:
// https://github.com/babel/babel-standalone
$v8 = new \V8Js();

// code to transpile
$v8->sourceCode = <<<EOF
import * as stuff from './foo';

a = () => {
    print("hello there from inside an arrow function!!...");
    return "return value from a function";
}
EOF;

// actual transpiler code
$script = <<<EOF
Babel.transform(PHP.sourceCode, {presets:['es2015']}).code;
EOF;

// include babel & execute our transpiler
$v8->executeString(file_get_contents(__DIR__ . '/babel.min.js'));
$transpiled = $v8->executeString($script);

// v8js's return mechanism and 'strict' mode...V8Js's return mechanism requires 
// assigning to an undefined variable.
$transpiled = str_replace('"use strict"', '', $transpiled);

echo "TRANSPILED TO:\n\n" . $transpiled . "\n\n\n";
echo "-----------\nEXECUTING:\n\n";

// now execute the transpiled code
$v8 = new \V8Js();
$v8->setModuleLoader(function($filename) { 
   print("Loading {$filename} via ES6 module...\n"); 
});
print_r($v8->executeString($transpiled)());

I will look on this to use here for now, I really liked. Today I have typescript compiler embedded, like deno do. ๐Ÿ˜…
So, why not babel? ๐Ÿ˜†

But to run es6 modules on v8 it's a little different than "normal" scripts, maybe some of the commonjs implementation can be reused but with de v8's module calls.

FYI I've also / mostly moved work from v8js to php-deno (https://github.com/joehoyle/php-deno) which has support for Es6 modules natively (and also have the TypeScript compiler via swc embedded)

I implemented a basic compileModuleString, executeModule and executeModuleString.
Lacks imports resolution. It just return the referrer module itself for testing purposes.
If someone is interested, my code is here:
https://github.com/chrisbckr/v8js/tree/php8-es6_modules