Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Xortive malonso/hotreload + windows ampersand escape fix #451

Merged
merged 67 commits into from
Aug 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
5532253
hotreload demo
xortive Jul 31, 2019
24104df
changed to use old script id instead of sessions
xortive Jun 14, 2019
008d578
added watch option to wranglerjs
xortive Jun 21, 2019
85f9f5d
add support for running wranglerjs in watch mode, utilizing webpack's
xortive Jul 31, 2019
2b630e3
remove watch module + refs
xortive Jul 31, 2019
c4af49b
check for debug flag to use localhost for preview server
xortive Jul 2, 2019
3115f98
added deps
xortive Jul 31, 2019
b73f85c
add build_and_watch
xortive Jul 31, 2019
994a177
please the borrow checker
xortive Jul 3, 2019
cd9129d
cleanup
xortive Jul 3, 2019
eb6fed6
fix temp file
xortive Jul 3, 2019
5777d1a
webpack watching works -- code is littered with debug statements and …
xortive Jul 31, 2019
d57ca17
update querystring params, use sessions instead of old_id/new_id
xortive Jul 8, 2019
8a1e9db
remove wranglerjs console logs
xortive Jul 8, 2019
6b96e9d
finalize communication with the fiddle, add port + session support
xortive Jul 8, 2019
d3707ab
move watcher inside thread closure to have the correct lifetime
xortive Jul 9, 2019
61d6b76
s/build_and_watch/watch_and_build, put watch_and_build inside its own…
xortive Jul 9, 2019
b89cc31
add guardedcommand for running wranglerjs in --watch while having it …
xortive Jul 31, 2019
f11a038
add cooldown period for fs events
xortive Jul 9, 2019
25107cf
don't swallow tx errors from watch_and_build
xortive Jul 10, 2019
074a2a7
fix wrangler build --watch
xortive Jul 15, 2019
59055ab
made messaging use message crate, removed some println!
xortive Jul 15, 2019
bc972d2
cargo fmt
xortive Jul 15, 2019
4d2d444
Add message when ignoring stale first change
xortive Jul 15, 2019
a0922a9
Check origin header and close if invalid
xortive Jul 15, 2019
88c42e2
separate out fiddle message server into its own module
xortive Jul 16, 2019
fed1314
fixed debug save_origins, cargo_fmt, added safe_origins log message
xortive Jul 22, 2019
41fdab0
updated preview url
xortive Jul 22, 2019
ed5a683
fix origins
xortive Jul 23, 2019
5cbbfb9
don't use hotreload host for normal open command
xortive Jul 23, 2019
6af51b4
remove allowing connections from msg is is confusing
xortive Jul 23, 2019
a63715f
cargo fmt
xortive Jul 29, 2019
8e6ebff
fix origin check and add localhost check
xortive Jul 29, 2019
359f16b
better errors
xortive Jul 29, 2019
f86c5a6
cargo fmt
xortive Jul 31, 2019
77d3064
DRY open browser function
xortive Jul 31, 2019
5979c5d
please clippy
xortive Jul 31, 2019
410de96
namespace query params
xortive Jul 31, 2019
7781e48
cargo fmt
xortive Jul 31, 2019
d67675b
Merge branch 'master' into malonso/hotreload
xortive Aug 12, 2019
13895c5
use info@ for fiddle messenger logs
xortive Aug 12, 2019
04a4f98
better log messages for wranglerjs + use info@ for watching temp file…
xortive Aug 12, 2019
0e84b59
fix double build bug
xortive Aug 12, 2019
ced45c1
cleanup fiddle messenger: use ws::Result instead of alias
xortive Aug 14, 2019
a145ce5
Keep trying port+1 so you can have multiple previews open
xortive Aug 14, 2019
bbdce84
Merge remote-tracking branch 'origin/master' into malonso/hotreload
xortive Aug 14, 2019
f0a126f
also watch entry point for rust
xortive Aug 14, 2019
3db1912
better update message
xortive Aug 14, 2019
cb60448
update preview service url
xortive Aug 15, 2019
20cbfe9
Merge remote-tracking branch 'origin/master' into malonso/hotreload
xortive Aug 15, 2019
694d078
Merge branch 'master' into malonso/hotreload
EverlastingBugstopper Aug 16, 2019
930f920
Use strict equality check in wranglerjs/index.js
xortive Aug 16, 2019
73933fb
Hide editor on wrangler preview without watch
EverlastingBugstopper Aug 16, 2019
ae50e37
Better messaging for preview update message
xortive Aug 16, 2019
2f9d2dc
use NonRecursive watcher for watch paths that always point to files
xortive Aug 16, 2019
ecb1ba9
bind to port 0 to allow the OS to assign us a port, instead of using our
xortive Aug 16, 2019
61ed11e
cargo fmt
xortive Aug 16, 2019
6e19a8e
Make open_browser more robust
xortive Aug 16, 2019
fa4c023
cargo fmt
xortive Aug 16, 2019
23f1d99
disable wrangler build --watch for now
xortive Aug 16, 2019
22c04df
PR feedback: namespacing, command matching, remove unnecessary unwraps
xortive Aug 16, 2019
462decb
fix(preview): escape & in windows URL
ashleygwilliams Aug 16, 2019
d1ab8b3
fix(style): appease cargo fmt
ashleygwilliams Aug 16, 2019
226b212
fix(clippy): unecessary if let to is_some
ashleygwilliams Aug 16, 2019
543d412
fix(watch): recurisve plz k thx
ashleygwilliams Aug 16, 2019
ada6ae2
fix(depr): ... -> ..=
ashleygwilliams Aug 16, 2019
52415ae
fix(preview): one last recursive
ashleygwilliams Aug 16, 2019
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
232 changes: 225 additions & 7 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ base64 = "0.10.1"
lazy_static = "1.3.0"
text_io = "0.1.7"
exitfailure = "0.5.1"
notify = "4.0.12"
ws = "0.9.0"

