Skip to content

Commit

Permalink
feat(wasm): support loading precompiled dependencies in /lib
Browse files Browse the repository at this point in the history
This adds support to utilize the `/lib` path in a similar way to the `gleam-cli` compiler.

It's currently the responsiblity of the caller to populate the files with `write_file_bytes` for this to be useful.

## TODO

Because the `PackageConfig` is hard-coded and has no dependencies declared, importing anything from `/lib` will produce a "Transitive dependency imported" warning.

## Motivation

While tinkering with the idea from
gleam-lang/playground#9

Found that the current playground includes `gleam_stdlib` by pretending they're submodules in `src/gleam/io.gleam` for instance.

This approach no longer works when you're trying to use more dependencies than 1. Mainly the `import .. from` JS statements will break as they're precompiled as *siblings* rather than clobbered into a single package with submodules.
  • Loading branch information
Beanow committed Dec 1, 2024
1 parent 95fdc7c commit ce26ab7
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions compiler-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ serde.workspace = true
termcolor.workspace = true
tracing.workspace = true
getrandom.workspace = true
ecow.workspace = true

[dev-dependencies]
wasm-bindgen-test = "0.3.42"
51 changes: 45 additions & 6 deletions compiler-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ mod log_telemetry;
mod tests;
mod wasm_filesystem;

use camino::Utf8PathBuf;
use camino::{Utf8Path, Utf8PathBuf};
use ecow::EcoString;
use gleam_core::{
analyse::TargetSupport,
build::{
Mode, NullTelemetry, PackageCompiler, StaleTracker, Target, TargetCodegenConfiguration,
},
config::PackageConfig,
io::{FileSystemReader, FileSystemWriter},
metadata, paths,
type_::ModuleInterface,
uid::UniqueIdGenerator,
warning::{VectorWarningEmitterIO, WarningEmitter},
Error,
Expand Down Expand Up @@ -167,14 +170,19 @@ pub fn pop_warning(project_id: usize) -> Option<String> {

fn do_compile_package(project: Project, target: Target) -> Result<(), Error> {
let ids = UniqueIdGenerator::new();
let mut type_manifests = im::HashMap::new();
let lib = Utf8PathBuf::from("/lib");
let out = Utf8PathBuf::from("/build");
let package = Utf8PathBuf::from("/");

let mut type_manifests = load_libraries(&ids, &project.fs, &lib)?;
let mut defined_modules = im::HashMap::new();
#[allow(clippy::arc_with_non_send_sync)]
let warning_emitter = WarningEmitter::new(Rc::new(project.warnings));
let config = PackageConfig {
name: "library".into(),
version: Version::new(1, 0, 0),
target,
// TODO: allow manipulation of the `PackageConfig`, like declaring dependencies.
..Default::default()
};

Expand All @@ -187,10 +195,6 @@ fn do_compile_package(project: Project, target: Target) -> Result<(), Error> {
};

tracing::info!("Compiling package");

let lib = Utf8PathBuf::from("/lib");
let out = Utf8PathBuf::from("/build");
let package = Utf8PathBuf::from("/");
let mut compiler = PackageCompiler::new(
&config,
Mode::Dev,
Expand All @@ -217,3 +221,38 @@ fn do_compile_package(project: Project, target: Target) -> Result<(), Error> {
.into_result()
.map(|_| ())
}

fn load_libraries(
ids: &UniqueIdGenerator,
fs: &WasmFileSystem,
lib: &Utf8Path,
) -> Result<im::HashMap<EcoString, ModuleInterface>, Error> {
tracing::info!("Reading precompiled module metadata files");
let mut manifests = im::HashMap::new();

for lib in fs.read_dir(lib)?.into_iter().filter_map(Result::ok) {
let path = lib.into_path().join(paths::ARTEFACT_DIRECTORY_NAME);
if !fs.is_directory(&path) {
continue;
}
for module in module_caches_paths(fs, &path)? {
let buf = fs.read_bytes(&module)?;
let module = metadata::ModuleDecoder::new(ids.clone()).read(buf.as_ref())?;
let _ = manifests.insert(module.name.clone(), module);
}
}

Ok(manifests)
}

pub fn module_caches_paths(
fs: &WasmFileSystem,
package_path: &Utf8Path,
) -> Result<impl Iterator<Item = Utf8PathBuf>, Error> {
Ok(fs
.read_dir(package_path)?
.into_iter()
.filter_map(Result::ok)
.map(|f| f.into_path())
.filter(|p| p.extension() == Some("cache")))
}

0 comments on commit ce26ab7

Please sign in to comment.