Skip to content

Commit 11926e6

Browse files
committed
Add 'bundle' subcommand.
1 parent 4ea2df6 commit 11926e6

File tree

5 files changed

+259
-76
lines changed

5 files changed

+259
-76
lines changed

cli/compiler.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,22 @@ impl ModuleMetaData {
5050
type CompilerConfig = Option<(String, Vec<u8>)>;
5151

5252
/// Creates the JSON message send to compiler.ts's onmessage.
53-
fn req(root_names: Vec<String>, compiler_config: CompilerConfig) -> Buf {
53+
fn req(
54+
root_names: Vec<String>,
55+
compiler_config: CompilerConfig,
56+
bundle: Option<String>,
57+
) -> Buf {
5458
let j = if let Some((config_path, config_data)) = compiler_config {
5559
json!({
5660
"rootNames": root_names,
61+
"bundle": bundle,
5762
"configPath": config_path,
5863
"config": str::from_utf8(&config_data).unwrap(),
5964
})
6065
} else {
6166
json!({
6267
"rootNames": root_names,
68+
"bundle": bundle,
6369
})
6470
};
6571
j.to_string().into_boxed_str().into_boxed_bytes()
@@ -82,6 +88,67 @@ pub fn get_compiler_config(
8288
}
8389
}
8490

91+
pub fn bundle_async(
92+
state: ThreadSafeState,
93+
module_name: String,
94+
out_file: String,
95+
) -> impl Future<Item = (), Error = Diagnostic> {
96+
debug!(
97+
"Invoking the compiler to bundle. module_name: {}",
98+
module_name
99+
);
100+
101+
let root_names = vec![module_name.clone()];
102+
let compiler_config = get_compiler_config(&state, "typescript");
103+
let req_msg = req(root_names, compiler_config, Some(out_file));
104+
105+
// Count how many times we start the compiler worker.
106+
state.metrics.compiler_starts.fetch_add(1, Ordering::SeqCst);
107+
108+
let mut worker = Worker::new(
109+
"TS".to_string(),
110+
startup_data::compiler_isolate_init(),
111+
// TODO(ry) Maybe we should use a separate state for the compiler.
112+
// as was done previously.
113+
state.clone(),
114+
);
115+
js_check(worker.execute("denoMain()"));
116+
js_check(worker.execute("workerMain()"));
117+
js_check(worker.execute("compilerMain()"));
118+
119+
let resource = worker.state.resource.clone();
120+
let compiler_rid = resource.rid;
121+
let first_msg_fut = resources::post_message_to_worker(compiler_rid, req_msg)
122+
.then(move |_| worker)
123+
.then(move |result| {
124+
if let Err(err) = result {
125+
// TODO(ry) Need to forward the error instead of exiting.
126+
eprintln!("{}", err.to_string());
127+
std::process::exit(1);
128+
}
129+
debug!("Sent message to worker");
130+
let stream_future =
131+
resources::get_message_stream_from_worker(compiler_rid).into_future();
132+
stream_future.map(|(f, _rest)| f).map_err(|(f, _rest)| f)
133+
});
134+
135+
first_msg_fut.map_err(|_| panic!("not handled")).and_then(
136+
move |maybe_msg: Option<Buf>| {
137+
debug!("Received message from worker");
138+
139+
if let Some(msg) = maybe_msg {
140+
let json_str = std::str::from_utf8(&msg).unwrap();
141+
debug!("Message: {}", json_str);
142+
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
143+
return Err(diagnostics);
144+
}
145+
}
146+
147+
Ok(())
148+
},
149+
)
150+
}
151+
85152
pub fn compile_async(
86153
state: ThreadSafeState,
87154
module_meta_data: &ModuleMetaData,
@@ -95,7 +162,7 @@ pub fn compile_async(
95162

96163
let root_names = vec![module_name.clone()];
97164
let compiler_config = get_compiler_config(&state, "typescript");
98-
let req_msg = req(root_names, compiler_config);
165+
let req_msg = req(root_names, compiler_config, None);
99166

100167
// Count how many times we start the compiler worker.
101168
state.metrics.compiler_starts.fetch_add(1, Ordering::SeqCst);

cli/flags.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ To get help on the another subcommands (run in this case):
154154
Includes versions of Deno, V8 JavaScript Engine, and the TypeScript
155155
compiler.",
156156
),
157+
).subcommand(
158+
SubCommand::with_name("bundle")
159+
.setting(AppSettings::DisableVersion)
160+
.about("Bundle module and dependnecies into single file")
161+
.long_about(
162+
"Fetch, compile, and output to a single file a module and its dependencies.
163+
"
164+
)
165+
.arg(Arg::with_name("source_file").takes_value(true).required(true))
166+
.arg(Arg::with_name("out_file").takes_value(true).required(true)),
157167
).subcommand(
158168
SubCommand::with_name("fetch")
159169
.setting(AppSettings::DisableVersion)
@@ -436,6 +446,7 @@ const PRETTIER_URL: &str = "https://deno.land/[email protected]/prettier/main.ts";
436446
/// There is no "Help" subcommand because it's handled by `clap::App` itself.
437447
#[derive(Debug, PartialEq)]
438448
pub enum DenoSubcommand {
449+
Bundle,
439450
Eval,
440451
Fetch,
441452
Info,
@@ -455,6 +466,13 @@ pub fn flags_from_vec(
455466
let mut flags = parse_flags(&matches.clone());
456467

457468
let subcommand = match matches.subcommand() {
469+
("bundle", Some(bundle_match)) => {
470+
flags.allow_write = true;
471+
let source_file: &str = bundle_match.value_of("source_file").unwrap();
472+
let out_file: &str = bundle_match.value_of("out_file").unwrap();
473+
argv.extend(vec![source_file.to_string(), out_file.to_string()]);
474+
DenoSubcommand::Bundle
475+
}
458476
("eval", Some(eval_match)) => {
459477
flags.allow_net = true;
460478
flags.allow_env = true;

cli/main.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ mod tokio_write;
4141
pub mod version;
4242
pub mod worker;
4343

44+
use crate::compiler::bundle_async;
4445
use crate::errors::RustOrJsError;
4546
use crate::progress::Progress;
4647
use crate::state::ThreadSafeState;
@@ -257,6 +258,25 @@ fn xeval_command(flags: DenoFlags, argv: Vec<String>) {
257258
tokio_util::run(main_future);
258259
}
259260

261+
fn bundle_command(flags: DenoFlags, argv: Vec<String>) {
262+
let (mut _worker, state) = create_worker_and_state(flags, argv);
263+
264+
let main_module = state.main_module().unwrap();
265+
let main_url = root_specifier_to_url(&main_module).unwrap();
266+
let out_file = state.out_file().unwrap();
267+
debug!(">>>>> bundle_async START");
268+
let bundle_future = bundle_async(state, main_url.to_string(), out_file)
269+
.map_err(|e| {
270+
debug!("diagnostics returned, exiting!");
271+
eprintln!("\n{}", e.to_string());
272+
std::process::exit(1);
273+
}).and_then(move |out| {
274+
debug!(">>>>> bundle_async END");
275+
Ok(out)
276+
});
277+
tokio_util::run(bundle_future);
278+
}
279+
260280
fn run_repl(flags: DenoFlags, argv: Vec<String>) {
261281
let (mut worker, _state) = create_worker_and_state(flags, argv);
262282

@@ -318,6 +338,7 @@ fn main() {
318338
});
319339

320340
match subcommand {
341+
DenoSubcommand::Bundle => bundle_command(flags, argv),
321342
DenoSubcommand::Eval => eval_command(flags, argv),
322343
DenoSubcommand::Fetch => fetch_or_info_command(flags, argv, false),
323344
DenoSubcommand::Info => fetch_or_info_command(flags, argv, true),

cli/state.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ impl ThreadSafeState {
270270
}
271271
}
272272

273+
/// Read the out file from argv
274+
pub fn out_file(&self) -> Option<String> {
275+
if self.argv.len() <= 2 {
276+
None
277+
} else {
278+
Some(self.argv[2].clone())
279+
}
280+
}
281+
273282
pub fn mark_compiled(&self, module_id: &str) {
274283
let mut c = self.compiled.lock().unwrap();
275284
c.insert(module_id.to_string());

0 commit comments

Comments
 (0)