[dev-dependencies]
assert_cmd = "0.11.1"
Expand Down
11 changes: 7 additions & 4 deletions src/commands/build/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
pub mod wranglerjs;

mod watch;
pub use watch::watch_and_build;

use crate::settings::project::{Project, ProjectType};
use crate::terminal::message;
use crate::{commands, install};

use std::path::PathBuf;
use std::process::Command;

use crate::terminal::message;

pub fn build(project: &Project) -> Result<(), failure::Error> {
let project_type = &project.project_type;
match project_type {
Expand All @@ -18,7 +21,7 @@ pub fn build(project: &Project) -> Result<(), failure::Error> {
let binary_path = install::install(tool_name, "rustwasm")?.binary(tool_name)?;
let args = ["build", "--target", "no-modules"];

let command = command(&args, binary_path);
let command = command(&args, &binary_path);
let command_name = format!("{:?}", command);

commands::run(command, &command_name)?;
Expand All @@ -31,7 +34,7 @@ pub fn build(project: &Project) -> Result<(), failure::Error> {
Ok(())
}

fn command(args: &[&str], binary_path: PathBuf) -> Command {
pub fn command(args: &[&str], binary_path: &PathBuf) -> Command {
message::working("Compiling your project to WebAssembly...");

let mut c = if cfg!(target_os = "windows") {
Expand Down
89 changes: 89 additions & 0 deletions src/commands/build/watch/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
mod watcher;
pub use watcher::wait_for_changes;

use crate::commands::build::{command, wranglerjs};
use crate::commands::publish::Package;
use crate::settings::project::{Project, ProjectType};
use crate::terminal::message;
use crate::{commands, install};

use notify::{self, RecursiveMode, Watcher};
use std::env;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

pub const COOLDOWN_PERIOD: Duration = Duration::from_millis(2000);

/// watch a project for changes and re-build it when necessary,
/// outputting a build event to tx.
pub fn watch_and_build(
project: &Project,
tx: Option<mpsc::Sender<()>>,
) -> Result<(), failure::Error> {
let project_type = &project.project_type;
match project_type {
ProjectType::JavaScript => {
let package = Package::new("./")?;
let entry = package.main()?;
thread::spawn(move || {
let (watcher_tx, watcher_rx) = mpsc::channel();
let mut watcher = notify::watcher(watcher_tx, Duration::from_secs(1)).unwrap();

watcher.watch(&entry, RecursiveMode::Recursive).unwrap();
message::info(&format!("watching {:?}", &entry));

loop {
match wait_for_changes(&watcher_rx, COOLDOWN_PERIOD) {
Ok(_path) => {
if let Some(tx) = tx.clone() {
tx.send(()).expect("--watch change message failed to send");
}
}
Err(_) => message::user_error("Something went wrong while watching."),
}
}
});
}
ProjectType::Rust => {
let tool_name = "wasm-pack";
let binary_path = install::install(tool_name, "rustwasm")?.binary(tool_name)?;
let args = ["build", "--target", "no-modules"];

let package = Package::new("./")?;
let entry = package.main()?;

thread::spawn(move || {
let (watcher_tx, watcher_rx) = mpsc::channel();
let mut watcher = notify::watcher(watcher_tx, Duration::from_secs(1)).unwrap();

let mut path = env::current_dir().expect("current dir");
path.push("src");

watcher.watch(&path, RecursiveMode::Recursive).unwrap();
watcher.watch(&entry, RecursiveMode::Recursive).unwrap();
message::info(&format!("watching {:?} and {:?}", &path, &entry));

loop {
match wait_for_changes(&watcher_rx, COOLDOWN_PERIOD) {
Ok(_path) => {
let command = command(&args, &binary_path);
let command_name = format!("{:?}", command);
if commands::run(command, &command_name).is_ok() {
if let Some(tx) = tx.clone() {
tx.send(()).expect("--watch change message failed to send");
}
}
}
Err(_) => message::user_error("Something went wrong while watching."),
}
}
});
}
ProjectType::Webpack => {
wranglerjs::run_build_and_watch(project, tx)?;
}
}

Ok(())
}
50 changes: 50 additions & 0 deletions src/commands/build/watch/watcher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use notify::DebouncedEvent;
use std::path::PathBuf;
use std::sync::mpsc::Receiver;
use std::time::Duration;

use failure::{format_err, Error};

use crate::terminal::message;
use log::info;

///Add cooldown for all types of events to watching logic
pub fn wait_for_changes(
rx: &Receiver<DebouncedEvent>,
cooldown: Duration,
) -> Result<PathBuf, Error> {
loop {
let event = rx.recv()?;
match get_changed_path_from_event(event) {
Ok(Some(path)) => {
message::working("Detected changes...");
//wait for cooldown
while let Ok(_) = rx.recv_timeout(cooldown) {
message::working("Detected change during cooldown...");
}
message::working("Cooldown over, propogating changes...");
return Ok(path);
}
Ok(None) => {
continue; //was an event type we don't care about, continue
}
Err(error) => {
message::user_error(&format!("WatchError {:?}", error));
continue;
}
};
}
}

fn get_changed_path_from_event(event: DebouncedEvent) -> Result<Option<PathBuf>, Error> {
info!("Detected Event {:?}", event);
match event {
DebouncedEvent::Error(error, _) => Err(format_err!("{:?}", error)),
DebouncedEvent::NoticeWrite(path) => Ok(Some(path)),
DebouncedEvent::Write(path) => Ok(Some(path)),
DebouncedEvent::NoticeRemove(path) => Ok(Some(path)),
DebouncedEvent::Remove(path) => Ok(Some(path)),
DebouncedEvent::Create(path) => Ok(Some(path)),
_ => Ok(None),
}
}
97 changes: 80 additions & 17 deletions src/commands/build/wranglerjs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
mod bundle;
pub mod output;

use crate::commands::build::watch::wait_for_changes;
use crate::commands::build::watch::COOLDOWN_PERIOD;

use crate::commands::publish::package::Package;
use crate::install;
use crate::util;
pub use bundle::Bundle;
use fs2::FileExt;
use log::info;
Expand All @@ -17,9 +21,13 @@ use std::path::{Path, PathBuf};
use std::process::Command;

use crate::settings::project::Project;

use crate::terminal::message;

use notify::{self, RecursiveMode, Watcher};
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

// Run the underlying {wranglerjs} executable.
//
// In Rust we create a virtual file, pass the pass to {wranglerjs}, run the
Expand All @@ -39,26 +47,81 @@ pub fn run_build(project: &Project) -> Result<(), failure::Error> {
let wranglerjs_output: WranglerjsOutput =
serde_json::from_str(&output).expect("could not parse wranglerjs output");

if wranglerjs_output.has_errors() {
message::user_error(wranglerjs_output.get_errors().as_str());
failure::bail!("Webpack returned an error");
}
write_wranglerjs_output(&bundle, &wranglerjs_output)
} else {
failure::bail!("failed to execute `{:?}`: exited with {}", command, status)
}
}

bundle
.write(&wranglerjs_output)
.expect("could not write bundle to disk");
pub fn run_build_and_watch(
project: &Project,
tx: Option<Sender<()>>,
) -> Result<(), failure::Error> {
let (mut command, temp_file, bundle) = setup_build(project)?;
command.arg("--watch=1");

info!("Running {:?} in watch mode", command);

//Turbofish the result of the closure so we can use ?
thread::spawn::<_, Result<(), failure::Error>>(move || {
let _command_guard = util::GuardedCommand::spawn(command);

let (watcher_tx, watcher_rx) = channel();
let mut watcher = notify::watcher(watcher_tx, Duration::from_secs(1))?;

watcher.watch(&temp_file, RecursiveMode::Recursive)?;

info!("watching temp file {:?}", &temp_file);

let mut is_first = true;

loop {
match wait_for_changes(&watcher_rx, COOLDOWN_PERIOD) {
Ok(_) => {
if is_first {
is_first = false;
message::info("Ignoring stale first change");
//skip the first change event
//so we don't do a refresh immediately
continue;
}

let output = fs::read_to_string(&temp_file).expect("could not retrieve ouput");
let wranglerjs_output: WranglerjsOutput =
serde_json::from_str(&output).expect("could not parse wranglerjs output");

if write_wranglerjs_output(&bundle, &wranglerjs_output).is_ok() {
if let Some(tx) = tx.clone() {
tx.send(()).expect("--watch change message failed to send");
}
}
}
Err(_) => message::user_error("Something went wrong while watching."),
}
}
});

let msg = format!(
"Built successfully, built project size is {}",
wranglerjs_output.project_size()
);
Ok(())
}

fs::remove_file(temp_file)?;
message::success(&msg);
Ok(())
} else {
failure::bail!("failed to execute `{:?}`: exited with {}", command, status)
fn write_wranglerjs_output(
bundle: &Bundle,
output: &WranglerjsOutput,
) -> Result<(), failure::Error> {
if output.has_errors() {
message::user_error(output.get_errors().as_str());
failure::bail!("Webpack returned an error");
}

bundle.write(output)?;

let msg = format!(
"Built successfully, built project size is {}",
output.project_size()
);

message::success(&msg);
Ok(())
}

//setup a build to run wranglerjs, return the command, the ipc temp file, and the bundle
Expand Down
4 changes: 2 additions & 2 deletions src/commands/build/wranglerjs/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ impl WranglerjsOutput {
};

match compressed_size {
WARN_THRESHOLD...MAX_PROJECT_SIZE => format!("{}. {2} Your built project is {} away from reaching the 1MiB size limit. {2}", human_size, human_leftover.expect("failed to get leftover bytes"), emoji::WARN),
0...MAX_BEFORE_WARN => format!("{}.", human_size),
WARN_THRESHOLD..=MAX_PROJECT_SIZE => format!("{}. {2} Your built project is {} away from reaching the 1MiB size limit. {2}", human_size, human_leftover.expect("failed to get leftover bytes"), emoji::WARN),
0..=MAX_BEFORE_WARN => format!("{}.", human_size),
_ => format!("{}. {1} Your built project has grown past the 1MiB size limit and may fail to deploy. {1}", human_size, emoji::WARN)
}
}
Expand Down
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod whoami;

pub use self::config::global_config;
pub use build::build;
pub use build::watch_and_build;
pub use generate::generate;
pub use init::init;
pub use publish::preview::preview;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/publish/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod preview;
mod route;
mod upload_form;

use package::Package;
pub use package::Package;
use route::Route;
use upload_form::build_script_upload_form;

Expand Down
Loading