diff --git a/README.md b/README.md index c0ca9f46..dd9202f3 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,10 @@ visiting that repo! ## 🎙️ Commands +- [`init`](docs/init.md): [**Deprecated**] Initialize an npm wasm pkg from a rustwasm crate +- [`build`](docs/build.md): Generate an npm wasm pkg from a rustwasm crate - [`init`](docs/init.md): Generate an npm wasm pkg from a rustwasm crate -- [`pack`](docs/pack-and-publish.md): Create a tarball of your rustwasm pkg -- [`publish`](docs/publish.md): Publish your rustwasm pkg to a registry +- [`pack` and `publish`](docs/pack-and-publish.md): Create a tarball of your rustwasm pkg and/or publish to a registry ## 📝 Logging @@ -89,7 +90,7 @@ check out our [contribution policy]. ``` 5. Install this tool: `cargo install wasm-pack` -6. Run `wasm-pack init`, optionally, pass a path to a dir or a scope (see above for details) +6. Run `wasm-pack build`, optionally, pass a path to a dir or a scope (see above for details) 7. This tool generates files in a `pkg` dir 8. To publish to npm, run `wasm-pack publish`. You may need to login to the registry you want to publish to. You can login using `wasm-pack login`. diff --git a/docs/build.md b/docs/build.md new file mode 100644 index 00000000..5fe9b620 --- /dev/null +++ b/docs/build.md @@ -0,0 +1,73 @@ +# wasm-pack build + +The `wasm-pack build` command creates the files neccessary for JavaScript +interoperability and for publishing a package to npm. This involves compiling +your code to wasm and generating a pkg folder. This pkg folder will contain the +wasm binary, a JS wrapper file, your `README`, and a `package.json` file. + +## Path + +The `wasm-pack build` command can be given an optional path argument, e.g.: + +``` +wasm-pack build examples/js-hello-world +``` + +This path should point to a directory that contains a `Cargo.toml` file. If no +path is given, the `build` command will run in the current directory. + +## Debug + +The init command accepts an optional `--debug` argument. This will build the +output package using cargo's +[default non-release profile][cargo-profile-sections-documentation]. Building +this way is faster but applies few optimizations to the output, and enables +debug assertions and other runtime correctness checks. + +The exact meaning of this flag may evolve as the platform matures. + +[cargo-profile-sections-documentation]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-profile-sections + +## 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: + +``` +wasm-pack build --target nodejs +``` + +| Option | Description | +|-----------|-----------------------------------------------------------------------------------------------------------------| +| `nodejs` | Outputs JS that uses CommonJS modules, for use with a `require` statement. | +| `browser` | Outputs JS that uses ES6 modules, primarily for use with `import` statements and/or bundlers such as `webpack`. | + +## Scope + +The init command also accepts an optional `--scope` argument. This will scope +your package name, which is useful if your package name might conflict with +something in the public registry. For example: + +``` +wasm-pack build examples/js-hello-world --scope test +``` + +This command would create a `package.json` file for a package called +`@test/js-hello-world`. For more information about scoping, you can refer to +the npm documentation [here][npm-scope-documentation]. + +[npm-scope-documentation]: https://docs.npmjs.com/misc/scope + +## Mode + +The `build` command accepts an optional `--mode` argument. +``` +wasm-pack build examples/js-hello-world --mode no-install +``` + +| Option | Description | +|---------------|------------------------------------------------------------------------------------------| +| `no-install` | `wasm-pack init` implicitly and create wasm binding without installing `wasm-bindgen`. | +| `normal` | do all the stuffs of `no-install` with installed `wasm-bindgen`. | diff --git a/docs/init.md b/docs/init.md index 91355c78..02d9924a 100644 --- a/docs/init.md +++ b/docs/init.md @@ -1,9 +1,9 @@ -# wasm-pack init +# wasm-pack init(Deprecated) The `wasm-pack init` command creates the files neccessary for JavaScript -interoperability and for publishing a package to npm. This involves compiling -your code to wasm and generating a pkg folder. This pkg folder will contain the -wasm binary, a JS wrapper file, your `README`, and a `package.json` file. +interoperability and for publishing a package to npm. This involves +generating a pkg folder. This pkg folder will contain the +`README` and a `package.json` file. ## Path @@ -46,27 +46,4 @@ This command would create a `package.json` file for a package called `@test/js-hello-world`. For more information about scoping, you can refer to the npm documentation [here][npm-scope-documentation]. -## Debug - -The init command accepts an optional `--debug` argument. This will build the -output package using cargo's -[default non-release profile][cargo-profile-sections-documentation]. Building -this way is faster but applies few optimizations to the output, and enables -debug assertions and other runtime correctness checks. - -The exact meaning of this flag may evolve as the platform matures. - -[npm-scope-documentation]: https://docs.npmjs.com/misc/scope -[cargo-profile-sections-documentation]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-profile-sections - -## Skipping build - -The init command accepts an optional `--skip-build` argument. - -This will deactivate those steps: -- installing wasm target (via cargo) -- compiling the code to wasm -- installing wasm-bindgen (via rustup) -- running wasm-bindgen on the built wasm - -Basically it will remains only the steps that update the metadata of `package.json`. +[npm-scope-documentation]: https://docs.npmjs.com/misc/scope \ No newline at end of file diff --git a/src/command/init.rs b/src/command/build.rs similarity index 60% rename from src/command/init.rs rename to src/command/build.rs index c405a80b..c9ebf59f 100644 --- a/src/command/init.rs +++ b/src/command/build.rs @@ -1,8 +1,6 @@ -//! Initializing a crate for packing `.wasm`s. - use bindgen; use build; -use command::utils::set_crate_path; +use command::utils::{create_pkg_dir, set_crate_path}; use emoji; use error::Error; use indicatif::HumanDuration; @@ -10,104 +8,85 @@ use manifest; use progressbar::Step; use readme; use slog::Logger; -use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::time::Instant; use PBAR; -/// Construct our `pkg` directory in the crate. -pub fn create_pkg_dir(path: &Path, step: &Step) -> Result<(), Error> { - let msg = format!("{}Creating a pkg directory...", emoji::FOLDER); - PBAR.step(step, &msg); - let pkg_dir_path = path.join("pkg"); - fs::create_dir_all(pkg_dir_path)?; - Ok(()) +/// Everything required to configure and run the `wasm-pack init` command. +pub(crate) struct Build { + pub crate_path: PathBuf, + pub scope: Option, + pub disable_dts: bool, + pub target: String, + pub debug: bool, + // build_config: Option, + pub crate_name: String, } -/// The `InitMode` determines which mode of initialization we are running, and +/// The `BuildMode` determines which mode of initialization we are running, and /// what build and install steps we perform. -pub enum InitMode { +pub enum BuildMode { /// Perform all the build and install steps. Normal, - /// Don't build the crate as a `.wasm` but do install tools and create - /// meta-data. - Nobuild, /// Don't install tools like `wasm-bindgen`, just use the global /// environment's existing versions to do builds. Noinstall, } -/// Everything required to configure and run the `wasm-pack init` command. -pub struct Init { - crate_path: PathBuf, - scope: Option, - disable_dts: bool, - target: String, +/// Everything required to configure and run the `wasm-pack build` command. +#[derive(Debug, StructOpt)] +pub struct BuildOptions { + /// The path to the Rust crate. + #[structopt(parse(from_os_str))] + pub path: Option, + + /// The npm scope to use in package.json, if any. + #[structopt(long = "scope", short = "s")] + pub scope: Option, + + #[structopt(long = "mode", short = "m", default_value = "normal")] + /// Sets steps to be run. [possible values: no-install, normal] + pub mode: String, + + #[structopt(long = "no-typescript")] + /// By default a *.d.ts file is generated for the generated JS file, but + /// this flag will disable generating this TypeScript file. + pub disable_dts: bool, + + #[structopt(long = "target", short = "t", default_value = "browser")] + /// Sets the target environment. [possible values: browser, nodejs] + pub target: String, + + #[structopt(long = "debug")] + /// Build without --release. debug: bool, - crate_name: String, + // build config from manifest + // build_config: Option, } -type InitStep = fn(&mut Init, &Step, &Logger) -> Result<(), Error>; - -impl Init { - /// Construct a new `Init` command. - pub fn new( - path: Option, - scope: Option, - disable_dts: bool, - target: String, - debug: bool, - ) -> Result { - let crate_path = set_crate_path(path); - let crate_name = manifest::get_crate_name(&crate_path)?; - Ok(Init { +impl From for Build { + fn from(build_opts: BuildOptions) -> Self { + let crate_path = set_crate_path(build_opts.path); + let crate_name = manifest::get_crate_name(&crate_path).unwrap(); + // let build_config = manifest::xxx(&crate_path).xxx(); + Build { crate_path, - scope, - disable_dts, - target, - debug, + scope: build_opts.scope, + disable_dts: build_opts.disable_dts, + target: build_opts.target, + debug: build_opts.debug, + // build_config, crate_name, - }) - } - - fn get_process_steps(mode: InitMode) -> Vec<(&'static str, InitStep)> { - macro_rules! steps { - ($($name:ident),+) => { - { - let mut steps: Vec<(&'static str, InitStep)> = Vec::new(); - $(steps.push((stringify!($name), Init::$name));)* - steps - } - }; - ($($name:ident,)*) => (steps![$($name),*]) - } - - match mode { - InitMode::Normal => steps![ - step_check_crate_config, - step_add_wasm_target, - step_build_wasm, - step_create_dir, - step_create_json, - step_copy_readme, - step_install_wasm_bindgen, - step_run_wasm_bindgen, - ], - InitMode::Nobuild => steps![step_create_dir, step_create_json, step_copy_readme,], - InitMode::Noinstall => steps![ - step_check_crate_config, - step_build_wasm, - step_create_dir, - step_create_json, - step_copy_readme, - step_run_wasm_bindgen - ], } } +} + +type BuildStep = fn(&mut Build, &Step, &Logger) -> Result<(), Error>; - /// Execute this `Init` command. - pub fn process(&mut self, log: &Logger, mode: InitMode) -> Result<(), Error> { - let process_steps = Init::get_process_steps(mode); +impl Build { + /// Execute this `Build` command. + pub fn run(&mut self, log: &Logger, mode: &BuildMode) -> Result<(), Error> { + let process_steps = Build::get_process_steps(mode); let mut step_counter = Step::new(process_steps.len()); @@ -136,6 +115,39 @@ impl Init { Ok(()) } + fn get_process_steps(mode: &BuildMode) -> Vec<(&'static str, BuildStep)> { + macro_rules! steps { + ($($name:ident),+) => { + { + let mut steps: Vec<(&'static str, BuildStep)> = Vec::new(); + $(steps.push((stringify!($name), Build::$name));)* + steps + } + }; + ($($name:ident,)*) => (steps![$($name),*]) + } + match &mode { + BuildMode::Normal => steps![ + step_check_crate_config, + step_add_wasm_target, + step_build_wasm, + step_create_dir, + step_create_json, + step_copy_readme, + step_install_wasm_bindgen, + step_run_wasm_bindgen, + ], + BuildMode::Noinstall => steps![ + step_check_crate_config, + step_build_wasm, + step_create_dir, + step_create_json, + step_copy_readme, + step_run_wasm_bindgen + ], + } + } + fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { info!(&log, "Checking crate configuration..."); manifest::check_crate_config(&self.crate_path, step)?; @@ -235,60 +247,3 @@ impl Init { Ok(()) } } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn init_normal_build() { - let steps: Vec<&str> = Init::get_process_steps(InitMode::Normal) - .into_iter() - .map(|(n, _)| n) - .collect(); - assert_eq!( - steps, - [ - "step_check_crate_config", - "step_add_wasm_target", - "step_build_wasm", - "step_create_dir", - "step_create_json", - "step_copy_readme", - "step_install_wasm_bindgen", - "step_run_wasm_bindgen" - ] - ); - } - - #[test] - fn init_skip_build() { - let steps: Vec<&str> = Init::get_process_steps(InitMode::Nobuild) - .into_iter() - .map(|(n, _)| n) - .collect(); - assert_eq!( - steps, - ["step_create_dir", "step_create_json", "step_copy_readme"] - ); - } - - #[test] - fn init_skip_install() { - let steps: Vec<&str> = Init::get_process_steps(InitMode::Noinstall) - .into_iter() - .map(|(n, _)| n) - .collect(); - assert_eq!( - steps, - [ - "step_check_crate_config", - "step_build_wasm", - "step_create_dir", - "step_create_json", - "step_copy_readme", - "step_run_wasm_bindgen" - ] - ); - } -} diff --git a/src/command/mod.rs b/src/command/mod.rs index 2b9ed8dc..9b20672c 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,12 +1,12 @@ //! CLI command structures, parsing, and execution. -pub mod init; +mod build; mod login; mod pack; mod publish; pub mod utils; -use self::init::{Init, InitMode}; +use self::build::{Build, BuildMode, BuildOptions}; use self::login::login; use self::pack::pack; use self::publish::publish; @@ -19,39 +19,14 @@ use PBAR; /// The various kinds of commands that `wasm-pack` can execute. #[derive(Debug, StructOpt)] pub enum Command { - #[structopt(name = "init")] - /// 🐣 initialize a package.json based on your compiled wasm! - Init { - /// The path to the Rust crate. - #[structopt(parse(from_os_str))] - path: Option, - - /// The npm scope to use in package.json, if any. - #[structopt(long = "scope", short = "s")] - scope: Option, - - #[structopt(long = "mode", short = "m", default_value = "normal")] - /// Sets steps to be run. [possible values: no-build, no-install, normal] - mode: String, - - #[structopt(long = "no-typescript")] - /// By default a *.d.ts file is generated for the generated JS file, but - /// this flag will disable generating this TypeScript file. - disable_dts: bool, - - #[structopt(long = "target", short = "t", default_value = "browser")] - /// Sets the target environment. [possible values: browser, nodejs] - target: String, - - #[structopt(long = "debug")] - /// Build without --release. - debug: bool, - }, + /// 🏗️ build your npm package! + #[structopt(name = "build", alias = "init")] + Build(BuildOptions), #[structopt(name = "pack")] /// 🍱 create a tar of your npm package but don't publish! Pack { - /// The path to the Rust crate. + /// The path to the Rust crate. #[structopt(parse(from_os_str))] path: Option, }, @@ -102,32 +77,14 @@ pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), Error // Run the correct command based off input and store the result of it so that we can clear // the progress bar then return it let status = match command { - Command::Init { - path, - scope, - mode, - disable_dts, - target, - debug, - } => { - info!(&log, "Running init command..."); - info!( - &log, - "Path: {:?}, Scope: {:?}, Skip build: {}, Disable Dts: {}, Target: {}, Debug: {}", - &path, - &scope, - &mode, - &disable_dts, - &target, - debug - ); - let modetype = match &*mode { - "no-build" => InitMode::Nobuild, - "no-install" => InitMode::Noinstall, - "normal" => InitMode::Normal, - _ => InitMode::Normal, + Command::Build(build_opts) => { + info!(&log, "Running build command..."); + let build_mode = match build_opts.mode.as_str() { + "no-install" => BuildMode::Noinstall, + "normal" => BuildMode::Normal, + _ => BuildMode::Normal, }; - Init::new(path, scope, disable_dts, target, debug)?.process(&log, modetype) + Build::from(build_opts).run(&log, &build_mode) } Command::Pack { path } => { info!(&log, "Running pack command..."); diff --git a/src/command/utils.rs b/src/command/utils.rs index 3e0fb705..c66b089e 100644 --- a/src/command/utils.rs +++ b/src/command/utils.rs @@ -1,6 +1,11 @@ //! Utility functions for commands. +use emoji; +use error::Error; +use progressbar::Step; +use std::fs; use std::path::{Path, PathBuf}; +use PBAR; /// If an explicit path is given, then use it, otherwise assume the current /// directory is the crate path. @@ -13,6 +18,15 @@ pub fn set_crate_path(path: Option) -> PathBuf { crate_path } +/// Construct our `pkg` directory in the crate. +pub fn create_pkg_dir(path: &Path, step: &Step) -> Result<(), Error> { + let msg = format!("{}Creating a pkg directory...", emoji::FOLDER); + PBAR.step(step, &msg); + let pkg_dir_path = path.join("pkg"); + fs::create_dir_all(pkg_dir_path)?; + Ok(()) +} + /// Locates the pkg directory from a specific path /// Returns None if unable to find the 'pkg' directory pub fn find_pkg_directory(path: &Path) -> Option { diff --git a/src/logger.rs b/src/logger.rs index 3ddea3a7..d100ccf7 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -33,7 +33,7 @@ pub fn new(cmd: &Command, verbosity: u8) -> Result { /// Figure out where to stick the log based off the command arguments given fn log_file_path(cmd: &Command) -> PathBuf { let path = match cmd { - Command::Init { path, .. } => path, + Command::Build(build_opts) => &build_opts.path, Command::Pack { path } => path, Command::Publish { path } => path, Command::Login { .. } => &None, diff --git a/src/main.rs b/src/main.rs index 68e6e4b2..0617f116 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ extern crate structopt; extern crate wasm_pack; use failure::Fail; +use std::env; use structopt::StructOpt; use wasm_pack::{command::run_wasm_pack, error::Error, logger, Cli}; @@ -20,6 +21,11 @@ fn main() { } fn run() -> Result<(), Error> { + // Deprecate `init` + if let Some("init") = env::args().nth(1).as_ref().map(|arg| arg.as_str()) { + println!("wasm-pack init is deprecated, consider using wasm-pack build"); + } + let args = Cli::from_args(); let log = logger::new(&args.cmd, args.verbosity)?; run_wasm_pack(args.cmd, &log)?; diff --git a/tests/all/manifest.rs b/tests/all/manifest.rs index 55431dce..714d0a42 100644 --- a/tests/all/manifest.rs +++ b/tests/all/manifest.rs @@ -55,7 +55,7 @@ fn it_recognizes_a_map_during_depcheck() { fn it_creates_a_package_json_default_path() { let fixture = fixture::fixture("."); let step = wasm_pack::progressbar::Step::new(1); - wasm_pack::command::init::create_pkg_dir(&fixture.path, &step).unwrap(); + wasm_pack::command::utils::create_pkg_dir(&fixture.path, &step).unwrap(); assert!(manifest::write_package_json(&fixture.path, &None, false, "", &step).is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); @@ -83,7 +83,7 @@ fn it_creates_a_package_json_default_path() { fn it_creates_a_package_json_provided_path() { let fixture = fixture::fixture("tests/fixtures/js-hello-world"); let step = wasm_pack::progressbar::Step::new(1); - wasm_pack::command::init::create_pkg_dir(&fixture.path, &step).unwrap(); + wasm_pack::command::utils::create_pkg_dir(&fixture.path, &step).unwrap(); assert!(manifest::write_package_json(&fixture.path, &None, false, "", &step).is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); @@ -104,7 +104,7 @@ fn it_creates_a_package_json_provided_path() { fn it_creates_a_package_json_provided_path_with_scope() { let fixture = fixture::fixture("tests/fixtures/scopes"); let step = wasm_pack::progressbar::Step::new(1); - wasm_pack::command::init::create_pkg_dir(&fixture.path, &step).unwrap(); + wasm_pack::command::utils::create_pkg_dir(&fixture.path, &step).unwrap(); assert!( manifest::write_package_json(&fixture.path, &Some("test".to_string()), false, "", &step) .is_ok() @@ -128,7 +128,7 @@ fn it_creates_a_package_json_provided_path_with_scope() { fn it_creates_a_pkg_json_with_correct_files_on_node() { let fixture = fixture::fixture("."); let step = wasm_pack::progressbar::Step::new(1); - wasm_pack::command::init::create_pkg_dir(&fixture.path, &step).unwrap(); + wasm_pack::command::utils::create_pkg_dir(&fixture.path, &step).unwrap(); assert!(manifest::write_package_json(&fixture.path, &None, false, "nodejs", &step).is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); @@ -157,7 +157,7 @@ fn it_creates_a_pkg_json_with_correct_files_on_node() { fn it_creates_a_package_json_with_correct_keys_when_types_are_skipped() { let fixture = fixture::fixture("."); let step = wasm_pack::progressbar::Step::new(1); - wasm_pack::command::init::create_pkg_dir(&fixture.path, &step).unwrap(); + wasm_pack::command::utils::create_pkg_dir(&fixture.path, &step).unwrap(); assert!(manifest::write_package_json(&fixture.path, &None, true, "", &step).is_ok()); let package_json_path = &fixture.path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok());