Merge pull request #567 from alexcrichton/web-target

Add support for `--target web`
master
ashley williams 6 years ago committed by GitHub
commit 4a84b499d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      docs/src/commands/build.md
  2. 11
      src/bindgen.rs
  3. 54
      src/command/build.rs
  4. 4
      src/command/publish/mod.rs
  5. 44
      src/manifest/mod.rs
  6. 27
      tests/all/manifest.rs

@ -47,20 +47,26 @@ The exact meaning of the profile flags may evolve as the platform matures.
## Target ## Target
The `build` command accepts a `--target` argument. This will customize the output files The `build` command accepts a `--target` argument. This will customize the JS
to align with a particular type of JS module. This allows wasm-pack to generate either that is emitted and how the WebAssembly files are instantiated and loaded. For
ES6 modules or CommonJS modules for use in browser and in NodeJS. Defaults to `browser`. more documentation on the various strategies here, see the [documentation on
The options are: using the compiled output][deploy].
``` ```
wasm-pack build --target nodejs wasm-pack build --target nodejs
``` ```
| Option | Description | | Option | Usage | Description |
|-----------|-----------------------------------------------------------------------------------------------------------------| |-----------|------------|-----------------------------------------------------------------------------------------------------|
| `nodejs` | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. | | *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. |
| `no-modules` | Outputs JS that use no modules. `browser` key in `package.json`. | | `nodejs` | [Node.js][deploy-nodejs] | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` 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. | | `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 ## Scope

@ -2,7 +2,7 @@
use binary_install::{Cache, Download}; use binary_install::{Cache, Download};
use child; use child;
use command::build::BuildProfile; use command::build::{BuildProfile, Target};
use emoji; use emoji;
use failure::{self, ResultExt}; use failure::{self, ResultExt};
use log::debug; use log::debug;
@ -176,7 +176,7 @@ pub fn wasm_bindgen_build(
bindgen: &Download, bindgen: &Download,
out_dir: &Path, out_dir: &Path,
disable_dts: bool, disable_dts: bool,
target: &str, target: &Target,
profile: BuildProfile, profile: BuildProfile,
step: &Step, step: &Step,
) -> Result<(), failure::Error> { ) -> Result<(), failure::Error> {
@ -203,9 +203,10 @@ pub fn wasm_bindgen_build(
"--typescript" "--typescript"
}; };
let target_arg = match target { let target_arg = match target {
"nodejs" => "--nodejs", Target::Nodejs => "--nodejs",
"no-modules" => "--no-modules", Target::NoModules => "--no-modules",
_ => "--browser", Target::Web => "--web",
Target::Bundler => "--browser",
}; };
let bindgen_path = bindgen.binary("wasm-bindgen")?; let bindgen_path = bindgen.binary("wasm-bindgen")?;
let mut cmd = Command::new(bindgen_path); let mut cmd = Command::new(bindgen_path);

