diff --git a/docs/src/commands/build.md b/docs/src/commands/build.md index 49b4540db..c7d0580c7 100644 --- a/docs/src/commands/build.md +++ b/docs/src/commands/build.md @@ -47,20 +47,26 @@ The exact meaning of the profile flags may evolve as the platform matures. ## Target -The `build` command accepts a `--target` argument. This will customize the output files -to align with a particular type of JS module. This allows wasm-pack to generate either -ES6 modules or CommonJS modules for use in browser and in NodeJS. Defaults to `browser`. -The options are: +The `build` command accepts a `--target` argument. This will customize the JS +that is emitted and how the WebAssembly files are instantiated and loaded. For +more documentation on the various strategies here, see the [documentation on +using the compiled output][deploy]. ``` wasm-pack build --target nodejs ``` -| Option | Description | -|-----------|-----------------------------------------------------------------------------------------------------------------| -| `nodejs` | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. | -| `no-modules` | Outputs JS that use no modules. `browser` key in `package.json`. | -| `browser` | Outputs JS that uses ES6 modules, primarily for use with `import` statements and/or bundlers such as `webpack`. `module` key in `package.json`. `sideEffects: false` by default. | +| Option | Deployment | Description | +|-----------|------------|-----------------------------------------------------------------------------------------------------| +| *not specified* or `bundler` | [Bundler][bundlers] | Outputs JS that is suitable for interoperation with a Bundler like Webpack. You'll `import` the JS and the `module` key is specified in `package.json`. `sideEffects: false` is by default. | +| `nodejs` | [Node.js][deploy-nodejs] | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. | +| `web` | [Native in browser][deploy-web] | Outputs JS that can be natively imported as an ES module in a browser, but the WebAssembly must be manually instantiated and loaded. | +| `no-modules` | [Native in browser][deploy-web] | Same as `web`, except the JS is included on a page and modifies global state, and doesn't support as many `wasm-bindgen` features as `web` | + +[deploy]: https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html +[bundlers]: https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html#bundlers +[deploy-nodejs]: https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html#nodejs +[deploy-web]: https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html#without-a-bundler ## Scope diff --git a/src/bindgen.rs b/src/bindgen.rs index 3d61df6f4..630ffecd6 100644 --- a/src/bindgen.rs +++ b/src/bindgen.rs @@ -2,7 +2,7 @@ use binary_install::{Cache, Download}; use child; -use command::build::BuildProfile; +use command::build::{BuildProfile, Target}; use emoji; use failure::{self, ResultExt}; use log::debug; @@ -176,7 +176,7 @@ pub fn wasm_bindgen_build( bindgen: &Download, out_dir: &Path, disable_dts: bool, - target: &str, + target: &Target, profile: BuildProfile, step: &Step, ) -> Result<(), failure::Error> { @@ -203,9 +203,10 @@ pub fn wasm_bindgen_build( "--typescript" }; let target_arg = match target { - "nodejs" => "--nodejs", - "no-modules" => "--no-modules", - _ => "--browser", + Target::Nodejs => "--nodejs", + Target::NoModules => "--no-modules", + Target::Web => "--web", + Target::Bundler => "--browser", }; let bindgen_path = bindgen.binary("wasm-bindgen")?; let mut cmd = Command::new(bindgen_path); diff --git a/src/command/build.rs b/src/command/build.rs index 30f85edb5..e7feb9b35 100644 --- a/src/command/build.rs +++ b/src/command/build.rs @@ -26,7 +26,7 @@ pub struct Build { pub crate_data: manifest::CrateData, pub scope: Option, pub disable_dts: bool, - pub target: String, + pub target: Target, pub profile: BuildProfile, pub mode: BuildMode, pub out_dir: PathBuf, @@ -66,6 +66,44 @@ impl FromStr for BuildMode { } } +/// What sort of output we're going to be generating and flags we're invoking +/// `wasm-bindgen` with. +#[derive(Clone, Copy, Debug)] +pub enum Target { + /// Default output mode or `--target bundler`, indicates output will be + /// used with a bundle in a later step. + Bundler, + /// Correspond to `--target web` where the output is natively usable as an + /// ES module in a browser and the wasm is manually instantiated. + Web, + /// Correspond to `--target nodejs` where the output is natively usable as + /// a Node.js module loaded with `require`. + Nodejs, + /// Correspond to `--target no-modules` where the output is natively usable + /// in a browser but pollutes the global namespace and must be manually + /// instantiated. + NoModules, +} + +impl Default for Target { + fn default() -> Target { + Target::Bundler + } +} + +impl FromStr for Target { + type Err = Error; + fn from_str(s: &str) -> Result { + match s { + "bundler" | "browser" => Ok(Target::Bundler), + "web" => Ok(Target::Web), + "nodejs" => Ok(Target::Nodejs), + "no-modules" => Ok(Target::NoModules), + _ => bail!("Unknown target: {}", s), + } + } +} + /// The build profile controls whether optimizations, debug info, and assertions /// are enabled or disabled. #[derive(Clone, Copy, Debug)] @@ -99,8 +137,8 @@ pub struct BuildOptions { pub disable_dts: bool, #[structopt(long = "target", short = "t", default_value = "browser")] - /// Sets the target environment. [possible values: browser, nodejs, no-modules] - pub target: String, + /// Sets the target environment. [possible values: browser, nodejs, web, no-modules] + pub target: Target, #[structopt(long = "debug")] /// Deprecated. Renamed to `--dev`. @@ -133,9 +171,9 @@ impl Default for BuildOptions { Self { path: None, scope: None, - mode: BuildMode::Normal, + mode: BuildMode::default(), disable_dts: false, - target: String::new(), + target: Target::default(), debug: false, dev: false, release: false, @@ -165,12 +203,6 @@ impl Build { _ => bail!("Can only supply one of the --dev, --release, or --profiling flags"), }; - // `possible_values` in clap isn't supported by `structopt` - let possible_targets = ["browser", "nodejs", "no-modules"]; - if !possible_targets.contains(&build_opts.target.as_str()) { - bail!("Supported targets: browser, nodejs, no-modules"); - } - Ok(Build { crate_path, crate_data, diff --git a/src/command/publish/mod.rs b/src/command/publish/mod.rs index f71fb5344..019a83bb7 100644 --- a/src/command/publish/mod.rs +++ b/src/command/publish/mod.rs @@ -2,7 +2,7 @@ pub mod access; use self::access::Access; -use command::build::{Build, BuildOptions}; +use command::build::{Build, BuildOptions, Target}; use command::utils::{find_pkg_directory, set_crate_path}; use dialoguer::{Confirmation, Input, Select}; use failure::Error; @@ -10,6 +10,7 @@ use log::info; use npm; use std::path::PathBuf; use std::result; +use std::str::FromStr; use PBAR; /// Creates a tarball from a 'pkg' directory @@ -45,6 +46,7 @@ pub fn publish( .default(0) .interact()? .to_string(); + let target = Target::from_str(&target)?; let build_opts = BuildOptions { path: Some(crate_path.clone()), target, diff --git a/src/manifest/mod.rs b/src/manifest/mod.rs index 84d8e2d55..ea376a4d4 100644 --- a/src/manifest/mod.rs +++ b/src/manifest/mod.rs @@ -11,7 +11,7 @@ use self::npm::{ repository::Repository, CommonJSPackage, ESModulesPackage, NoModulesPackage, NpmPackage, }; use cargo_metadata::Metadata; -use command::build::BuildProfile; +use command::build::{BuildProfile, Target}; use emoji; use failure::{Error, ResultExt}; use progressbar::Step; @@ -377,19 +377,18 @@ impl CrateData { out_dir: &Path, scope: &Option, disable_dts: bool, - target: &str, + target: &Target, step: &Step, ) -> Result<(), Error> { let msg = format!("{}Writing a package.json...", emoji::MEMO); PBAR.step(step, &msg); let pkg_file_path = out_dir.join("package.json"); - let npm_data = if target == "nodejs" { - self.to_commonjs(scope, disable_dts, out_dir) - } else if target == "no-modules" { - self.to_nomodules(scope, disable_dts, out_dir) - } else { - self.to_esmodules(scope, disable_dts, out_dir) + let npm_data = match target { + Target::Nodejs => self.to_commonjs(scope, disable_dts, out_dir), + Target::NoModules => self.to_nomodules(scope, disable_dts, out_dir), + Target::Bundler => self.to_esmodules(scope, disable_dts, out_dir), + Target::Web => self.to_web(scope, disable_dts, out_dir), }; let npm_json = serde_json::to_string_pretty(&npm_data)?; @@ -522,6 +521,35 @@ impl CrateData { }) } + fn to_web(&self, scope: &Option, disable_dts: bool, out_dir: &Path) -> NpmPackage { + let data = self.npm_data(scope, false, disable_dts, out_dir); + let pkg = &self.data.packages[self.current_idx]; + + self.check_optional_fields(); + + NpmPackage::ESModulesPackage(ESModulesPackage { + name: data.name, + collaborators: pkg.authors.clone(), + description: self.manifest.package.description.clone(), + version: pkg.version.clone(), + license: self.license(), + repository: self + .manifest + .package + .repository + .clone() + .map(|repo_url| Repository { + ty: "git".to_string(), + url: repo_url, + }), + files: data.files, + module: data.main, + homepage: data.homepage, + types: data.dts_file, + side_effects: "false".to_string(), + }) + } + fn to_nomodules( &self, scope: &Option, diff --git a/tests/all/manifest.rs b/tests/all/manifest.rs index 4bb7b69f0..6c274d20b 100644 --- a/tests/all/manifest.rs +++ b/tests/all/manifest.rs @@ -3,6 +3,7 @@ use std::collections::HashSet; use std::fs; use std::path::PathBuf; use utils::{self, fixture}; +use wasm_pack::command::build::Target; use wasm_pack::{self, license, manifest}; #[test] @@ -66,7 +67,7 @@ fn it_creates_a_package_json_default_path() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &None, false, "", &step) + .write_package_json(&out_dir, &None, false, &Target::Bundler, &step) .is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); fs::metadata(package_json_path).unwrap(); @@ -102,7 +103,7 @@ fn it_creates_a_package_json_provided_path() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &None, false, "", &step) + .write_package_json(&out_dir, &None, false, &Target::Bundler, &step) .is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); fs::metadata(package_json_path).unwrap(); @@ -131,7 +132,13 @@ fn it_creates_a_package_json_provided_path_with_scope() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &Some("test".to_string()), false, "", &step) + .write_package_json( + &out_dir, + &Some("test".to_string()), + false, + &Target::Bundler, + &step + ) .is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); fs::metadata(package_json_path).unwrap(); @@ -160,7 +167,7 @@ fn it_creates_a_pkg_json_with_correct_files_on_node() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &None, false, "nodejs", &step) + .write_package_json(&out_dir, &None, false, &Target::Nodejs, &step) .is_ok()); let package_json_path = &out_dir.join("package.json"); fs::metadata(package_json_path).unwrap(); @@ -196,7 +203,7 @@ fn it_creates_a_pkg_json_with_correct_files_on_nomodules() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &None, false, "no-modules", &step) + .write_package_json(&out_dir, &None, false, &Target::NoModules, &step) .is_ok()); let package_json_path = &out_dir.join("package.json"); fs::metadata(package_json_path).unwrap(); @@ -231,7 +238,7 @@ fn it_creates_a_pkg_json_in_out_dir() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &None, false, "", &step) + .write_package_json(&out_dir, &None, false, &Target::Bundler, &step) .is_ok()); let package_json_path = &fixture.path.join(&out_dir).join("package.json"); @@ -247,7 +254,7 @@ fn it_creates_a_package_json_with_correct_keys_when_types_are_skipped() { let step = wasm_pack::progressbar::Step::new(1); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); assert!(crate_data - .write_package_json(&out_dir, &None, true, "", &step) + .write_package_json(&out_dir, &None, true, &Target::Bundler, &step) .is_ok()); let package_json_path = &out_dir.join("package.json"); fs::metadata(package_json_path).unwrap(); @@ -310,7 +317,7 @@ fn it_sets_homepage_field_if_available_in_cargo_toml() { let step = wasm_pack::progressbar::Step::new(2); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); crate_data - .write_package_json(&out_dir, &None, true, "", &step) + .write_package_json(&out_dir, &None, true, &Target::Bundler, &step) .unwrap(); let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap(); @@ -327,7 +334,7 @@ fn it_sets_homepage_field_if_available_in_cargo_toml() { let step = wasm_pack::progressbar::Step::new(2); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); crate_data - .write_package_json(&out_dir, &None, true, "", &step) + .write_package_json(&out_dir, &None, true, &Target::Bundler, &step) .unwrap(); let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap(); @@ -430,7 +437,7 @@ fn it_lists_license_files_in_files_field_of_package_json() { wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); license::copy_from_crate(&crate_data, &fixture.path, &out_dir, &step).unwrap(); crate_data - .write_package_json(&out_dir, &None, false, "", &step) + .write_package_json(&out_dir, &None, false, &Target::Bundler, &step) .unwrap(); let package_json_path = &fixture.path.join("pkg").join("package.json");