1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-03 04:48:52 -05:00

feat(compile): Enable multiple roots for a standalone module graph (#17663)

This change will enable dynamic imports and web workers to use modules
not reachable from the main module, by passing a list of extra side
module roots as options to `deno compile`. 

This can be done by specifying "--include" flag that accepts a file path or a
URL. This flag can be specified multiple times, to include several modules.
The modules specified with "--include" flag, will be added to the produced
"eszip".
This commit is contained in:
Andreu Botella 2023-03-19 00:43:07 +01:00 committed by GitHub
parent a80d1b6e66
commit b64ec79268
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 8 deletions

View file

@ -83,6 +83,7 @@ pub struct CompileFlags {
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
pub args: Vec<String>, pub args: Vec<String>,
pub target: Option<String>, pub target: Option<String>,
pub include: Vec<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
@ -908,6 +909,20 @@ fn compile_subcommand<'a>() -> Command<'a> {
runtime_args(Command::new("compile"), true, false) runtime_args(Command::new("compile"), true, false)
.trailing_var_arg(true) .trailing_var_arg(true)
.arg(script_arg().required(true)) .arg(script_arg().required(true))
.arg(
Arg::new("include")
.long("include")
.help("UNSTABLE: Additional module to include in the module graph")
.long_help(
"Includes an additional module in the compiled executable's module \
graph. Use this flag if a dynamically imported module or a web worker main \
module fails to load in the executable. This flag can be passed multiple \
times, to include multiple additional modules.",
)
.takes_value(true)
.multiple_occurrences(true)
.value_hint(ValueHint::FilePath),
)
.arg( .arg(
Arg::new("output") Arg::new("output")
.long("output") .long("output")
@ -2486,12 +2501,17 @@ fn compile_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
let source_file = script[0].to_string(); let source_file = script[0].to_string();
let output = matches.value_of("output").map(PathBuf::from); let output = matches.value_of("output").map(PathBuf::from);
let target = matches.value_of("target").map(String::from); let target = matches.value_of("target").map(String::from);
let include = match matches.values_of("include") {
Some(f) => f.map(String::from).collect(),
None => vec![],
};
flags.subcommand = DenoSubcommand::Compile(CompileFlags { flags.subcommand = DenoSubcommand::Compile(CompileFlags {
source_file, source_file,
output, output,
args, args,
target, target,
include,
}); });
} }
@ -6242,6 +6262,7 @@ mod tests {
output: None, output: None,
args: vec![], args: vec![],
target: None, target: None,
include: vec![]
}), }),
type_check_mode: TypeCheckMode::Local, type_check_mode: TypeCheckMode::Local,
..Flags::default() ..Flags::default()
@ -6261,6 +6282,7 @@ mod tests {
output: Some(PathBuf::from("colors")), output: Some(PathBuf::from("colors")),
args: svec!["foo", "bar"], args: svec!["foo", "bar"],
target: None, target: None,
include: vec![]
}), }),
import_map_path: Some("import_map.json".to_string()), import_map_path: Some("import_map.json".to_string()),
no_remote: true, no_remote: true,

View file

