├── npm ├── .gitignore ├── run.js ├── install.js ├── package.json ├── README.md └── binary.js ├── rsw.png ├── src ├── main.rs ├── template │ ├── rsw_cargo.toml │ ├── rsw_readme.md │ ├── rsw_lib.rs │ ├── mod.rs │ └── rsw.toml ├── core │ ├── mod.rs │ ├── init.rs │ ├── clean.rs │ ├── error.rs │ ├── link.rs │ ├── build.rs │ ├── create.rs │ ├── info.rs │ ├── watch.rs │ └── cli.rs ├── lib.rs ├── config.rs └── utils.rs ├── .gitignore ├── Cargo.toml ├── LICENSE ├── CHANGELOG.md ├── README.zh_CN.md ├── README.md └── .github └── workflows └── release.yml /npm/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /rsw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rwasm/rsw-rs/HEAD/rsw.png -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | rsw::rsw_cli(); 4 | } 5 | -------------------------------------------------------------------------------- /npm/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { run } = require("./binary"); 4 | run(); -------------------------------------------------------------------------------- /npm/install.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { install } = require("./binary"); 4 | install(); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | target/ 4 | Cargo.lock 5 | 6 | node_modules/ 7 | yarn.lock 8 | package-lock.json 9 | 10 | /rsw.toml 11 | /@rsw 12 | /rsw-* 13 | /.rsw 14 | /.watchignore 15 | 16 | # IDE 17 | .vscode/ 18 | .idea/ 19 | /npm/bin/ -------------------------------------------------------------------------------- /src/template/rsw_cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsw-template" 3 | version = "0.1.0" 4 | authors = [] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | wasm-bindgen = "0.2.83" 14 | -------------------------------------------------------------------------------- /src/template/rsw_readme.md: -------------------------------------------------------------------------------- 1 | # rsw-template 2 | 3 | ## Usage 4 | 5 | [rsw-rs doc](https://github.com/lencx/rsw-rs) 6 | 7 | ```bash 8 | # install rsw 9 | cargo install rsw 10 | 11 | # --- help --- 12 | # rsw help 13 | rsw -h 14 | # new help 15 | rsw new -h 16 | 17 | # --- usage --- 18 | # dev 19 | rsw watch 20 | 21 | # production 22 | rsw build 23 | ``` 24 | -------------------------------------------------------------------------------- /src/template/rsw_lib.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | // Import the \`window.alert\` function from the Web. 4 | #[wasm_bindgen] 5 | extern "C" { 6 | fn alert(s: &str); 7 | } 8 | 9 | // Export a \`greet\` function from Rust to JavaScript, that alerts a 10 | // hello message. 11 | #[wasm_bindgen] 12 | pub fn greet(name: &str) { 13 | alert(&format!("[rsw] Hello, {}!", name)); 14 | } 15 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | //! rsw cli 2 | 3 | mod build; 4 | mod clean; 5 | mod cli; 6 | mod create; 7 | mod error; 8 | mod info; 9 | mod init; 10 | mod link; 11 | mod watch; 12 | 13 | pub use self::build::Build; 14 | pub use self::clean::Clean; 15 | pub use self::cli::Cli; 16 | pub use self::create::Create; 17 | pub use self::error::RswErr; 18 | pub use self::info::RswInfo; 19 | pub use self::init::Init; 20 | pub use self::link::Link; 21 | pub use self::watch::Watch; 22 | -------------------------------------------------------------------------------- /src/core/init.rs: -------------------------------------------------------------------------------- 1 | //! rsw init 2 | 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::path::Path; 6 | 7 | use crate::core::RswInfo; 8 | use crate::{ 9 | config, template, 10 | utils::{path_exists, print}, 11 | }; 12 | 13 | pub struct Init; 14 | 15 | impl Init { 16 | pub fn init() -> std::io::Result<()> { 17 | if !path_exists(Path::new(config::RSW_FILE)) { 18 | File::create(config::RSW_FILE)?.write_all(template::RSW_TOML)?; 19 | print(RswInfo::RswTomlOk); 20 | } else { 21 | print(RswInfo::RswTomExist); 22 | } 23 | 24 | Ok(()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsw" 3 | version = "0.8.0" 4 | description = "wasm-pack based build tool" 5 | edition = "2021" 6 | authors = ["lencx "] 7 | homepage = "https://github.com/lencx/rsw-rs" 8 | repository = "https://github.com/lencx/rsw-rs" 9 | keywords = ["rsw", "wasm-pack", "webassembly", "wasm", "npm"] 10 | license = "MIT" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | anyhow = "1.0.52" 16 | clap = { version = "3.0.5", features = ["derive"] } 17 | colored = "2.0.0" 18 | env_logger = "0.9.0" 19 | log = "0.4.14" 20 | notify = "4.0.17" 21 | path-clean = "0.1.0" 22 | regex = "1.5.4" 23 | serde = "1.0.133" 24 | serde_derive = "1.0.133" 25 | toml = "0.5.8" 26 | which = "4.2.5" 27 | ignore = "0.4.18" 28 | tokio = { version = "1.18.0", features = ["macros", "rt-multi-thread"] } 29 | -------------------------------------------------------------------------------- /npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rsw/cli", 3 | "version": "0.7.24", 4 | "rsw_version": "0.7.12", 5 | "description": "🦞 wasm-pack based build tool", 6 | "author": "lencx ", 7 | "license": "MIT", 8 | "main": "binary.js", 9 | "scripts": { 10 | "postinstall": "node ./install.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/rwasm/rsw-rs" 15 | }, 16 | "keywords": [ 17 | "rsw", 18 | "wasm", 19 | "rust-wasm", 20 | "registry", 21 | "cli", 22 | "rust", 23 | "npm", 24 | "package" 25 | ], 26 | "bugs": { 27 | "url": "https://github.com/rwasm/rsw-rs/issues" 28 | }, 29 | "homepage": "https://github.com/rwasm/rsw-rs#readme", 30 | "dependencies": { 31 | "axios": "^0.27.2", 32 | "binary-install": "^1.0.6", 33 | "rimraf": "^3.0.2", 34 | "tar": "^6.1.11" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /npm/README.md: -------------------------------------------------------------------------------- 1 | # @rsw/cli 2 | 3 | ## Pre-installed 4 | 5 | - [rust](https://www.rust-lang.org/learn/get-started) 6 | - [nodejs](https://nodejs.org) 7 | - [wasm-pack](https://github.com/rustwasm/wasm-pack) 8 | 9 | ## Quick start 10 | 11 | ```bash 12 | # https://github.com/lencx/create-mpl 13 | # npm 6.x 14 | npm init mpl@latest my-app --type wasm 15 | 16 | # npm 7+, extra double-dash is needed: 17 | npm init mpl@latest my-app -- --type wasm 18 | ``` 19 | 20 | --- 21 | 22 | ## Usgae 23 | 24 | ```bash 25 | # install 26 | npm install -g @rsw/cli 27 | ``` 28 | 29 | ```bash 30 | # help 31 | rsw -h 32 | 33 | # rsw.toml - initial configuration 34 | rsw init 35 | 36 | # generate a wasm project 37 | rsw new 38 | 39 | # dev mode 40 | rsw watch 41 | 42 | # release mode 43 | rsw build 44 | 45 | # clean - link & build 46 | rsw clean 47 | ``` 48 | 49 | [rsw docs](https://github.com/lencx/rsw-rs/blob/main/README.md) 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 lencx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/core/clean.rs: -------------------------------------------------------------------------------- 1 | //! rsw clean 2 | 3 | use std::collections::HashMap; 4 | use std::path::PathBuf; 5 | 6 | use crate::config::RswConfig; 7 | use crate::core::{Link, RswInfo}; 8 | use crate::utils::{path_exists, print}; 9 | 10 | pub struct Clean; 11 | 12 | // clean: link & build 13 | impl Clean { 14 | pub fn init(config: RswConfig) { 15 | let mut crates: Vec = Vec::new(); 16 | let mut path_map: HashMap = HashMap::new(); 17 | 18 | for i in &config.crates { 19 | let rsw_crate = i.clone(); 20 | let crate_path = PathBuf::from(rsw_crate.root.as_ref().unwrap()) 21 | .join(&i.name) 22 | .join(rsw_crate.out_dir.unwrap()); 23 | 24 | let pkg_path = crate_path.to_string_lossy().to_string(); 25 | 26 | if path_exists(&crate_path) { 27 | path_map.insert(pkg_path, crate_path); 28 | } 29 | 30 | crates.push(rsw_crate.name); 31 | } 32 | 33 | Link::unlink(&config.cli.unwrap(), crates); 34 | 35 | for (_crate, _path) in path_map { 36 | std::fs::remove_dir_all(_path).unwrap(); 37 | print(RswInfo::Clean("package".into(), _crate)); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.8.0 4 | 5 | - feat: `rsw.toml` adds `scope` field 6 | 7 | ## 0.7.12 8 | 9 | - fix: `config.cli` optional with default to `npm` 10 | 11 | ## 0.7.11 12 | 13 | - fix: watch mode in windows doesn't refresh 14 | 15 | ## 0.7.10 16 | 17 | - fix: build link 18 | 19 | ## 0.7.7 20 | 21 | - fix: npm binary install 22 | 23 | ## 0.7.6 24 | 25 | - feat: watch abort 26 | 27 | ## 0.7.5 28 | 29 | - feat: add .watchignore 30 | 31 | ## 0.7.4 32 | 33 | - fix: yarn link 34 | 35 | ## 0.7.3 36 | 37 | - fix: path clean 38 | - fix: `rsw.toml` - the `run` field is invalid 39 | 40 | ## 0.7.2 41 | 42 | - fix: check env 43 | 44 | ## 0.7.1 45 | 46 | - fix: crate root 47 | 48 | ## 0.7.0 49 | 50 | - add `.rsw/rsw.crates` 51 | 52 | ## 0.6.0 53 | 54 | - add `.rsw` dir 55 | 56 | ## 0.5.0 57 | 58 | - link - npm, yarn or pnpm 59 | - rsw clean - link & build 60 | 61 | ## 0.4.0 62 | 63 | - rsw.log - generate log files in watch mode 64 | 65 | ## 0.3.0 66 | 67 | - npm install 68 | 69 | ## 0.2.0 70 | 71 | - rsw new (rsw | user) 72 | - add logger 73 | 74 | ## 0.1.0 75 | 76 | - rsw new (wasm-pack new) 77 | - rsw init - generate `rsw.toml` 78 | - rsw watch 79 | 80 | ## 0.0.2 81 | 82 | - rsw build 83 | - rsw.toml 84 | 85 | ## 0.0.1 86 | 87 | Initial release. 88 | -------------------------------------------------------------------------------- /src/core/error.rs: -------------------------------------------------------------------------------- 1 | use colored::Colorize; 2 | use core::fmt::Display; 3 | 4 | pub enum RswErr { 5 | WasmPack, 6 | Config(std::io::Error), 7 | ParseToml(toml::de::Error), 8 | WatchFile(notify::Error), 9 | Crate(String, std::io::Error), 10 | } 11 | 12 | impl Display for RswErr { 13 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 14 | match self { 15 | RswErr::WasmPack => { 16 | write!(f, 17 | "{} wasm-pack {}\nCannot find wasm-pack in your PATH. Please make sure wasm-pack is installed.", 18 | "[⚙️ rsw::env]".red().on_black(), 19 | "https://github.com/rustwasm/wasm-pack".green(), 20 | ) 21 | } 22 | RswErr::Config(_err) => { 23 | write!( 24 | f, 25 | "{} {} must exist in the project root path.", 26 | "[⚙️ rsw.toml]".red().on_black(), 27 | "rsw.toml".yellow(), 28 | // _err, 29 | ) 30 | } 31 | RswErr::ParseToml(err) => { 32 | write!(f, "{} {}", "[⚙️ rsw.toml]".red().on_black(), err) 33 | } 34 | RswErr::WatchFile(e) => { 35 | write!( 36 | f, 37 | "{} Error while trying to watch the files:\n\t{}", 38 | "[🦀 rsw::crate]".red().on_black(), 39 | e 40 | ) 41 | } 42 | RswErr::Crate(name, err) => { 43 | write!( 44 | f, 45 | "{} {} {}", 46 | "[🦀 rsw::crate]".red().on_black(), 47 | name.yellow(), 48 | err 49 | ) 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /npm/binary.js: -------------------------------------------------------------------------------- 1 | const { Binary } = require('binary-install'); 2 | const os = require('os'); 3 | 4 | const name = 'rsw'; 5 | const { rsw_version: version, repository } = require('./package.json'); 6 | 7 | const supportedPlatforms = [ 8 | { 9 | TYPE: 'Windows_NT', 10 | ARCHITECTURE: 'x64', 11 | RUST_TARGET: 'x86_64-pc-windows-msvc', 12 | BINARY_NAME: `${name}.exe` 13 | }, 14 | { 15 | TYPE: 'Linux', 16 | ARCHITECTURE: 'x64', 17 | RUST_TARGET: 'x86_64-unknown-linux-musl', 18 | BINARY_NAME: name 19 | }, 20 | { 21 | TYPE: 'Darwin', 22 | ARCHITECTURE: 'x64', 23 | RUST_TARGET: 'x86_64-apple-darwin', 24 | BINARY_NAME: name 25 | } 26 | ]; 27 | 28 | const getPlatformMetadata = () => { 29 | const type = os.type(); 30 | const architecture = os.arch(); 31 | 32 | for (let supportedPlatform of supportedPlatforms) { 33 | if ( 34 | type === supportedPlatform.TYPE && 35 | architecture === supportedPlatform.ARCHITECTURE 36 | ) { 37 | return supportedPlatform; 38 | } 39 | } 40 | 41 | error( 42 | `Platform with type '${type}' and architecture '${architecture}' is not supported by ${name}.\nYour system must be one of the following:\n\n${cTable.getTable( 43 | supportedPlatforms 44 | )}` 45 | ); 46 | }; 47 | 48 | const getBinary = () => { 49 | const platformMetadata = getPlatformMetadata(); 50 | // the url for this binary is constructed from values in `package.json` 51 | const url = `${repository.url}/releases/download/v${version}/rsw-v${version}-${platformMetadata.RUST_TARGET}.tar.gz`; 52 | return new Binary(platformMetadata.BINARY_NAME, url); 53 | }; 54 | 55 | const run = () => { 56 | const binary = getBinary(); 57 | binary.run(); 58 | }; 59 | 60 | const install = () => { 61 | const binary = getBinary(); 62 | binary.install(); 63 | }; 64 | 65 | module.exports = { 66 | install, 67 | run 68 | }; 69 | -------------------------------------------------------------------------------- /src/template/mod.rs: -------------------------------------------------------------------------------- 1 | //! rsw template 2 | 3 | use std::path::Path; 4 | 5 | use crate::utils::load_file_contents; 6 | 7 | // config 8 | pub static RSW_TOML: &[u8] = include_bytes!("rsw.toml"); 9 | 10 | // crate 11 | pub static CARGO_TOML: &[u8] = include_bytes!("rsw_cargo.toml"); 12 | pub static LIB_RS: &[u8] = include_bytes!("rsw_lib.rs"); 13 | pub static README: &[u8] = include_bytes!("rsw_readme.md"); 14 | 15 | #[derive(Debug)] 16 | pub struct Template { 17 | pub cargo: Vec, 18 | pub readme: Vec, 19 | pub lib: Vec, 20 | } 21 | 22 | impl Template { 23 | pub fn new>(template_dir: P) -> Self { 24 | // Creates a `Template` from the given `template_dir`. 25 | // If a file is found in the template dir, it will override the default version. 26 | let template_dir = template_dir.as_ref(); 27 | let mut template = Template::default(); 28 | 29 | // If the theme directory doesn't exist there's no point continuing... 30 | if !template_dir.exists() || !template_dir.is_dir() { 31 | return template; 32 | } 33 | 34 | // Check for individual files, if they exist copy them across 35 | { 36 | let files = vec![ 37 | (template_dir.join("Cargo.tmol"), &mut template.cargo), 38 | (template_dir.join("README.md"), &mut template.readme), 39 | (template_dir.join("src/lib.rs"), &mut template.lib), 40 | ]; 41 | 42 | let load_with_warn = |filename: &Path, dest| { 43 | if !filename.exists() { 44 | // Don't warn if the file doesn't exist. 45 | return false; 46 | } 47 | if let Err(e) = load_file_contents(filename, dest) { 48 | println!("Couldn't load custom file, {}: {}", filename.display(), e); 49 | false 50 | } else { 51 | true 52 | } 53 | }; 54 | 55 | for (filename, dest) in files { 56 | load_with_warn(&filename, dest); 57 | } 58 | } 59 | 60 | template 61 | } 62 | } 63 | 64 | impl Default for Template { 65 | fn default() -> Template { 66 | Template { 67 | cargo: CARGO_TOML.to_owned(), 68 | readme: README.to_owned(), 69 | lib: LIB_RS.to_owned(), 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/core/link.rs: -------------------------------------------------------------------------------- 1 | //! rsw link 2 | 3 | use std::path::PathBuf; 4 | 5 | use crate::core::RswInfo; 6 | use crate::utils::{get_root, os_cli, print}; 7 | 8 | pub struct Link { 9 | cli: String, 10 | name: String, 11 | cwd: PathBuf, 12 | } 13 | 14 | impl Link { 15 | pub fn new(cli: String, cwd: PathBuf, name: String) -> Link { 16 | Link { cli, cwd, name } 17 | } 18 | pub fn init(self) { 19 | if self.cli == "yarn" { 20 | self.yarn_link(); 21 | } 22 | if self.cli == "pnpm" { 23 | self.pnpm_link(); 24 | } 25 | } 26 | pub fn npm_link(cli: String, crates: Vec) { 27 | os_cli(cli, [&["link".into()], &crates[..]].concat(), get_root()); 28 | print(RswInfo::CrateLink("npm link".into(), crates.join(" "))); 29 | } 30 | 31 | pub fn yarn_link(&self) { 32 | // register package 33 | // 1. cd / 34 | // 2. yarn link 35 | os_cli(self.cli.clone(), ["link".into()].to_vec(), &self.cwd); 36 | 37 | // yarn link 38 | os_cli( 39 | self.cli.clone(), 40 | ["link".into(), self.name.clone()].to_vec(), 41 | get_root(), 42 | ); 43 | 44 | print(RswInfo::CrateLink( 45 | "yarn link".into(), 46 | self.name.to_string(), 47 | )); 48 | } 49 | 50 | pub fn pnpm_link(&self) { 51 | // pnpm link --dir 52 | let dir = get_root().to_string_lossy().to_string(); 53 | os_cli( 54 | self.cli.clone(), 55 | ["link".into(), "--dir".into(), dir].to_vec(), 56 | &self.cwd, 57 | ); 58 | 59 | print(RswInfo::CrateLink( 60 | "pnpm link".into(), 61 | self.name.to_string(), 62 | )); 63 | } 64 | 65 | pub fn unlink(cli: &String, crates: Vec) { 66 | let root = get_root(); 67 | 68 | // unlink foo bar 69 | os_cli( 70 | cli.clone(), 71 | [&["unlink".into()], &crates[..]].concat(), 72 | &root, 73 | ); 74 | 75 | if cli == "npm" { 76 | // npm unlink -g foo bar 77 | os_cli( 78 | cli.clone(), 79 | [&["unlink".into(), "-g".into()], &crates[..]].concat(), 80 | root, 81 | ); 82 | } 83 | 84 | print(RswInfo::Clean(format!("{} unlink", cli), crates.join(" "))); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/template/rsw.toml: -------------------------------------------------------------------------------- 1 | name = "rsw" 2 | version = "0.1.0" 3 | 4 | #! time interval for file changes to trigger wasm-pack build, default `50` milliseconds 5 | interval = 50 6 | 7 | #! link 8 | #! npm link @see https://docs.npmjs.com/cli/v8/commands/npm-link 9 | #! yarn link @see https://classic.yarnpkg.com/en/docs/cli/link 10 | #! pnpm link @see https://pnpm.io/cli/link 11 | #! The link command will only be executed if `[[crates]] link = true` 12 | #! cli: `npm` | `yarn` | `pnpm`, default is `npm` 13 | cli = "npm" 14 | 15 | #! --------------------------- 16 | 17 | #! rsw new 18 | [new] 19 | #! @see https://rustwasm.github.io/docs/wasm-pack/commands/new.html 20 | #! using: `wasm-pack` | `rsw` | `user`, default is `wasm-pack` 21 | #! 1. wasm-pack: `rsw new --template