v8js icon indicating copy to clipboard operation
v8js copied to clipboard

Support for ES Modules

Open joehoyle opened this issue 4 years ago • 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?

joehoyle avatar Nov 25 '20 20:11 joehoyle

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! 😄

chrisbckr avatar Feb 20 '23 19:02 chrisbckr

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.

redbullmarky avatar Feb 20 '23 21:02 redbullmarky

@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)());

redbullmarky avatar Feb 20 '23 21:02 redbullmarky

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.

chrisbckr avatar Feb 21 '23 00:02 chrisbckr

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)

joehoyle avatar Feb 21 '23 06:02 joehoyle

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

chrisbckr avatar Feb 22 '23 11:02 chrisbckr