mirror of
https://github.com/denoland/deno.git
synced 2024-10-31 09:14:20 -04:00
0ceb554343
* Native ES modules This is a major refactor of internal compiler. Before: JS and TS both were sent through the typescript compiler where their imports were parsed and handled. Both compiled to AMD JS and finally sent to V8 Now: JS is sent directly into V8. TS is sent through the typescript compiler, but tsc generates ES modules now instead of AMD. This generated JS is then dumped into V8. This should much faster for pure JS code. It may improve TS compilation speed. In the future this allows us to separate TS out of the runtime heap and into its own dedicated snapshot. This will result in a smaller runtime heap, and thus should be faster. Some tests were unfortunately disabled to ease landing this patch: 1. compiler_tests.ts which I intend to bring back in later commits. 2. Some text_encoding_test.ts tests which made the file invalid utf8. See PR for a discussion. Also worth noting that this is necessary to support WASM
156 lines
4.3 KiB
Rust
156 lines
4.3 KiB
Rust
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
|
use isolate::Buf;
|
|
use isolate::IsolateState;
|
|
use msg;
|
|
use resources;
|
|
use resources::Resource;
|
|
use resources::ResourceId;
|
|
use workers;
|
|
|
|
use futures::Future;
|
|
use serde_json;
|
|
use std::sync::Arc;
|
|
use std::sync::Mutex;
|
|
|
|
lazy_static! {
|
|
static ref c_rid: Mutex<Option<ResourceId>> = Mutex::new(None);
|
|
}
|
|
|
|
// This corresponds to JS ModuleMetaData.
|
|
// TODO Rename one or the other so they correspond.
|
|
#[derive(Debug)]
|
|
pub struct CodeFetchOutput {
|
|
pub module_name: String,
|
|
pub filename: String,
|
|
pub media_type: msg::MediaType,
|
|
pub source_code: String,
|
|
pub maybe_output_code: Option<String>,
|
|
pub maybe_source_map: Option<String>,
|
|
}
|
|
|
|
impl CodeFetchOutput {
|
|
pub fn js_source<'a>(&'a self) -> String {
|
|
if self.media_type == msg::MediaType::Json {
|
|
return String::from(format!("export default {};", self.source_code));
|
|
}
|
|
match self.maybe_output_code {
|
|
None => self.source_code.clone(),
|
|
Some(ref output_code) => output_code.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CodeFetchOutput {
|
|
// TODO Use serde_derive? Use flatbuffers?
|
|
fn from_json(json_str: &str) -> Option<Self> {
|
|
match serde_json::from_str::<serde_json::Value>(json_str) {
|
|
Ok(serde_json::Value::Object(map)) => {
|
|
let module_name = match map["moduleId"].as_str() {
|
|
None => return None,
|
|
Some(s) => s.to_string(),
|
|
};
|
|
|
|
let filename = match map["fileName"].as_str() {
|
|
None => return None,
|
|
Some(s) => s.to_string(),
|
|
};
|
|
|
|
let source_code = match map["sourceCode"].as_str() {
|
|
None => return None,
|
|
Some(s) => s.to_string(),
|
|
};
|
|
|
|
let maybe_output_code =
|
|
map["outputCode"].as_str().map(|s| s.to_string());
|
|
|
|
let maybe_source_map = map["sourceMap"].as_str().map(|s| s.to_string());
|
|
|
|
Some(CodeFetchOutput {
|
|
module_name,
|
|
filename,
|
|
media_type: msg::MediaType::JavaScript, // TODO
|
|
source_code,
|
|
maybe_output_code,
|
|
maybe_source_map,
|
|
})
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource {
|
|
let mut cell = c_rid.lock().unwrap();
|
|
let rid = cell.get_or_insert_with(|| {
|
|
let resource =
|
|
workers::spawn(parent_state.clone(), "compilerMain()".to_string());
|
|
resource.rid
|
|
});
|
|
Resource { rid: *rid }
|
|
}
|
|
|
|
fn req(specifier: &str, referrer: &str) -> Buf {
|
|
json!({
|
|
"specifier": specifier,
|
|
"referrer": referrer,
|
|
}).to_string()
|
|
.into_boxed_str()
|
|
.into_boxed_bytes()
|
|
}
|
|
|
|
pub fn compile_sync(
|
|
parent_state: &Arc<IsolateState>,
|
|
specifier: &str,
|
|
referrer: &str,
|
|
) -> Option<CodeFetchOutput> {
|
|
let req_msg = req(specifier, referrer);
|
|
|
|
let compiler = lazy_start(parent_state);
|
|
|
|
let send_future = resources::worker_post_message(compiler.rid, req_msg);
|
|
send_future.wait().unwrap();
|
|
|
|
let recv_future = resources::worker_recv_message(compiler.rid);
|
|
let res_msg = recv_future.wait().unwrap().unwrap();
|
|
|
|
let res_json = std::str::from_utf8(&res_msg).unwrap();
|
|
CodeFetchOutput::from_json(res_json)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_compile_sync() {
|
|
let cwd = std::env::current_dir().unwrap();
|
|
let cwd_string = cwd.to_str().unwrap().to_owned();
|
|
|
|
let specifier = "./tests/002_hello.ts";
|
|
let referrer = cwd_string + "/";
|
|
|
|
let cfo =
|
|
compile_sync(&IsolateState::mock(), specifier, &referrer).unwrap();
|
|
let output_code = cfo.maybe_output_code.unwrap();
|
|
assert!(output_code.starts_with("console.log(\"Hello World\");"));
|
|
}
|
|
|
|
#[test]
|
|
fn code_fetch_output_from_json() {
|
|
let json = r#"{
|
|
"moduleId":"/Users/rld/src/deno/tests/002_hello.ts",
|
|
"fileName":"/Users/rld/src/deno/tests/002_hello.ts",
|
|
"mediaType":1,
|
|
"sourceCode":"console.log(\"Hello World\");\n",
|
|
"outputCode":"yyy",
|
|
"sourceMap":"xxx",
|
|
"scriptVersion":"1"
|
|
}"#;
|
|
let actual = CodeFetchOutput::from_json(json).unwrap();
|
|
assert_eq!(actual.filename, "/Users/rld/src/deno/tests/002_hello.ts");
|
|
assert_eq!(actual.module_name, "/Users/rld/src/deno/tests/002_hello.ts");
|
|
assert_eq!(actual.source_code, "console.log(\"Hello World\");\n");
|
|
assert_eq!(actual.maybe_output_code, Some("yyy".to_string()));
|
|
assert_eq!(actual.maybe_source_map, Some("xxx".to_string()));
|
|
}
|
|
}
|