Skip to content

Commit 4bdc448

Browse files
0x5457nyannyacha
authored andcommitted
feat(import-map): add support for import maps in user workers
1 parent 13d6282 commit 4bdc448

File tree

9 files changed

+146
-18
lines changed

9 files changed

+146
-18
lines changed

crates/base/src/runtime/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,11 @@ where
517517
let base_dir_path =
518518
std::env::current_dir().map(|p| p.join(&service_path))?;
519519

520+
let maybe_import_map_path = context
521+
.get("importMapPath")
522+
.and_then(|it| it.as_str())
523+
.map(str::to_string);
524+
520525
let eszip = if let Some(eszip_payload) = maybe_eszip {
521526
eszip_payload
522527
} else {
@@ -564,6 +569,7 @@ where
564569
CacheSetting::Use
565570
};
566571

572+
emitter_factory.set_import_map_path(maybe_import_map_path.clone());
567573
emitter_factory
568574
.set_permissions_options(Some(permissions_options.clone()));
569575

@@ -634,10 +640,6 @@ where
634640
.get("sourceMap")
635641
.and_then(serde_json::Value::as_bool)
636642
.unwrap_or_default();
637-
let maybe_import_map_path = context
638-
.get("importMapPath")
639-
.and_then(|it| it.as_str())
640-
.map(str::to_string);
641643

