mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 10:59:13 +00:00
feat(vendor): support for npm specifiers (#19186)
We never properly added support for this. This fixes vendoring when it has npm or node specifiers. Vendoring occurs by adding a `"nodeModulesDir": true` property to deno.json then it uses a local node_modules directory. This can be opted out by setting `"nodeModulesDir": false` or running with `--node-modules-dir=false`. Closes #18090 Closes #17210 Closes #17619 Closes #16778
This commit is contained in:
parent
7f5290b694
commit
cc406c8360
11 changed files with 463 additions and 110 deletions
|
@ -10,6 +10,7 @@ use test_util as util;
|
|||
use test_util::TempDir;
|
||||
use util::http_server;
|
||||
use util::new_deno_dir;
|
||||
use util::TestContextBuilder;
|
||||
|
||||
#[test]
|
||||
fn output_dir_exists() {
|
||||
|
@ -186,15 +187,13 @@ fn import_map_output_dir() {
|
|||
String::from_utf8_lossy(&output.stderr).trim(),
|
||||
format!(
|
||||
concat!(
|
||||
"Ignoring import map. Specifying an import map file ({}) in the deno ",
|
||||
"vendor output directory is not supported. If you wish to use an ",
|
||||
"import map while vendoring, please specify one located outside this ",
|
||||
"directory.\n",
|
||||
"{}\n",
|
||||
"Download http://localhost:4545/vendor/logger.ts\n",
|
||||
"{}",
|
||||
"{}\n\n{}",
|
||||
),
|
||||
PathBuf::from("vendor").join("import_map.json").display(),
|
||||
success_text_updated_deno_json("1 module", "vendor/"),
|
||||
ignoring_import_map_text(),
|
||||
vendored_text("1 module", "vendor/"),
|
||||
success_text_updated_deno_json("vendor/"),
|
||||
)
|
||||
);
|
||||
assert!(output.status.success());
|
||||
|
@ -511,8 +510,9 @@ fn update_existing_config_test() {
|
|||
assert_eq!(
|
||||
String::from_utf8_lossy(&output.stderr).trim(),
|
||||
format!(
|
||||
"Download http://localhost:4545/vendor/logger.ts\n{}",
|
||||
success_text_updated_deno_json("1 module", "vendor2",)
|
||||
"Download http://localhost:4545/vendor/logger.ts\n{}\n\n{}",
|
||||
vendored_text("1 module", "vendor2"),
|
||||
success_text_updated_deno_json("vendor2",)
|
||||
)
|
||||
);
|
||||
assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "");
|
||||
|
@ -537,38 +537,158 @@ fn update_existing_config_test() {
|
|||
assert!(output.status.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vendor_npm_node_specifiers() {
|
||||
let context = TestContextBuilder::for_npm().use_temp_cwd().build();
|
||||
let temp_dir = context.temp_dir();
|
||||
temp_dir.write(
|
||||
"my_app.ts",
|
||||
concat!(
|
||||
"import { path, getValue, setValue } from 'http://localhost:4545/vendor/npm_and_node_specifier.ts';\n",
|
||||
"setValue(5);\n",
|
||||
"console.log(path.isAbsolute(Deno.cwd()), getValue());",
|
||||
),
|
||||
);
|
||||
temp_dir.write("deno.json", "{}");
|
||||
|
||||
let output = context.new_command().args("vendor my_app.ts").run();
|
||||
output.assert_matches_text(
|
||||
format!(
|
||||
concat!(
|
||||
"Download http://localhost:4545/vendor/npm_and_node_specifier.ts\n",
|
||||
"Download http://localhost:4545/npm/registry/@denotest/esm-basic\n",
|
||||
"Download http://localhost:4545/npm/registry/@denotest/esm-basic/1.0.0.tgz\n",
|
||||
"{}\n",
|
||||
"Initialize @denotest/esm-basic@1.0.0\n",
|
||||
"{}\n\n",
|
||||
"{}\n",
|
||||
),
|
||||
vendored_text("1 module", "vendor/"),
|
||||
vendored_npm_package_text("1 npm package"),
|
||||
success_text_updated_deno_json("vendor/")
|
||||
)
|
||||
);
|
||||
let output = context.new_command().args("run -A my_app.ts").run();
|
||||
output.assert_matches_text("true 5\n");
|
||||
assert!(temp_dir.path().join("node_modules").exists());
|
||||
assert!(temp_dir.path().join("deno.lock").exists());
|
||||
|
||||
// now try re-vendoring with a lockfile
|
||||
let output = context.new_command().args("vendor --force my_app.ts").run();
|
||||
output.assert_matches_text(format!(
|
||||
"{}\n{}\n\n{}\n",
|
||||
ignoring_import_map_text(),
|
||||
vendored_text("1 module", "vendor/"),
|
||||
success_text_updated_deno_json("vendor/"),
|
||||
));
|
||||
|
||||
// delete the node_modules folder
|
||||
temp_dir.remove_dir_all("node_modules");
|
||||
|
||||
// vendor with --node-modules-dir=false
|
||||
let output = context
|
||||
.new_command()
|
||||
.args("vendor --node-modules-dir=false --force my_app.ts")
|
||||
.run();
|
||||
output.assert_matches_text(format!(
|
||||
"{}\n{}\n\n{}\n",
|
||||
ignoring_import_map_text(),
|
||||
vendored_text("1 module", "vendor/"),
|
||||
success_text_updated_deno_json("vendor/")
|
||||
));
|
||||
assert!(!temp_dir.path().join("node_modules").exists());
|
||||
|
||||
// delete the deno.json
|
||||
temp_dir.remove_file("deno.json");
|
||||
|
||||
// vendor with --node-modules-dir
|
||||
let output = context
|
||||
.new_command()
|
||||
.args("vendor --node-modules-dir --force my_app.ts")
|
||||
.run();
|
||||
output.assert_matches_text(format!(
|
||||
"Initialize @denotest/esm-basic@1.0.0\n{}\n\n{}\n",
|
||||
vendored_text("1 module", "vendor/"),
|
||||
use_import_map_text("vendor/")
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vendor_only_npm_specifiers() {
|
||||
let context = TestContextBuilder::for_npm().use_temp_cwd().build();
|
||||
let temp_dir = context.temp_dir();
|
||||
temp_dir.write(
|
||||
"my_app.ts",
|
||||
concat!(
|
||||
"import { getValue, setValue } from 'npm:@denotest/esm-basic';\n",
|
||||
"setValue(5);\n",
|
||||
"console.log(path.isAbsolute(Deno.cwd()), getValue());",
|
||||
),
|
||||
);
|
||||
temp_dir.write("deno.json", "{}");
|
||||
|
||||
let output = context.new_command().args("vendor my_app.ts").run();
|
||||
output.assert_matches_text(
|
||||
format!(
|
||||
concat!(
|
||||
"Download http://localhost:4545/npm/registry/@denotest/esm-basic\n",
|
||||
"Download http://localhost:4545/npm/registry/@denotest/esm-basic/1.0.0.tgz\n",
|
||||
"{}\n",
|
||||
"Initialize @denotest/esm-basic@1.0.0\n",
|
||||
"{}\n",
|
||||
),
|
||||
vendored_text("0 modules", "vendor/"),
|
||||
vendored_npm_package_text("1 npm package"),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn success_text(module_count: &str, dir: &str, has_import_map: bool) -> String {
|
||||
let mut text = format!("Vendored {module_count} into {dir} directory.");
|
||||
if has_import_map {
|
||||
let f = format!(
|
||||
concat!(
|
||||
"\n\nTo use vendored modules, specify the `--import-map {}import_map.json` flag when ",
|
||||
r#"invoking Deno subcommands or add an `"importMap": "<path_to_vendored_import_map>"` "#,
|
||||
"entry to a deno.json file.",
|
||||
),
|
||||
if dir != "vendor/" {
|
||||
format!("{}{}", dir.trim_end_matches('/'), if cfg!(windows) { '\\' } else {'/'})
|
||||
} else {
|
||||
dir.to_string()
|
||||
}
|
||||
);
|
||||
write!(text, "{f}").unwrap();
|
||||
write!(text, "\n\n{}", use_import_map_text(dir)).unwrap();
|
||||
}
|
||||
text
|
||||
}
|
||||
|
||||
fn success_text_updated_deno_json(module_count: &str, dir: &str) -> String {
|
||||
fn use_import_map_text(dir: &str) -> String {
|
||||
format!(
|
||||
concat!(
|
||||
"To use vendored modules, specify the `--import-map {}import_map.json` flag when ",
|
||||
r#"invoking Deno subcommands or add an `"importMap": "<path_to_vendored_import_map>"` "#,
|
||||
"entry to a deno.json file.",
|
||||
),
|
||||
if dir != "vendor/" {
|
||||
format!("{}{}", dir.trim_end_matches('/'), if cfg!(windows) { '\\' } else {'/'})
|
||||
} else {
|
||||
dir.to_string()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn vendored_text(module_count: &str, dir: &str) -> String {
|
||||
format!("Vendored {} into {} directory.", module_count, dir)
|
||||
}
|
||||
|
||||
fn vendored_npm_package_text(package_count: &str) -> String {
|
||||
format!(
|
||||
concat!(
|
||||
"Vendored {} into node_modules directory. Set `nodeModulesDir: false` ",
|
||||
"in the Deno configuration file to disable vendoring npm packages in the future.",
|
||||
),
|
||||
package_count
|
||||
)
|
||||
}
|
||||
|
||||
fn success_text_updated_deno_json(dir: &str) -> String {
|
||||
format!(
|
||||
concat!(
|
||||
"Vendored {} into {} directory.\n\n",
|
||||
"Updated your local Deno configuration file with a reference to the ",
|
||||
"new vendored import map at {}import_map.json. Invoking Deno subcommands will ",
|
||||
"now automatically resolve using the vendored modules. You may override ",
|
||||
"this by providing the `--import-map <other-import-map>` flag or by ",
|
||||
"manually editing your Deno configuration file.",
|
||||
),
|
||||
module_count,
|
||||
dir,
|
||||
if dir != "vendor/" {
|
||||
format!(
|
||||
"{}{}",
|
||||
|
@ -580,3 +700,15 @@ fn success_text_updated_deno_json(module_count: &str, dir: &str) -> String {
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn ignoring_import_map_text() -> String {
|
||||
format!(
|
||||
concat!(
|
||||
"Ignoring import map. Specifying an import map file ({}) in the deno ",
|
||||
"vendor output directory is not supported. If you wish to use an ",
|
||||
"import map while vendoring, please specify one located outside this ",
|
||||
"directory.",
|
||||
),
|
||||
PathBuf::from("vendor").join("import_map.json").display(),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue