Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions crates/base/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@ where
let base_dir_path =
std::env::current_dir().map(|p| p.join(&service_path))?;

let maybe_import_map_path = context
.get("importMapPath")
.and_then(|it| it.as_str())
.map(str::to_string);

let eszip = if let Some(eszip_payload) = maybe_eszip {
eszip_payload
} else {
Expand Down Expand Up @@ -563,6 +568,7 @@ where
CacheSetting::Use
};

emitter_factory.set_import_map_path(maybe_import_map_path.clone());
emitter_factory
.set_permissions_options(Some(permissions_options.clone()));

Expand Down Expand Up @@ -631,10 +637,6 @@ where
.get("sourceMap")
.and_then(serde_json::Value::as_bool)
.unwrap_or_default();
let maybe_import_map_path = context
.get("importMapPath")
.and_then(|it| it.as_str())
.map(str::to_string);

let rt_provider = create_module_loader_for_standalone_from_eszip_kind(
eszip,
Expand Down
3 changes: 3 additions & 0 deletions crates/base/test_cases/user-worker-with-import-map/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function getHelperMessage(): string {
return "import map works!";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"imports": {
"helper-from-import-map": "./helper.ts"
}
}
40 changes: 40 additions & 0 deletions crates/base/test_cases/user-worker-with-import-map/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as path from "jsr:@std/path";

Deno.serve(async (req: Request) => {
const basePath = "test_cases/user-worker-with-import-map";
const url = new URL(req.url);
const { pathname } = url;

const userWorkerPath = path.join(basePath, "user_worker");
if (pathname === "/import_map") {
const worker = await EdgeRuntime.userWorkers.create({
servicePath: userWorkerPath,
forceCreate: true,
context: {
importMapPath: path.join(basePath, "import_map.json"),
},
});
return worker.fetch(req);
}
if (pathname === "/inline_import_map") {
const inlineImportMap = {
imports: {
"helper-from-import-map": `./${path.join(basePath, "helper.ts")}`,
},
};
const importMapPath = `data:${
encodeURIComponent(JSON.stringify(inlineImportMap))
}`;

const worker = await EdgeRuntime.userWorkers.create({
servicePath: userWorkerPath,
forceCreate: true,
context: {
importMapPath: importMapPath,
},
});
return worker.fetch(req);
}

return new Response("Not Found", { status: 404 });
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getHelperMessage } from "helper-from-import-map";

Deno.serve((_req: Request) => {
return new Response(
JSON.stringify({
message: getHelperMessage(),
success: true,
}),
{
headers: {
"Content-Type": "application/json",
Connection: "keep-alive",
},
},
);
});
50 changes: 49 additions & 1 deletion crates/base/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ use base::server::ServerEvent;
use base::server::ServerFlags;
use base::server::ServerHealth;
use base::server::Tls;
use base::utils::test_utils;
use base::utils::test_utils::create_test_user_worker;
use base::utils::test_utils::ensure_npm_package_installed;
use base::utils::test_utils::test_user_runtime_opts;
use base::utils::test_utils::test_user_worker_pool_policy;
use base::utils::test_utils::TestBedBuilder;
use base::utils::test_utils::{self};
use base::worker;
use base::worker::TerminationToken;
use base::WorkerKind;
Expand Down Expand Up @@ -4095,6 +4095,54 @@ async fn test_user_workers_cleanup_idle_workers() {
unreachable!("test failed");
}

#[tokio::test]
#[serial]
async fn test_user_worker_with_import_map() {
let assert_fn = |resp: Result<Response, reqwest::Error>| async {
let res = resp.unwrap();
let status = res.status().as_u16();

let body_bytes = res.bytes().await.unwrap();
let body_str = String::from_utf8_lossy(&body_bytes);

assert_eq!(
status, 200,
"Expected 200, got {} with body: {}",
status, body_str
);

assert!(
body_str.contains("import map works!"),
"Expected import map works!, got: {}",
body_str
);
};
{
integration_test!(
"./test_cases/user-worker-with-import-map",
NON_SECURE_PORT,
"import_map",
None,
None,
None,
(assert_fn),
TerminationToken::new()
);
}
{
integration_test!(
"./test_cases/user-worker-with-import-map",
NON_SECURE_PORT,
"inline_import_map",
None,
None,
None,
(assert_fn),
TerminationToken::new()
);
}
}

#[derive(Deserialize)]
struct ErrorResponsePayload {
msg: String,
Expand Down
12 changes: 12 additions & 0 deletions crates/deno_facade/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ use ext_node::DenoFsNodeResolverEnv;
use ext_node::NodeResolver;
use ext_node::PackageJsonResolver;

use crate::import_map::load_import_map;
use crate::permissions::RuntimePermissionDescriptorParser;

struct Deferred<T>(once_cell::unsync::OnceCell<T>);
Expand Down Expand Up @@ -120,6 +121,7 @@ pub struct EmitterFactory {
sloppy_imports_resolver: Deferred<Option<Arc<CliSloppyImportsResolver>>>,
workspace_resolver: Deferred<Arc<WorkspaceResolver>>,

import_map_path: Option<String>,
cache_strategy: Option<CacheSetting>,
deno_dir: DenoDir,
deno_options: Option<Arc<DenoOptions>>,
Expand Down Expand Up @@ -160,6 +162,7 @@ impl EmitterFactory {
sloppy_imports_resolver: Default::default(),
workspace_resolver: Default::default(),

import_map_path: Default::default(),
cache_strategy: None,
deno_dir,
deno_options: None,
Expand All @@ -180,6 +183,11 @@ impl EmitterFactory {
self
}

pub fn set_import_map_path(&mut self, value: Option<String>) -> &mut Self {
self.import_map_path = value;
self
}

pub fn set_cache_strategy(
&mut self,
value: Option<CacheSetting>,
Expand Down Expand Up @@ -528,8 +536,12 @@ impl EmitterFactory {
) -> Result<&Arc<WorkspaceResolver>, anyhow::Error> {
self.workspace_resolver.get_or_try_init(|| {
let options = self.deno_options()?;
let specified_import_map =
load_import_map(self.import_map_path.as_deref())?;

let resolver = options.create_workspace_resolver(
self.file_fetcher()?,
specified_import_map,
if options.use_byonm() {
PackageJsonDepResolution::Disabled
} else {
Expand Down
29 changes: 16 additions & 13 deletions crates/deno_facade/import_map.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use anyhow::anyhow;
use anyhow::Error;
use deno_config::workspace::SpecifiedImportMap;
use deno_core::serde_json;
use deno_core::url::Url;
use import_map::parse_from_json;
use import_map::ImportMap;
use urlencoding::decode;

use std::fs;
use std::path::Path;
use urlencoding::decode;

pub fn load_import_map(
maybe_path: Option<String>,
) -> Result<Option<ImportMap>, Error> {
maybe_path: Option<&str>,
) -> Result<Option<SpecifiedImportMap>, Error> {
if let Some(path_str) = maybe_path {
let json_str;
let base_url;
Expand All @@ -19,12 +18,15 @@ pub fn load_import_map(
// the data URI takes the following format
// data:{encodeURIComponent(mport_map.json)?{encodeURIComponent(base_path)}
if path_str.starts_with("data:") {
let data_uri = Url::parse(&path_str)?;
let data_uri = Url::parse(path_str)?;
json_str = decode(data_uri.path())?.into_owned();
base_url = Url::from_directory_path(
decode(data_uri.query().unwrap_or(""))?.into_owned(),
)
.map_err(|_| anyhow!("invalid import map base url"))?;
if let Some(query) = data_uri.query() {
base_url = Url::from_directory_path(decode(query)?.into_owned())
.map_err(|_| anyhow!("invalid import map base url"))?;
} else {
base_url = Url::from_directory_path(std::env::current_dir().unwrap())
.map_err(|_| anyhow!("invalid import map base url"))?;
}
} else {
let path = Path::new(&path_str);
let abs_path = std::env::current_dir().map(|p| p.join(path))?;
Expand All @@ -33,8 +35,9 @@ pub fn load_import_map(
.map_err(|_| anyhow!("invalid import map base url"))?;
}

let result = parse_from_json(base_url, json_str.as_str())?;
Ok(Some(result.import_map))
let value = serde_json::from_str(&json_str)?;

Ok(Some(SpecifiedImportMap { base_url, value }))
} else {
Ok(None)
}
Expand Down
4 changes: 3 additions & 1 deletion deno/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use deno_config::deno_json::TsConfigForEmit;
use deno_config::deno_json::TsConfigType;
use deno_config::workspace::CreateResolverOptions;
use deno_config::workspace::PackageJsonDepResolution;
use deno_config::workspace::SpecifiedImportMap;
use deno_config::workspace::VendorEnablement;
use deno_config::workspace::WorkspaceDirectory;
use deno_config::workspace::WorkspaceDirectoryEmptyOptions;
Expand Down Expand Up @@ -199,12 +200,13 @@ impl DenoOptions {
pub fn create_workspace_resolver(
&self,
_file_fetcher: &FileFetcher,
specified_import_map: Option<SpecifiedImportMap>,
pkg_json_dep_resolution: PackageJsonDepResolution,
) -> Result<WorkspaceResolver, AnyError> {
Ok(self.workspace().create_resolver(
CreateResolverOptions {
pkg_json_dep_resolution,
specified_import_map: None,
specified_import_map,
},
|path| Ok(std::fs::read_to_string(path)?),
)?)
Expand Down
Loading