@ -26,7 +26,7 @@ pub struct Build {
pub crate_data: manifest::CrateData, pub crate_data: manifest::CrateData,
pub scope: Option<String>, pub scope: Option<String>,
pub disable_dts: bool, pub disable_dts: bool,
pub target: String, pub target: Target,
pub profile: BuildProfile, pub profile: BuildProfile,
pub mode: BuildMode, pub mode: BuildMode,
pub out_dir: PathBuf, 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<Self, Error> {
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 /// The build profile controls whether optimizations, debug info, and assertions
/// are enabled or disabled. /// are enabled or disabled.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -99,8 +137,8 @@ pub struct BuildOptions {
pub disable_dts: bool, pub disable_dts: bool,
#[structopt(long = "target", short = "t", default_value = "browser")] #[structopt(long = "target", short = "t", default_value = "browser")]
/// Sets the target environment. [possible values: browser, nodejs, no-modules] /// Sets the target environment. [possible values: browser, nodejs, web, no-modules]
pub target: String, pub target: Target,
#[structopt(long = "debug")] #[structopt(long = "debug")]
/// Deprecated. Renamed to `--dev`. /// Deprecated. Renamed to `--dev`.
@ -133,9 +171,9 @@ impl Default for BuildOptions {
Self { Self {
path: None, path: None,
scope: None, scope: None,
mode: BuildMode::Normal, mode: BuildMode::default(),
disable_dts: false, disable_dts: false,
target: String::new(), target: Target::default(),
debug: false, debug: false,
dev: false, dev: false,
release: false, release: false,
@ -165,12 +203,6 @@ impl Build {
_ => bail!("Can only supply one of the --dev, --release, or --profiling flags"), _ => 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 { Ok(Build {
crate_path, crate_path,
crate_data, crate_data,

@ -2,7 +2,7 @@
pub mod access; pub mod access;
use self::access::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 command::utils::{find_pkg_directory, set_crate_path};
use dialoguer::{Confirmation, Input, Select}; use dialoguer::{Confirmation, Input, Select};
use failure::Error; use failure::Error;
@ -10,6 +10,7 @@ use log::info;
use npm; use npm;
use std::path::PathBuf; use std::path::PathBuf;
use std::result; use std::result;
use std::str::FromStr;
use PBAR; use PBAR;
/// Creates a tarball from a 'pkg' directory /// Creates a tarball from a 'pkg' directory
@ -45,6 +46,7 @@ pub fn publish(
.default(0) .default(0)
.interact()? .interact()?
.to_string(); .to_string();
let target = Target::from_str(&target)?;
let build_opts = BuildOptions { let build_opts = BuildOptions {
path: Some(crate_path.clone()), path: Some(crate_path.clone()),
target, target,

@ -11,7 +11,7 @@ use self::npm::{
repository::Repository, CommonJSPackage, ESModulesPackage, NoModulesPackage, NpmPackage, repository::Repository, CommonJSPackage, ESModulesPackage, NoModulesPackage, NpmPackage,
}; };
use cargo_metadata::Metadata; use cargo_metadata::Metadata;
use command::build::BuildProfile; use command::build::{BuildProfile, Target};
use emoji; use emoji;
use failure::{Error, ResultExt}; use failure::{Error, ResultExt};
use progressbar::Step; use progressbar::Step;
@ -377,19 +377,18 @@ impl CrateData {
out_dir: &Path, out_dir: &Path,
scope: &Option<String>, scope: &Option<String>,
disable_dts: bool, disable_dts: bool,
target: &str, target: &Target,
step: &Step, step: &Step,
) -> Result<(), Error> { ) -> Result<(), Error> {
let msg = format!("{}Writing a package.json...", emoji::MEMO); let msg = format!("{}Writing a package.json...", emoji::MEMO);
PBAR.step(step, &msg); PBAR.step(step, &msg);
let pkg_file_path = out_dir.join("package.json"); let pkg_file_path = out_dir.join("package.json");
let npm_data = if target == "nodejs" { let npm_data = match target {
self.to_commonjs(scope, disable_dts, out_dir) Target::Nodejs => self.to_commonjs(scope, disable_dts, out_dir),
} else if target == "no-modules" { Target::NoModules => self.to_nomodules(scope, disable_dts, out_dir),
self.to_nomodules(scope, disable_dts, out_dir) Target::Bundler => self.to_esmodules(scope, disable_dts, out_dir),
} else { Target::Web => self.to_web(scope, disable_dts, out_dir),
self.to_esmodules(scope, disable_dts, out_dir)
}; };
let npm_json = serde_json::to_string_pretty(&npm_data)?; let npm_json = serde_json::to_string_pretty(&npm_data)?;
@ -522,6 +521,35 @@ impl CrateData {
}) })
} }
fn to_web(&self, scope: &Option<String>, 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( fn to_nomodules(
&self, &self,
scope: &Option<String>, scope: &Option<String>,

@ -3,6 +3,7 @@ use std::collections::HashSet;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use utils::{self, fixture}; use utils::{self, fixture};
use wasm_pack::command::build::Target;
use wasm_pack::{self, license, manifest}; use wasm_pack::{self, license, manifest};
#[test] #[test]
@ -66,7 +67,7 @@ fn it_creates_a_package_json_default_path() {
let step = wasm_pack::progressbar::Step::new(1); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data assert!(crate_data
.write_package_json(&out_dir, &None, false, "", &step) .write_package_json(&out_dir, &None, false, &Target::Bundler, &step)
.is_ok()); .is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json"); let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap(); 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); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data assert!(crate_data
.write_package_json(&out_dir, &None, false, "", &step) .write_package_json(&out_dir, &None, false, &Target::Bundler, &step)
.is_ok()); .is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json"); let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap(); 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); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data 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()); .is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json"); let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap(); 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); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data assert!(crate_data
.write_package_json(&out_dir, &None, false, "nodejs", &step) .write_package_json(&out_dir, &None, false, &Target::Nodejs, &step)
.is_ok()); .is_ok());
let package_json_path = &out_dir.join("package.json"); let package_json_path = &out_dir.join("package.json");
fs::metadata(package_json_path).unwrap(); 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); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data 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()); .is_ok());
let package_json_path = &out_dir.join("package.json"); let package_json_path = &out_dir.join("package.json");
fs::metadata(package_json_path).unwrap(); 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); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data assert!(crate_data
.write_package_json(&out_dir, &None, false, "", &step) .write_package_json(&out_dir, &None, false, &Target::Bundler, &step)
.is_ok()); .is_ok());
let package_json_path = &fixture.path.join(&out_dir).join("package.json"); 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); let step = wasm_pack::progressbar::Step::new(1);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
assert!(crate_data assert!(crate_data
.write_package_json(&out_dir, &None, true, "", &step) .write_package_json(&out_dir, &None, true, &Target::Bundler, &step)
.is_ok()); .is_ok());
let package_json_path = &out_dir.join("package.json"); let package_json_path = &out_dir.join("package.json");
fs::metadata(package_json_path).unwrap(); 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); let step = wasm_pack::progressbar::Step::new(2);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
crate_data crate_data
.write_package_json(&out_dir, &None, true, "", &step) .write_package_json(&out_dir, &None, true, &Target::Bundler, &step)
.unwrap(); .unwrap();
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).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); let step = wasm_pack::progressbar::Step::new(2);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
crate_data crate_data
.write_package_json(&out_dir, &None, true, "", &step) .write_package_json(&out_dir, &None, true, &Target::Bundler, &step)
.unwrap(); .unwrap();
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).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(); wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
license::copy_from_crate(&crate_data, &fixture.path, &out_dir, &step).unwrap(); license::copy_from_crate(&crate_data, &fixture.path, &out_dir, &step).unwrap();
crate_data crate_data
.write_package_json(&out_dir, &None, false, "", &step) .write_package_json(&out_dir, &None, false, &Target::Bundler, &step)
.unwrap(); .unwrap();
let package_json_path = &fixture.path.join("pkg").join("package.json"); let package_json_path = &fixture.path.join("pkg").join("package.json");

Loading…
Cancel
Save