Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for --target web #567

Merged
merged 1 commit into from
Mar 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 | Usage | 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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for making this an enum it's a clear improvement!

"nodejs" => "--nodejs",
"no-modules" => "--no-modules",
_ => "--browser",
Target::Nodejs => "--nodejs",
Target::NoModules => "--no-modules",
Target::Web => "--web",
Target::Bundler => "--browser",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we perhaps deprecate --browser and add a --bundler alias in wasm-bindgen? (you might already be on this, in which case linking to a PR/issue would be great)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that long term we may want to but for now it serves a purpose we haven't displaced, so it can't be removed just yet

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to open a tracking issue? let me know what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened up rustwasm/wasm-bindgen#1332 for this

};
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