@ -150,7 +150,7 @@ pub fn graph_lock_or_exit(graph: &ModuleGraph, lockfile: &mut Lockfile) {
} }
pub async fn create_graph_and_maybe_check( pub async fn create_graph_and_maybe_check(
root: ModuleSpecifier, roots: Vec<ModuleSpecifier>,
ps: &ProcState, ps: &ProcState,
) -> Result<Arc<deno_graph::ModuleGraph>, AnyError> { ) -> Result<Arc<deno_graph::ModuleGraph>, AnyError> {
let mut cache = cache::FetchCacher::new( let mut cache = cache::FetchCacher::new(
@ -176,7 +176,7 @@ pub async fn create_graph_and_maybe_check(
build_graph_with_npm_resolution( build_graph_with_npm_resolution(
&mut graph, &mut graph,
&ps.npm_resolver, &ps.npm_resolver,
vec![root], roots,
&mut cache, &mut cache,
deno_graph::BuildOptions { deno_graph::BuildOptions {
is_dynamic: false, is_dynamic: false,

View file

@ -592,3 +592,37 @@ fn dynamic_import() {
.unwrap(); .unwrap();
assert_eq!(String::from_utf8(output.stdout).unwrap(), expected); assert_eq!(String::from_utf8(output.stdout).unwrap(), expected);
} }
#[test]
fn dynamic_import_unanalyzable() {
let _guard = util::http_server();
let dir = TempDir::new();
let exe = if cfg!(windows) {
dir.path().join("dynamic_import_unanalyzable.exe")
} else {
dir.path().join("dynamic_import_unanalyzable")
};
let output = util::deno_cmd()
.current_dir(util::root_path())
.arg("compile")
.arg("--allow-read")
.arg("--include")
.arg(util::testdata_path().join("./compile/dynamic_imports/import1.ts"))
.arg("--output")
.arg(&exe)
.arg(
util::testdata_path()
.join("./compile/dynamic_imports/main_unanalyzable.ts"),
)
.output()
.unwrap();
assert!(output.status.success());
let output = Command::new(&exe).env("NO_COLOR", "").output().unwrap();
assert!(output.status.success());
let expected = std::fs::read_to_string(
util::testdata_path().join("./compile/dynamic_imports/main.out"),
)
.unwrap();
assert_eq!(String::from_utf8(output.stdout).unwrap(), expected);
}

View file

@ -0,0 +1 @@
./import1.ts

View file

@ -3,4 +3,4 @@ console.log("Starting the main module");
setTimeout(() => { setTimeout(() => {
console.log("Dynamic importing"); console.log("Dynamic importing");
import("./import1.ts").then(() => console.log("Dynamic import done.")); import("./import1.ts").then(() => console.log("Dynamic import done."));
}, 500); }, 0);

View file

@ -0,0 +1,18 @@
import { join } from "https://deno.land/std@0.178.0/path/mod.ts";
console.log("Starting the main module");
// We load the dynamic import path from the file system, to make sure any
// improvements in static analysis can't defeat the purpose of this test, which
// is to make sure the `--include` flag works to add non-analyzed imports to the
// module graph.
const IMPORT_PATH_FILE_PATH = join(
Deno.cwd(),
"tests/testdata/compile/dynamic_imports/import_path",
);
setTimeout(async () => {
console.log("Dynamic importing");
const importPath = (await Deno.readTextFile(IMPORT_PATH_FILE_PATH)).trim();
import(importPath).then(() => console.log("Dynamic import done."));
}, 0);

View file

@ -45,7 +45,8 @@ pub async fn bundle(
log::debug!(">>>>> bundle START"); log::debug!(">>>>> bundle START");
let ps = ProcState::from_options(cli_options).await?; let ps = ProcState::from_options(cli_options).await?;
let graph = let graph =
create_graph_and_maybe_check(module_specifier.clone(), &ps).await?; create_graph_and_maybe_check(vec![module_specifier.clone()], &ps)
.await?;
let mut paths_to_watch: Vec<PathBuf> = graph let mut paths_to_watch: Vec<PathBuf> = graph
.specifiers() .specifiers()

View file

@ -41,6 +41,14 @@ pub async fn compile(
let ps = ProcState::build(flags).await?; let ps = ProcState::build(flags).await?;
let module_specifier = let module_specifier =
resolve_url_or_path(&compile_flags.source_file, ps.options.initial_cwd())?; resolve_url_or_path(&compile_flags.source_file, ps.options.initial_cwd())?;
let module_roots = {
let mut vec = Vec::with_capacity(compile_flags.include.len() + 1);
vec.push(module_specifier.clone());
for side_module in &compile_flags.include {
vec.push(resolve_url_or_path(side_module, ps.options.initial_cwd())?);
}
vec
};
let deno_dir = &ps.dir; let deno_dir = &ps.dir;
let output_path = resolve_compile_executable_output_path( let output_path = resolve_compile_executable_output_path(
@ -49,10 +57,9 @@ pub async fn compile(
) )
.await?; .await?;
let graph = Arc::try_unwrap( let graph =
create_graph_and_maybe_check(module_specifier.clone(), &ps).await?, Arc::try_unwrap(create_graph_and_maybe_check(module_roots, &ps).await?)
) .unwrap();
.unwrap();
// at the moment, we don't support npm specifiers in deno_compile, so show an error // at the moment, we don't support npm specifiers in deno_compile, so show an error
error_for_any_npm_specifier(&graph)?; error_for_any_npm_specifier(&graph)?;
@ -351,6 +358,7 @@ mod test {
output: Some(PathBuf::from("./file")), output: Some(PathBuf::from("./file")),
args: Vec::new(), args: Vec::new(),
target: Some("x86_64-unknown-linux-gnu".to_string()), target: Some("x86_64-unknown-linux-gnu".to_string()),
include: vec![],
}, },
&std::env::current_dir().unwrap(), &std::env::current_dir().unwrap(),
) )
@ -371,6 +379,7 @@ mod test {
output: Some(PathBuf::from("./file")), output: Some(PathBuf::from("./file")),
args: Vec::new(), args: Vec::new(),
target: Some("x86_64-pc-windows-msvc".to_string()), target: Some("x86_64-pc-windows-msvc".to_string()),
include: vec![],
}, },
&std::env::current_dir().unwrap(), &std::env::current_dir().unwrap(),
) )