Skip to content

Commit

Permalink
Add support for --target web
Browse files Browse the repository at this point in the history
This commit adds support for the new `--web` flag in `wasm-bindgen`
under the flag name `--target web`. To ensure that it was plubmed around
the stringly-typed `target` type was switched to an `enum Target` to
ensure that all cases it's looked at are handled appropriately for the
new `web` target.
  • Loading branch information
alexcrichton committed Mar 8, 2019
1 parent 2967f8b commit b0f42b4
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 44 deletions.
24 changes: 15 additions & 9 deletions docs/src/commands/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 6 additions & 5 deletions src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand All @@ -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);
Expand Down
54 changes: 43 additions & 11 deletions src/command/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct Build {
pub crate_data: manifest::CrateData,
pub scope: Option<String>,
pub disable_dts: bool,
pub target: String,
pub target: Target,
pub profile: BuildProfile,
pub mode: BuildMode,
pub out_dir: PathBuf,
Expand Down Expand Up @@ -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
/// are enabled or disabled.
#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion src/command/publish/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
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;
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
Expand Down Expand Up @@ -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,
Expand Down
44 changes: 36 additions & 8 deletions src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -377,19 +377,18 @@ impl CrateData {
out_dir: &Path,
scope: &Option<String>,
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)?;
Expand Down Expand Up @@ -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(
&self,
scope: &Option<String>,
Expand Down
27 changes: 17 additions & 10 deletions tests/all/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit b0f42b4

Please sign in to comment.