diff --git a/README.md b/README.md index 0c9f27b33..4aeb78672 100644 --- a/README.md +++ b/README.md @@ -529,6 +529,10 @@ Space-delimited list of hosts or socket paths which should be denied for network Set a timeout in seconds for idle sockets being kept-alive. Default timeout is 15 seconds +### `LLRT_PLATFORM=value` + +Used to explicitly specify a preferred platform for the Node.js package resolver. The default is `browser`. If `node` is specified, "node" takes precedence in the search path. If a value other than `browser` or `node` is specified, it will behave as if "browser" was specified. + ### `LLRT_TLS_VERSION=value` Set the TLS version to be used for network connections. By default only TLS 1.2 is enabled. TLS 1.3 can also be enabled by setting this variable to `1.3` diff --git a/llrt_core/src/environment.rs b/llrt_core/src/environment.rs index f7560f27d..5c2af4dad 100644 --- a/llrt_core/src/environment.rs +++ b/llrt_core/src/environment.rs @@ -12,5 +12,8 @@ pub const ENV_LLRT_EXTRA_CA_CERTS: &str = "LLRT_EXTRA_CA_CERTS"; //log pub const ENV_LLRT_LOG: &str = "LLRT_LOG"; +//module +pub const ENV_LLRT_PLATFORM: &str = "LLRT_PLATFORM"; + //vm pub const ENV_LLRT_GC_THRESHOLD_MB: &str = "LLRT_GC_THRESHOLD_MB"; diff --git a/llrt_core/src/module_loader/loader.rs b/llrt_core/src/module_loader/loader.rs index 574d5ccf1..520dbf037 100644 --- a/llrt_core/src/module_loader/loader.rs +++ b/llrt_core/src/module_loader/loader.rs @@ -1,3 +1,5 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 use once_cell::sync::Lazy; use rquickjs::{loader::Loader, Ctx, Function, Module, Object, Result, Value}; use std::{ diff --git a/llrt_core/src/module_loader/mod.rs b/llrt_core/src/module_loader/mod.rs index 26f3cc2b0..de93d7e0f 100644 --- a/llrt_core/src/module_loader/mod.rs +++ b/llrt_core/src/module_loader/mod.rs @@ -1,3 +1,11 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::env; + +use once_cell::sync::Lazy; + +use crate::environment; + pub mod loader; pub mod resolver; @@ -5,3 +13,10 @@ pub mod resolver; pub const CJS_IMPORT_PREFIX: &str = "__cjs:"; // added to force CJS imports in loader pub const CJS_LOADER_PREFIX: &str = "__cjsm:"; + +pub static LLRT_PLATFORM: Lazy = Lazy::new(|| { + env::var(environment::ENV_LLRT_PLATFORM) + .ok() + .filter(|platform| platform == "node") + .unwrap_or_else(|| "browser".to_string()) +}); diff --git a/llrt_core/src/module_loader/resolver.rs b/llrt_core/src/module_loader/resolver.rs index 5d9fdb4bd..5c4ea7b5d 100644 --- a/llrt_core/src/module_loader/resolver.rs +++ b/llrt_core/src/module_loader/resolver.rs @@ -24,7 +24,7 @@ use crate::{ utils::io::{is_supported_ext, JS_EXTENSIONS, SUPPORTED_EXTENSIONS}, }; -use super::CJS_IMPORT_PREFIX; +use super::{CJS_IMPORT_PREFIX, LLRT_PLATFORM}; include!(concat!(env!("OUT_DIR"), "/bytecode_cache.rs")); @@ -433,7 +433,8 @@ fn load_package_imports(ctx: &Ctx<'_>, x: &str, dir: &str) -> Result( let (module_path, is_cjs) = package_exports_resolve(&package_json, name, is_esm)?; - let module_path = correct_extensions([dir, "/", scope, "/", module_path].concat()); + let module_path = to_abs_path(correct_extensions( + [dir, "/", scope, "/", module_path].concat(), + ))?; + let prefix = if is_cjs && is_esm { CJS_LOADER_PREFIX } else { @@ -584,9 +588,9 @@ fn package_exports_resolve<'a>( if let Some(BorrowedValue::Object(exports)) = map.get("exports") { if let Some(BorrowedValue::Object(name)) = exports.get(modules_name) { - // Check for exports -> name -> browser -> [import | require] - if let Some(BorrowedValue::Object(browser)) = name.get("browser") { - if let Some(BorrowedValue::String(ident)) = browser.get(ident) { + // Check for exports -> name -> platform(browser or node) -> [import | require] + if let Some(BorrowedValue::Object(platform)) = name.get(LLRT_PLATFORM.as_str()) { + if let Some(BorrowedValue::String(ident)) = platform.get(ident) { return Ok((ident.as_ref(), is_cjs)); } } @@ -624,9 +628,9 @@ fn package_exports_resolve<'a>( } } } - // Check for browser field - if let Some(BorrowedValue::String(browser)) = map.get("browser") { - return Ok((browser.as_ref(), is_cjs)); + // Check for platform(browser or node) field + if let Some(BorrowedValue::String(platform)) = map.get(LLRT_PLATFORM.as_str()) { + return Ok((platform.as_ref(), is_cjs)); } // [ESM only] Check for module field if is_esm { @@ -650,6 +654,10 @@ fn package_imports_resolve<'a>( if let BorrowedValue::Object(map) = package_json { if let Some(BorrowedValue::Object(imports)) = map.get("imports") { if let Some(BorrowedValue::Object(name)) = imports.get(modules_name) { + // Check for imports -> name -> platform(browser or node) + if let Some(BorrowedValue::String(platform)) = name.get(LLRT_PLATFORM.as_str()) { + return Some(platform.as_ref()); + } // Check for imports -> name -> require if let Some(BorrowedValue::String(require)) = name.get("require") { return Some(require.as_ref());