mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
fix(ext/node): basic vm.runInNewContext implementation (#21527)
Simple implementation to support webpack (& Next.js):
8766092180/lib/javascript/JavascriptParser.js (L4329)
This commit is contained in:
parent
0bee37a5e2
commit
02e138dca9
6 changed files with 131 additions and 7 deletions
|
@ -82,6 +82,7 @@ util::unit_test_factory!(
|
||||||
tty_test,
|
tty_test,
|
||||||
util_test,
|
util_test,
|
||||||
v8_test,
|
v8_test,
|
||||||
|
vm_test,
|
||||||
worker_threads_test,
|
worker_threads_test,
|
||||||
zlib_test
|
zlib_test
|
||||||
]
|
]
|
||||||
|
|
57
cli/tests/unit_node/vm_test.ts
Normal file
57
cli/tests/unit_node/vm_test.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
import { runInNewContext } from "node:vm";
|
||||||
|
import {
|
||||||
|
assertEquals,
|
||||||
|
assertThrows,
|
||||||
|
} from "../../../test_util/std/assert/mod.ts";
|
||||||
|
|
||||||
|
Deno.test({
|
||||||
|
name: "vm runInNewContext",
|
||||||
|
fn() {
|
||||||
|
const two = runInNewContext("1 + 1");
|
||||||
|
assertEquals(two, 2);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test({
|
||||||
|
name: "vm runInNewContext sandbox",
|
||||||
|
fn() {
|
||||||
|
assertThrows(() => runInNewContext("Deno"));
|
||||||
|
// deno-lint-ignore no-var
|
||||||
|
var a = 1;
|
||||||
|
assertThrows(() => runInNewContext("a + 1"));
|
||||||
|
|
||||||
|
runInNewContext("a = 2");
|
||||||
|
assertEquals(a, 1);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/webpack/webpack/blob/87660921808566ef3b8796f8df61bd79fc026108/lib/javascript/JavascriptParser.js#L4329
|
||||||
|
Deno.test({
|
||||||
|
name: "vm runInNewContext webpack magic comments",
|
||||||
|
fn() {
|
||||||
|
const webpackCommentRegExp = new RegExp(
|
||||||
|
/(^|\W)webpack[A-Z]{1,}[A-Za-z]{1,}:/,
|
||||||
|
);
|
||||||
|
const comments = [
|
||||||
|
'webpackChunkName: "test"',
|
||||||
|
'webpackMode: "lazy"',
|
||||||
|
"webpackPrefetch: true",
|
||||||
|
"webpackPreload: true",
|
||||||
|
"webpackProvidedExports: true",
|
||||||
|
'webpackChunkLoading: "require"',
|
||||||
|
'webpackExports: ["default", "named"]',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const comment of comments) {
|
||||||
|
const result = webpackCommentRegExp.test(comment);
|
||||||
|
assertEquals(result, true);
|
||||||
|
|
||||||
|
const [[key, _value]]: [string, string][] = Object.entries(
|
||||||
|
runInNewContext(`(function(){return {${comment}};})()`),
|
||||||
|
);
|
||||||
|
const expectedKey = comment.split(":")[0].trim();
|
||||||
|
assertEquals(key, expectedKey);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
|
@ -30,6 +30,7 @@ mod path;
|
||||||
mod polyfill;
|
mod polyfill;
|
||||||
mod resolution;
|
mod resolution;
|
||||||
|
|
||||||
|
pub use ops::v8::VM_CONTEXT_INDEX;
|
||||||
pub use package_json::PackageJson;
|
pub use package_json::PackageJson;
|
||||||
pub use path::PathClean;
|
pub use path::PathClean;
|
||||||
pub use polyfill::is_builtin_node_module;
|
pub use polyfill::is_builtin_node_module;
|
||||||
|
@ -243,6 +244,7 @@ deno_core::extension!(deno_node,
|
||||||
ops::winerror::op_node_sys_to_uv_error,
|
ops::winerror::op_node_sys_to_uv_error,
|
||||||
ops::v8::op_v8_cached_data_version_tag,
|
ops::v8::op_v8_cached_data_version_tag,
|
||||||
ops::v8::op_v8_get_heap_statistics,
|
ops::v8::op_v8_get_heap_statistics,
|
||||||
|
ops::v8::op_vm_run_in_new_context,
|
||||||
ops::idna::op_node_idna_domain_to_ascii,
|
ops::idna::op_node_idna_domain_to_ascii,
|
||||||
ops::idna::op_node_idna_domain_to_unicode,
|
ops::idna::op_node_idna_domain_to_unicode,
|
||||||
ops::idna::op_node_idna_punycode_decode,
|
ops::idna::op_node_idna_punycode_decode,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
use deno_core::error::AnyError;
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::v8;
|
use deno_core::v8;
|
||||||
|
|
||||||
|
@ -30,3 +31,50 @@ pub fn op_v8_get_heap_statistics(
|
||||||
buffer[12] = stats.used_global_handles_size() as f64;
|
buffer[12] = stats.used_global_handles_size() as f64;
|
||||||
buffer[13] = stats.external_memory() as f64;
|
buffer[13] = stats.external_memory() as f64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const VM_CONTEXT_INDEX: usize = 0;
|
||||||
|
|
||||||
|
fn make_context<'a>(
|
||||||
|
scope: &mut v8::HandleScope<'a>,
|
||||||
|
) -> v8::Local<'a, v8::Context> {
|
||||||
|
let scope = &mut v8::EscapableHandleScope::new(scope);
|
||||||
|
let context = v8::Context::from_snapshot(scope, VM_CONTEXT_INDEX).unwrap();
|
||||||
|
scope.escape(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[op2]
|
||||||
|
pub fn op_vm_run_in_new_context<'a>(
|
||||||
|
scope: &mut v8::HandleScope<'a>,
|
||||||
|
script: v8::Local<v8::String>,
|
||||||
|
ctx_val: v8::Local<v8::Value>,
|
||||||
|
) -> Result<v8::Local<'a, v8::Value>, AnyError> {
|
||||||
|
let _ctx_obj = if ctx_val.is_undefined() || ctx_val.is_null() {
|
||||||
|
v8::Object::new(scope)
|
||||||
|
} else {
|
||||||
|
ctx_val.try_into()?
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctx = make_context(scope);
|
||||||
|
|
||||||
|
let scope = &mut v8::ContextScope::new(scope, ctx);
|
||||||
|
|
||||||
|
let tc_scope = &mut v8::TryCatch::new(scope);
|
||||||
|
let script = match v8::Script::compile(tc_scope, script, None) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => {
|
||||||
|
assert!(tc_scope.has_caught());
|
||||||
|
tc_scope.rethrow();
|
||||||
|
return Ok(v8::undefined(tc_scope).into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(match script.run(tc_scope) {
|
||||||
|
Some(result) => result,
|
||||||
|
None => {
|
||||||
|
assert!(tc_scope.has_caught());
|
||||||
|
tc_scope.rethrow();
|
||||||
|
|
||||||
|
v8::undefined(tc_scope).into()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import { notImplemented } from "ext:deno_node/_utils.ts";
|
import { notImplemented } from "ext:deno_node/_utils.ts";
|
||||||
|
|
||||||
const { core } = globalThis.__bootstrap;
|
const { core } = globalThis.__bootstrap;
|
||||||
|
const ops = core.ops;
|
||||||
|
|
||||||
export class Script {
|
export class Script {
|
||||||
code: string;
|
code: string;
|
||||||
|
@ -25,8 +26,13 @@ export class Script {
|
||||||
notImplemented("Script.prototype.runInContext");
|
notImplemented("Script.prototype.runInContext");
|
||||||
}
|
}
|
||||||
|
|
||||||
runInNewContext(_contextObject: any, _options: any) {
|
runInNewContext(contextObject: any, options: any) {
|
||||||
notImplemented("Script.prototype.runInNewContext");
|
if (options) {
|
||||||
|
console.warn(
|
||||||
|
"Script.runInNewContext options are currently not supported",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ops.op_vm_run_in_new_context(this.code, contextObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
createCachedData() {
|
createCachedData() {
|
||||||
|
@ -51,11 +57,14 @@ export function runInContext(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runInNewContext(
|
export function runInNewContext(
|
||||||
_code: string,
|
code: string,
|
||||||
_contextObject: any,
|
contextObject: any,
|
||||||
_options: any,
|
options: any,
|
||||||
) {
|
) {
|
||||||
notImplemented("runInNewContext");
|
if (options) {
|
||||||
|
console.warn("vm.runInNewContext options are currently not supported");
|
||||||
|
}
|
||||||
|
return ops.op_vm_run_in_new_context(code, contextObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runInThisContext(
|
export function runInThisContext(
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::shared::runtime;
|
||||||
use deno_cache::SqliteBackedCache;
|
use deno_cache::SqliteBackedCache;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::snapshot_util::*;
|
use deno_core::snapshot_util::*;
|
||||||
|
use deno_core::v8;
|
||||||
use deno_core::Extension;
|
use deno_core::Extension;
|
||||||
use deno_http::DefaultHttpPropertyExtractor;
|
use deno_http::DefaultHttpPropertyExtractor;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -261,7 +262,13 @@ pub fn create_runtime_snapshot(
|
||||||
startup_snapshot: None,
|
startup_snapshot: None,
|
||||||
extensions,
|
extensions,
|
||||||
compression_cb: None,
|
compression_cb: None,
|
||||||
with_runtime_cb: None,
|
with_runtime_cb: Some(Box::new(|rt| {
|
||||||
|
let isolate = rt.v8_isolate();
|
||||||
|
let scope = &mut v8::HandleScope::new(isolate);
|
||||||
|
|
||||||
|
let ctx = v8::Context::new(scope);
|
||||||
|
assert_eq!(scope.add_context(ctx), deno_node::VM_CONTEXT_INDEX);
|
||||||
|
})),
|
||||||
skip_op_registration: false,
|
skip_op_registration: false,
|
||||||
});
|
});
|
||||||
for path in output.files_loaded_during_snapshot {
|
for path in output.files_loaded_during_snapshot {
|
||||||
|
|
Loading…
Reference in a new issue