Skip to content

Commit c53620e

Browse files
authored
Merge pull request #221 from supabase/support-import-maps-for-eszip-bundle
feat: add support for import maps in generated eszips
2 parents ef432f5 + c930533 commit c53620e

File tree

12 files changed

+111
-55
lines changed

12 files changed

+111
-55
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ tokio-util = "0.7.4"
6060
uuid = { version = "1.3.0", features = ["v4"] }
6161
rsa = { version = "0.7.0", default-features = false, features = ["std", "pem", "hazmat"] }
6262
monch = "=0.4.3"
63-
6463
reqwest = { version = "0.11.20", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks", "json"] }
6564
ring = "=0.16.20"
65+
urlencoding = { version = "2.1.2" }
6666

6767
[profile.release]
6868
lto = true

crates/base/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ sb_os = { version = "0.1.0", path = "../sb_os" }
4848
sb_npm = { version = "0.1.0", path = "../npm" }
4949
sb_graph = { version = "0.1.0", path = "../sb_graph" }
5050
sb_module_loader = { version = "0.1.0", path = "../sb_module_loader" }
51-
urlencoding = { version = "2.1.2" }
5251
uuid = { workspace = true }
5352
deno_broadcast_channel.workspace = true
5453
sb_node = { version = "0.1.0", path = "../node" }
5554
eszip.workspace = true
5655
notify = { version = "6.1.1", default-features = false, features = ["macos_kqueue"] }
56+
urlencoding.workspace = true
5757

5858
[dev-dependencies]
5959
futures-util = { version = "0.3.28" }
@@ -79,7 +79,6 @@ deno_websocket = { workspace = true }
7979
httparse = { version = "1.8.0" }
8080
hyper = { version = "0.14.26", features = ["full"] }
8181
http = { version = "0.2" }
82-
import_map = { version = "0.15.0" }
8382
log = { workspace = true }
8483
module_fetcher = { path = "../module_fetcher" }
8584
reqwest.workspace = true
@@ -92,4 +91,4 @@ sb_env = { version = "0.1.0", path = "../sb_env" }
9291
sb_core = { version = "0.1.0", path = "../sb_core" }
9392
sb_os = { version = "0.1.0", path = "../sb_os" }
9493
sb_node = { version = "0.1.0", path = "../node" }
95-
deno_broadcast_channel.workspace = true
94+
deno_broadcast_channel.workspace = true

crates/base/src/deno_runtime.rs

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,20 @@ use deno_tls::rustls;
99
use deno_tls::rustls::RootCertStore;
1010
use deno_tls::rustls_native_certs::load_native_certs;
1111
use deno_tls::RootCertStoreProvider;
12-
use import_map::{parse_from_json, ImportMap};
1312
use log::error;
1413
use serde::de::DeserializeOwned;
1514
use std::collections::HashMap;
16-
use std::path::Path;
15+
use std::fmt;
1716
use std::sync::Arc;
1817
use std::time::Duration;
19-
use std::{fmt, fs};
2018
use tokio::net::UnixStream;
2119
use tokio::sync::mpsc;
22-
use urlencoding::decode;
2320

2421
use crate::snapshot;
2522
use event_worker::events::{EventMetadata, WorkerEventWithMetadata};
2623
use event_worker::js_interceptors::sb_events_js_interceptors;
2724
use event_worker::sb_user_event_worker;
2825
use module_fetcher::file_fetcher::CacheSetting;
29-
use module_fetcher::util::diagnostic::print_import_map_diagnostics;
3026
use sb_core::cert::ValueRootCertStoreProvider;
3127
use sb_core::http_start::sb_core_http;
3228
use sb_core::net::sb_core_net;
@@ -35,43 +31,14 @@ use sb_core::runtime::sb_core_runtime;
3531
use sb_core::sb_core_main_js;
3632
use sb_env::sb_env as sb_env_op;
3733
use sb_graph::emitter::EmitterFactory;
34+
use sb_graph::import_map::load_import_map;
3835
use sb_graph::{generate_binary_eszip, EszipPayloadKind};
3936
use sb_module_loader::standalone::create_module_loader_for_standalone_from_eszip_kind;
4037
use sb_module_loader::RuntimeProviders;
4138
use sb_node::deno_node;
4239
use sb_workers::context::{UserWorkerMsgs, WorkerContextInitOpts, WorkerRuntimeOpts};
4340
use sb_workers::sb_user_workers;
4441

45-
fn load_import_map(maybe_path: Option<String>) -> Result<Option<ImportMap>, Error> {
46-
if let Some(path_str) = maybe_path {
47-
let json_str;
48-
let base_url;
49-
50-
// check if the path is a data URI (prefixed with data:)
51-
// the data URI takes the following format
52-
// data:{encodeURIComponent(mport_map.json)?{encodeURIComponent(base_path)}
53-
if path_str.starts_with("data:") {
54-
let data_uri = Url::parse(&path_str)?;
55-
json_str = decode(data_uri.path())?.into_owned();
56-
base_url =
57-
Url::from_directory_path(decode(data_uri.query().unwrap_or(""))?.into_owned())
58-
.map_err(|_| anyhow!("invalid import map base url"))?;
59-
} else {
60-
let path = Path::new(&path_str);
61-
let abs_path = std::env::current_dir().map(|p| p.join(path))?;
62-
json_str = fs::read_to_string(abs_path.clone())?;
63-
base_url = Url::from_directory_path(abs_path.parent().unwrap())
64-
.map_err(|_| anyhow!("invalid import map base url"))?;
65-
}
66-
67-
let result = parse_from_json(&base_url, json_str.as_str())?;
68-
print_import_map_diagnostics(&result.diagnostics);
69-
Ok(Some(result.import_map))
70-
} else {
71-
Ok(None)
72-
}
73-
}
74-
7542
pub struct DenoRuntimeError(Error);
7643

7744
impl PartialEq for DenoRuntimeError {
@@ -180,9 +147,13 @@ impl DenoRuntime {
180147
None
181148
};
182149

183-
let eszip =
184-
generate_binary_eszip(main_module_url_file_path, arc_emitter_factory, maybe_code)
185-
.await?;
150+
let eszip = generate_binary_eszip(
151+
main_module_url_file_path,
152+
arc_emitter_factory,
153+
maybe_code,
154+
import_map_path.clone(),
155+
)
156+
.await?;
186157

187158
EszipPayloadKind::Eszip(eszip)
188159
};
@@ -491,7 +462,7 @@ mod test {
491462
.unwrap();
492463
let path_buf = PathBuf::from("./test_cases/eszip-source-test.ts");
493464
let emitter_factory = Arc::new(EmitterFactory::new());
494-
let bin_eszip = generate_binary_eszip(path_buf, emitter_factory.clone(), None)
465+
let bin_eszip = generate_binary_eszip(path_buf, emitter_factory.clone(), None, None)
495466
.await
496467
.unwrap();
497468
fs::remove_file("./test_cases/eszip-source-test.ts").unwrap();
@@ -540,7 +511,7 @@ mod test {
540511
let file = PathBuf::from("./test_cases/eszip-silly-test/index.ts");
541512
let service_path = PathBuf::from("./test_cases/eszip-silly-test");
542513
let emitter_factory = Arc::new(EmitterFactory::new());
543-
let binary_eszip = generate_binary_eszip(file, emitter_factory.clone(), None)
514+
let binary_eszip = generate_binary_eszip(file, emitter_factory.clone(), None, None)
544515
.await
545516
.unwrap();
546517

crates/cli/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ path = "src/main.rs"
1010
[dependencies]
1111
anyhow = { workspace = true }
1212
base = { path = "../base" }
13-
sb_graph = { path = "../sb_graph" }
13+
deno_core = { workspace = true }
1414
clap = { version = "4.0.29", features = ["cargo"] }
1515
env_logger = "0.10.0"
1616
log = { workspace = true }
17+
sb_graph = { path = "../sb_graph" }
1718
tokio.workspace = true
18-

crates/cli/src/main.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
mod logger;
22

3-
use anyhow::Error;
3+
use anyhow::{anyhow, Error};
44
use base::commands::start_server;
55
use base::server::WorkerEntrypoints;
66
use clap::builder::FalseyValueParser;
77
use clap::{arg, crate_version, value_parser, ArgAction, Command};
8+
use deno_core::url::Url;
89
use sb_graph::emitter::EmitterFactory;
910
use sb_graph::generate_binary_eszip;
11+
use sb_graph::import_map::load_import_map;
1012
use std::fs::File;
1113
use std::io::Write;
1214
use std::path::PathBuf;
@@ -55,6 +57,7 @@ fn cli() -> Command {
5557
.about("Creates an 'eszip' file that can be executed by the EdgeRuntime. Such file contains all the modules in contained in a single binary.")
5658
.arg(arg!(--"output" <DIR> "Path to output eszip file").default_value("bin.eszip"))
5759
.arg(arg!(--"entrypoint" <Path> "Path to entrypoint to bundle as an eszip").required(true))
60+
.arg(arg!(--"import-map" <Path> "Path to import map file"))
5861
)
5962
}
6063

@@ -125,17 +128,33 @@ fn main() -> Result<(), anyhow::Error> {
125128
}
126129
Some(("bundle", sub_matches)) => {
127130
let output_path = sub_matches.get_one::<String>("output").cloned().unwrap();
131+
let import_map_path = sub_matches.get_one::<String>("import-map").cloned();
128132

129133
let entry_point_path = sub_matches
130134
.get_one::<String>("entrypoint")
131135
.cloned()
132136
.unwrap();
133137

134138
let path = PathBuf::from(entry_point_path.as_str());
139+
let mut emitter_factory = EmitterFactory::new();
140+
let maybe_import_map = load_import_map(import_map_path.clone())?;
141+
let mut maybe_import_map_url = None;
142+
if maybe_import_map.is_some() {
143+
let abs_import_map_path =
144+
std::env::current_dir().map(|p| p.join(import_map_path.unwrap()))?;
145+
maybe_import_map_url = Some(
146+
Url::from_file_path(abs_import_map_path)
147+
.map_err(|_| anyhow!("failed get import map url"))?
148+
.to_string(),
149+
);
150+
}
151+
emitter_factory.set_import_map(maybe_import_map.clone());
152+
135153
let eszip = generate_binary_eszip(
136154
path.canonicalize().unwrap(),
137-
Arc::new(EmitterFactory::new()),
155+
Arc::new(emitter_factory),
138156
None,
157+
maybe_import_map_url,
139158
)
140159
.await?;
141160
let bin = eszip.into_bytes();

crates/sb_graph/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ deno_ast.workspace = true
2727
deno_fs.workspace = true
2828
deno_npm.workspace = true
2929
once_cell.workspace = true
30-
deno_web.workspace = true
30+
deno_web.workspace = true
31+
urlencoding.workspace = true

crates/sb_graph/import_map.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use anyhow::{anyhow, Error};
2+
use deno_core::url::Url;
3+
use import_map::{parse_from_json, ImportMap};
4+
use module_fetcher::util::diagnostic::print_import_map_diagnostics;
5+
use std::fs;
6+
use std::path::Path;
7+
use urlencoding::decode;
8+
9+
pub fn load_import_map(maybe_path: Option<String>) -> Result<Option<ImportMap>, Error> {
10+
if let Some(path_str) = maybe_path {
11+
let json_str;
12+
let base_url;
13+
14+
// check if the path is a data URI (prefixed with data:)
15+
// the data URI takes the following format
16+
// data:{encodeURIComponent(mport_map.json)?{encodeURIComponent(base_path)}
17+
if path_str.starts_with("data:") {
18+
let data_uri = Url::parse(&path_str)?;
19+
json_str = decode(data_uri.path())?.into_owned();
20+
base_url =
21+
Url::from_directory_path(decode(data_uri.query().unwrap_or(""))?.into_owned())
22+
.map_err(|_| anyhow!("invalid import map base url"))?;
23+
} else {
24+
let path = Path::new(&path_str);
25+
let abs_path = std::env::current_dir().map(|p| p.join(path))?;
26+
json_str = fs::read_to_string(abs_path.clone())?;
27+
base_url = Url::from_directory_path(abs_path.parent().unwrap())
28+
.map_err(|_| anyhow!("invalid import map base url"))?;
29+
}
30+
31+
let result = parse_from_json(&base_url, json_str.as_str())?;
32+
print_import_map_diagnostics(&result.diagnostics);
33+
Ok(Some(result.import_map))
34+
} else {
35+
Ok(None)
36+
}
37+
}

crates/sb_graph/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ use deno_core::error::AnyError;
55
use deno_core::{serde_json, FastString, JsBuffer, ModuleSpecifier};
66
use deno_fs::{FileSystem, RealFs};
77
use deno_npm::NpmSystemInfo;
8-
use eszip::EszipV2;
8+
use eszip::{EszipV2, ModuleKind};
99
use sb_fs::{build_vfs, VfsOpts};
1010
use std::path::PathBuf;
1111
use std::sync::Arc;
1212

1313
pub mod emitter;
1414
pub mod graph_resolver;
1515
pub mod graph_util;
16+
pub mod import_map;
1617

1718
pub const VFS_ESZIP_KEY: &str = "---SUPABASE-VFS-DATA-ESZIP---";
1819
pub const SOURCE_CODE_ESZIP_KEY: &str = "---SUPABASE-SOURCE-CODE-ESZIP---";
@@ -28,6 +29,7 @@ pub async fn generate_binary_eszip(
2829
file: PathBuf,
2930
emitter_factory: Arc<EmitterFactory>,
3031
maybe_module_code: Option<FastString>,
32+
maybe_import_map_url: Option<String>,
3133
) -> Result<EszipV2, AnyError> {
3234
let graph = create_graph(file.clone(), emitter_factory.clone(), &maybe_module_code).await;
3335
let eszip = create_eszip_from_graph_raw(graph, Some(emitter_factory.clone())).await;
@@ -72,6 +74,22 @@ pub async fn generate_binary_eszip(
7274
eszip.add_opaque_data(String::from(VFS_ESZIP_KEY), Arc::from(boxed_slice));
7375
eszip.add_opaque_data(String::from(SOURCE_CODE_ESZIP_KEY), bin_code);
7476

77+
// add import map
78+
if emitter_factory.maybe_import_map.is_some() {
79+
eszip.add_import_map(
80+
ModuleKind::Json,
81+
maybe_import_map_url.unwrap(),
82+
Arc::from(
83+
emitter_factory
84+
.maybe_import_map
85+
.as_ref()
86+
.unwrap()
87+
.to_json()
88+
.as_bytes(),
89+
),
90+
);
91+
};
92+
7593
Ok(eszip)
7694
} else {
7795
eszip

examples/express/import_map.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"imports": {
3+
"oak": "https://deno.land/x/[email protected]/mod.ts",
4+
"shared_cors": "./_shared/cors.ts",
5+
"express": "npm:[email protected]"
6+
}
7+
}

0 commit comments

Comments
 (0)