An open API service indexing awesome lists of open source software.

https://github.com/zachleat/javascript-eval-modules

Playground for testing various dynamic script execution methods in JavaScript
https://github.com/zachleat/javascript-eval-modules

Last synced: 9 months ago
JSON representation

Playground for testing various dynamic script execution methods in JavaScript

Awesome Lists containing this project

README

          

# Dynamic Script Evaluation in JavaScript

You have a `String` of JavaScript code. How can you execute it? This is a playground for testing various dynamic script execution methods in Node.js and what features they support.

This is research for [`import-module-string`](https://github.com/zachleat/import-module-string) (the approach I currently use and recommend for ESM code) and [`node-retrieve-globals`](https://github.com/zachleat/node-retrieve-globals/) (legacy but more CommonJS friendly), whose features I have documented in a separate compatibility table below.

* [`vm` Node.js documentation](https://nodejs.org/docs/latest/api/vm.html)
* [MDN docs for `eval`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)
* [`import("data:…")` approach from `2ality.com`](https://2ality.com/2019/10/eval-via-import.html)
* [`import("blob:…")` approach suggested by David Bushnell](https://github.com/dbushell/dinossr/blob/main/src/bundle/import.ts#L13) (not currently supported in Node.js but works in Deno!)

## Runtime Native Methods



JavaScript Feature
Module#_compile
Function()
vm.Script
vm.Module
import("data:…") (or blob:…)




Assign module.exports (CommonJS-only)
Yes
No
Yes
No5
No


export (ESM-only)
No
No
No
Yes1
Yes


require
Yes
Yes
Yes
Yes1
No6


import (ESM-only)
No4
No4
No4
Yes1
No7


Dynamic import()
Yes
Yes
Yes2
Yes1
No7


Top level async or await
Faux3
Faux3
Faux3
Yes1
Yes


Can leak to global scope
Yes
Yes
No
No
Yes


Runtime Compatibility
Node.js
Any
Node.js
Node.js
Any

Notes:

1. Requires `--experimental-vm-modules`. Use outputs an `ExperimentalWarning` to the console.
2. Requires `vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER` an experimental Node feature added in v21.7.0, v20.12.0. Any use outputs an `ExperimentalWarning` to the console.
3. Requires the code to be wrapped in an `(async () => {})()` IIFE wrapper.
4. Can use `esm-import-transformer` to transform static `import` to dynamic `import()` or `require`: https://github.com/zachleat/esm-import-transformer
5. Probably shimmable but not worth it.
6. `require` is shimmable in Node.js via [`node:module#createRequire`](https://nodejs.org/docs/latest/api/module.html#modulecreaterequirefilename)
7. `import` of runtime built-ins (e.g. `node:` prefixed modules in Node.js) are allowed.

## npm Packages



JavaScript Feature
npm:node-retrieve-globals
npm:import-module-string




Assign module.exports (CommonJS-only)
Yes
No


export (ESM-only)
No
Yes


require
Yes
Yes


import (ESM-only)
No
Yes


Dynamic import()
Yes
Yes


Top level async or await
Faux3
Yes


Can leak to global scope
Yes
Yes


Runtime Compatibility
Node.js
Any

## Alternate methods

* A lot of the pain here is due to an experimental `vm.Module`. If you already have access to a bundler (e.g. `esbuild`), use that to output CommonJS code and run it through `Module#_compile` to bypass current limitations with dynamic ESM in Node.js.
* [Vite writes a temporary file to the filesystem](https://github.com/vitejs/vite/blob/77d5165e2f252bfecbb0eebccc6f04dc8be0c5ba/packages/vite/src/node/config.ts#L1172-L1184) to workaround this issue.
* Some [more discussion on Mastodon](https://fediverse.zachleat.com/@zachleat/111580482330587997).