feat(debug): Inline dbg-swc (#4651)

This commit is contained in:
Donny/강동윤 2022-05-13 15:05:21 +09:00 committed by GitHub
parent f0639c9de4
commit b393773373
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 372 additions and 12 deletions

39
Cargo.lock generated
View File

@ -784,6 +784,28 @@ dependencies = [
"parking_lot",
]
[[package]]
name = "dbg-swc"
version = "0.12.0"
dependencies = [
"anyhow",
"clap 3.1.0",
"rayon",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_codegen",
"swc_ecma_minifier",
"swc_ecma_parser",
"swc_ecma_transforms_base",
"swc_ecma_visit",
"swc_error_reporters",
"swc_timer",
"tracing",
"tracing-subscriber",
"url",
]
[[package]]
name = "debug_unreachable"
version = "0.1.1"
@ -2260,9 +2282,9 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.5.1"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221"
dependencies = [
"autocfg",
"crossbeam-deque",
@ -2272,14 +2294,13 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.9.1"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
@ -4379,9 +4400,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
version = "0.1.32"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
dependencies = [
"cfg-if 1.0.0",
"log",
@ -4445,9 +4466,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.9"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce"
checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596"
dependencies = [
"ansi_term",
"lazy_static",

View File

@ -1,5 +1,6 @@
[workspace]
members = [
"crates/dbg-swc",
"crates/jsdoc",
"crates/binding_core_node",
"crates/binding_core_wasm",
@ -44,5 +45,5 @@ opt-level = 3
opt-level = 3
[patch.crates-io]
cranelift-codegen = { git = "https://github.com/kdy1/wasmtime", branch = "tls" }
cranelift-entity = { git = "https://github.com/kdy1/wasmtime", branch = "tls" }
cranelift-codegen = {git = "https://github.com/kdy1/wasmtime", branch = "tls"}
cranelift-entity = {git = "https://github.com/kdy1/wasmtime", branch = "tls"}

26
crates/dbg-swc/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
description = "Debug utilities"
edition = "2021"
license = "Apache-2.0"
name = "dbg-swc"
repository = "https://github.com/kdy1/dbg-swc.git"
version = "0.12.0"
[dependencies]
anyhow = "1.0.57"
clap = {version = "3", features = ["derive"]}
rayon = "1.5.2"
swc_atoms = { version = "0.2.11", path = "../swc_atoms" }
swc_common = { version = "0.18.0", features = ["concurrent"], path = "../swc_common" }
swc_ecma_ast = { version = "0.78.0", path = "../swc_ecma_ast" }
swc_ecma_codegen = { version = "0.107.0", path = "../swc_ecma_codegen" }
swc_ecma_minifier = { version = "0.113.1", path = "../swc_ecma_minifier" }
swc_ecma_parser = { version = "0.104.0", path = "../swc_ecma_parser" }
swc_ecma_transforms_base = { version = "0.84.0", path = "../swc_ecma_transforms_base" }
swc_ecma_visit = { version = "0.64.0", path = "../swc_ecma_visit" }
swc_error_reporters = { version = "0.2.0", path = "../swc_error_reporters" }
swc_timer = { version = "0.6.0", path = "../swc_timer" }
tracing = "0.1.34"
tracing-subscriber = {version = "0.3.11", features = ["fmt"]}
url = "2"

View File

@ -0,0 +1,39 @@
use std::{
process::{Command, Stdio},
sync::Arc,
};
use anyhow::{bail, Context, Result};
use clap::Subcommand;
use swc_common::{FileName, SourceMap};
use swc_timer::timer;
use crate::util::{parse_js, wrap_task, ModuleRecord};
#[derive(Debug, Subcommand)]
pub enum BundleCommand {}
pub fn bundle(cm: Arc<SourceMap>, entry_url: &str) -> Result<ModuleRecord> {
wrap_task(|| {
let _timer = timer!("bundle");
let mut cmd = Command::new("deno");
cmd.arg("bundle");
cmd.arg(entry_url);
cmd.stderr(Stdio::inherit());
let output = cmd.output().context("failed to invoke `deno bundle`")?;
if !output.status.success() {
bail!("`deno bundle` failed with status code {}", output.status);
}
let code =
String::from_utf8(output.stdout).context("deno bundle emitted non-utf8 output")?;
let fm = cm.new_source_file(FileName::Anon, code);
parse_js(fm).context("failed to parse js filed emitted by `deno bundle`")
})
.with_context(|| format!("failed to bundle `{}`", entry_url))
}

View File

@ -0,0 +1,57 @@
#![feature(box_syntax)]
use std::sync::Arc;
use anyhow::Result;
use clap::{StructOpt, Subcommand};
use swc_common::{
errors::{ColorConfig, HANDLER},
Globals, SourceMap, GLOBALS,
};
use swc_error_reporters::handler::{try_with_handler, HandlerOpts};
use self::{bundle::BundleCommand, minify::MinifyCommand, test::TestCommand};
mod bundle;
mod minify;
mod test;
mod util;
#[derive(Debug, clap::Parser)]
struct AppArgs {
#[clap(subcommand)]
cmd: Cmd,
}
#[derive(Debug, Subcommand)]
enum Cmd {
#[clap(subcommand)]
Bundle(BundleCommand),
#[clap(subcommand)]
Minify(MinifyCommand),
#[clap(subcommand)]
Test(TestCommand),
}
fn main() -> Result<()> {
let args = AppArgs::parse();
let cm = Arc::new(SourceMap::default());
try_with_handler(
cm.clone(),
HandlerOpts {
color: ColorConfig::Always,
skip_filename: false,
},
|handler| {
GLOBALS.set(&Globals::default(), || {
HANDLER.set(handler, || match args.cmd {
Cmd::Bundle(_) => todo!(),
Cmd::Minify(_) => todo!(),
Cmd::Test(cmd) => cmd.run(cm),
})
})
},
)
}

View File

@ -0,0 +1,5 @@
use clap::Subcommand;
/// Minify a javascript file.
#[derive(Debug, Subcommand)]
pub enum MinifyCommand {}

129
crates/dbg-swc/src/test.rs Normal file
View File

@ -0,0 +1,129 @@
use std::{
fs,
path::{Path, PathBuf},
process::{Command, Stdio},
sync::Arc,
};
use anyhow::{bail, Context, Result};
use clap::{Args, Subcommand};
use swc_common::SourceMap;
use swc_ecma_minifier::option::MinifyOptions;
use swc_ecma_transforms_base::fixer::fixer;
use swc_ecma_visit::VisitMutWith;
use swc_timer::timer;
use tracing::info;
use crate::{bundle::bundle, util::print_js};
/// Execute a javascript file after performing some preprocessing.
#[derive(Debug, Subcommand)]
pub enum TestCommand {
MinifiedBundle(TestMinifiedBundleCommand),
}
impl TestCommand {
pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {
let _timer = timer!("test");
let output = {
let _timer = timer!("process");
match self {
TestCommand::MinifiedBundle(cmd) => cmd.run(cm),
}?
};
{
let _timer = timer!("run");
let stdout = output
.runtime
.execute(&output.path)
.context("failed to execute generated code")?;
info!("----- Stdout -----\n{}", stdout);
}
Ok(())
}
}
#[derive(Debug, Args)]
pub struct TestMinifiedBundleCommand {
entry: String,
}
impl TestMinifiedBundleCommand {
fn run(self, cm: Arc<SourceMap>) -> Result<Output> {
let bundle = bundle(cm.clone(), &self.entry)?;
let mut minified = {
let _timer = timer!("minify");
swc_ecma_minifier::optimize(
bundle.module,
cm.clone(),
None,
None,
&MinifyOptions {
compress: Some(Default::default()),
mangle: Some(Default::default()),
..Default::default()
},
&swc_ecma_minifier::option::ExtraOptions {
unresolved_mark: bundle.unresolved_mark,
top_level_mark: bundle.top_level_mark,
},
)
};
minified.visit_mut_with(&mut fixer(None));
let code = print_js(cm, &minified, true).context("failed to convert ast to code")?;
let path = Path::new("output.js").to_path_buf();
fs::write(&path, code.as_bytes()).context("failed to write code as file")?;
Ok(Output {
path,
runtime: JsRuntime::Deno,
})
}
}
pub struct Output {
pub path: PathBuf,
pub runtime: JsRuntime,
}
pub enum JsRuntime {
// Node,
Deno,
}
impl JsRuntime {
pub fn execute(&self, path: &Path) -> Result<String> {
match self {
// JsRuntime::Node => todo!("node.execute"),
JsRuntime::Deno => {
let mut cmd = Command::new("deno");
cmd.arg("run").arg("--no-check");
cmd.arg(path);
cmd.stderr(Stdio::inherit());
let output = cmd.output().context("failed to get output from deno")?;
if !output.status.success() {
bail!("deno exited with status {}", output.status);
}
Ok(
(String::from_utf8(output.stdout).context("deno emitted non-utf8 string")?)
.trim()
.to_string(),
)
}
}
}
}

View File

@ -0,0 +1,78 @@
use std::sync::Arc;
use anyhow::{bail, Context, Result};
use swc_common::{errors::HANDLER, Mark, SourceFile, SourceMap};
use swc_ecma_ast::{EsVersion, Module};
use swc_ecma_codegen::text_writer::{omit_trailing_semi, JsWriter, WriteJs};
use swc_ecma_parser::{parse_file_as_module, Syntax};
use swc_ecma_transforms_base::resolver;
use swc_ecma_visit::VisitMutWith;
/// Type annotation
pub fn wrap_task<T, F>(op: F) -> Result<T>
where
F: FnOnce() -> Result<T>,
{
op()
}
pub fn parse_js(fm: Arc<SourceFile>) -> Result<ModuleRecord> {
let unresolved_mark = Mark::new();
let top_level_mark = Mark::new();
let mut errors = vec![];
let res = parse_file_as_module(
&fm,
Syntax::Es(Default::default()),
EsVersion::latest(),
None,
&mut errors,
)
.map_err(|err| HANDLER.with(|handler| err.into_diagnostic(handler).emit()));
for err in errors {
HANDLER.with(|handler| err.into_diagnostic(handler).emit());
}
let mut m = match res {
Ok(v) => v,
Err(()) => bail!("failed to parse a js file as a module"),
};
m.visit_mut_with(&mut resolver(unresolved_mark, top_level_mark, false));
Ok(ModuleRecord {
module: m,
top_level_mark,
unresolved_mark,
})
}
pub fn print_js(cm: Arc<SourceMap>, m: &Module, minify: bool) -> Result<String> {
let mut buf = vec![];
{
let mut wr = box JsWriter::new(cm.clone(), "\n", &mut buf, None) as Box<dyn WriteJs>;
if minify {
wr = box omit_trailing_semi(wr);
}
let mut e = swc_ecma_codegen::Emitter {
cfg: swc_ecma_codegen::Config { minify },
cm,
comments: None,
wr,
};
e.emit_module(m).unwrap();
}
String::from_utf8(buf).context("swc emitted non-utf8 output")
}
#[derive(Debug)]
pub struct ModuleRecord {
pub module: Module,
pub top_level_mark: Mark,
pub unresolved_mark: Mark,
}

View File

@ -2,7 +2,7 @@
extern crate swc_node_base;
use std::{env, fs, path::PathBuf};
use std::{env, fs, path::PathBuf, time::Instant};
use anyhow::Result;
use rayon::prelude::*;
@ -20,7 +20,9 @@ use walkdir::WalkDir;
fn main() {
let dirs = env::args().skip(1).collect::<Vec<_>>();
let files = expand_dirs(dirs);
eprintln!("Using {} files", files.len());
let start = Instant::now();
testing::run_test2(false, |cm, handler| {
GLOBALS.with(|globals| {
let _ = files
@ -81,6 +83,8 @@ fn main() {
})
})
.unwrap();
eprintln!("Took {:?}", start.elapsed());
}
/// Return the whole input files as abolute path.