642644
let rt_provider = create_module_loader_for_standalone_from_eszip_kind(
643645
eszip,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function getHelperMessage(): string {
2+
return "import map works!";
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"imports": {
3+
"helper-from-import-map": "./helper.ts"
4+
}
5+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as path from "jsr:@std/path";
2+
3+
Deno.serve(async (req: Request) => {
4+
const basePath = "test_cases/user-worker-with-import-map";
5+
const url = new URL(req.url);
6+
const { pathname } = url;
7+
8+
const userWorkerPath = path.join(basePath, "user_worker");
9+
if (pathname === "/import_map") {
10+
const worker = await EdgeRuntime.userWorkers.create({
11+
servicePath: userWorkerPath,
12+
forceCreate: true,
13+
context: {
14+
importMapPath: path.join(basePath, "import_map.json"),
15+
},
16+
});
17+
return worker.fetch(req);
18+
}
19+
if (pathname === "/inline_import_map") {
20+
const inlineImportMap = {
21+
imports: {
22+
"helper-from-import-map": `./${path.join(basePath, "helper.ts")}`,
23+
},
24+
};
25+
const importMapPath = `data:${encodeURIComponent(JSON.stringify(inlineImportMap))}`;
26+
27+
const worker = await EdgeRuntime.userWorkers.create({
28+
servicePath: userWorkerPath,
29+
forceCreate: true,
30+
context: {
31+
importMapPath: importMapPath,
32+
},
33+
});
34+
return worker.fetch(req);
35+
}
36+
37+
return new Response("Not Found", { status: 404 });
38+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { getHelperMessage } from "helper-from-import-map";
2+
3+
Deno.serve((_req: Request) => {
4+
return new Response(
5+
JSON.stringify({
6+
message: getHelperMessage(),
7+
success: true,
8+
}),
9+
{
10+
headers: {
11+
"Content-Type": "application/json",
12+
Connection: "keep-alive",
13+
},
14+
},
15+
);
16+
});

crates/base/tests/integration_tests.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ use base::utils::test_utils::test_user_runtime_opts;
3131
use base::utils::test_utils::test_user_worker_pool_policy;
3232
use base::utils::test_utils::TestBed;
3333
use base::utils::test_utils::TestBedBuilder;
34-
use base::utils::test_utils::{self};
3534
use base::worker;
3635
use base::worker::TerminationToken;
3736
use base::WorkerKind;
@@ -4176,6 +4175,54 @@ directory."
41764175
}
41774176
}
41784177

4178+
#[tokio::test]
4179+
#[serial]
4180+
async fn test_user_worker_with_import_map() {
4181+
let assert_fn = |resp: Result<Response, reqwest::Error>| async {
4182+
let res = resp.unwrap();
4183+
let status = res.status().as_u16();
4184+
4185+
let body_bytes = res.bytes().await.unwrap();
4186+
let body_str = String::from_utf8_lossy(&body_bytes);
4187+
4188+
assert_eq!(
4189+
status, 200,
4190+
"Expected 200, got {} with body: {}",
4191+
status, body_str
4192+
);
4193+
4194+
assert!(
4195+
body_str.contains("import map works!"),
4196+
"Expected import map works!, got: {}",
4197+
body_str
4198+
);
4199+
};
4200+
{
4201+
integration_test!(
4202+
"./test_cases/user-worker-with-import-map",
4203+
NON_SECURE_PORT,
4204+
"import_map",
4205+
None,
4206+
None,
4207+
None,
4208+
(assert_fn),
4209+
TerminationToken::new()
4210+
);
4211+
}
4212+
{
4213+
integration_test!(
4214+
"./test_cases/user-worker-with-import-map",
4215+
NON_SECURE_PORT,
4216+
"inline_import_map",
4217+
None,
4218+
None,
4219+
None,
4220+
(assert_fn),
4221+
TerminationToken::new()
4222+
);
4223+
}
4224+
}
4225+
41794226
#[derive(Deserialize)]
41804227
struct ErrorResponsePayload {
41814228
msg: String,

crates/deno_facade/emitter.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use ext_node::DenoFsNodeResolverEnv;
5858
use ext_node::NodeResolver;
5959
use ext_node::PackageJsonResolver;
6060

61+
use crate::import_map::load_import_map;
6162
use crate::permissions::RuntimePermissionDescriptorParser;
6263

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

124+
import_map_path: Option<String>,
123125
cache_strategy: Option<CacheSetting>,
124126
deno_dir: DenoDir,
125127
deno_options: Option<Arc<DenoOptions>>,
@@ -160,6 +162,7 @@ impl EmitterFactory {
160162
sloppy_imports_resolver: Default::default(),
161163
workspace_resolver: Default::default(),
162164

165+
import_map_path: Default::default(),
163166
cache_strategy: None,
164167
deno_dir,
165168
deno_options: None,
@@ -180,6 +183,11 @@ impl EmitterFactory {
180183
self
181184
}
182185

186+
pub fn set_import_map_path(&mut self, value: Option<String>) -> &mut Self {
187+
self.import_map_path = value;
188+
self
189+
}
190+
183191
pub fn set_cache_strategy(
184192
&mut self,
185193
value: Option<CacheSetting>,
@@ -528,8 +536,12 @@ impl EmitterFactory {
528536
) -> Result<&Arc<WorkspaceResolver>, anyhow::Error> {
529537
self.workspace_resolver.get_or_try_init(|| {
530538
let options = self.deno_options()?;
539+
let specified_import_map =
540+
load_import_map(self.import_map_path.as_deref())?;
541+
531542
let resolver = options.create_workspace_resolver(
532543
self.file_fetcher()?,
544+
specified_import_map,
533545
if options.use_byonm() {
534546
PackageJsonDepResolution::Disabled
535547
} else {

crates/deno_facade/import_map.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use anyhow::anyhow;
22
use anyhow::Error;
3+
use deno_config::workspace::SpecifiedImportMap;
4+
use deno_core::serde_json;
35
use deno_core::url::Url;
4-
use import_map::parse_from_json;
5-
use import_map::ImportMap;
6-
use urlencoding::decode;
7-
86
use std::fs;
97
use std::path::Path;
8+
use urlencoding::decode;
109

1110
pub fn load_import_map(
12-
maybe_path: Option<String>,
13-
) -> Result<Option<ImportMap>, Error> {
11+
maybe_path: Option<&str>,
12+
) -> Result<Option<SpecifiedImportMap>, Error> {
1413
if let Some(path_str) = maybe_path {
1514
let json_str;
1615
let base_url;
@@ -21,10 +20,13 @@ pub fn load_import_map(
2120
if path_str.starts_with("data:") {
2221
let data_uri = Url::parse(&path_str)?;
2322
json_str = decode(data_uri.path())?.into_owned();
24-
base_url = Url::from_directory_path(
25-
decode(data_uri.query().unwrap_or(""))?.into_owned(),
26-
)
27-
.map_err(|_| anyhow!("invalid import map base url"))?;
23+
if let Some(query) = data_uri.query() {
24+
base_url = Url::from_directory_path(decode(query)?.into_owned())
25+
.map_err(|_| anyhow!("invalid import map base url"))?;
26+
} else {
27+
base_url = Url::from_directory_path(std::env::current_dir().unwrap())
28+
.map_err(|_| anyhow!("invalid import map base url"))?;
29+
}
2830
} else {
2931
let path = Path::new(&path_str);
3032
let abs_path = std::env::current_dir().map(|p| p.join(path))?;
@@ -33,8 +35,9 @@ pub fn load_import_map(
3335
.map_err(|_| anyhow!("invalid import map base url"))?;
3436
}
3537

36-
let result = parse_from_json(base_url, json_str.as_str())?;
37-
Ok(Some(result.import_map))
38+
let value = serde_json::from_str(&json_str)?;
39+
40+
Ok(Some(SpecifiedImportMap { base_url, value }))
3841
} else {
3942
Ok(None)
4043
}

deno/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use deno_config::deno_json::TsConfigForEmit;
1616
use deno_config::deno_json::TsConfigType;
1717
use deno_config::workspace::CreateResolverOptions;
1818
use deno_config::workspace::PackageJsonDepResolution;
19+
use deno_config::workspace::SpecifiedImportMap;
1920
use deno_config::workspace::VendorEnablement;
2021
use deno_config::workspace::WorkspaceDirectory;
2122
use deno_config::workspace::WorkspaceDirectoryEmptyOptions;
@@ -199,12 +200,13 @@ impl DenoOptions {
199200
pub fn create_workspace_resolver(
200201
&self,
201202
_file_fetcher: &FileFetcher,
203+
specified_import_map: Option<SpecifiedImportMap>,
202204
pkg_json_dep_resolution: PackageJsonDepResolution,
203205
) -> Result<WorkspaceResolver, AnyError> {
204206
Ok(self.workspace().create_resolver(
205207
CreateResolverOptions {
206208
pkg_json_dep_resolution,
207-
specified_import_map: None,
209+
specified_import_map,
208210
},
209211
|path| Ok(std::fs::read_to_string(path)?),
210212
)?)

0 commit comments

Comments
 (0)