Skip to content

Commit

Permalink
feat(cli): Deno.emit supports bundling as IIFE (denoland#9291)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk committed Feb 16, 2021
1 parent a6beab8 commit 7e9028b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 12 deletions.
6 changes: 4 additions & 2 deletions cli/dts/lib.deno.unstable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,10 @@ declare namespace Deno {

interface EmitOptions {
/** Indicate that the source code should be emitted to a single file
* JavaScript bundle that is an ES module (`"esm"`). */
bundle?: "esm";
* JavaScript bundle that is a single ES module (`"esm"`) or a single file
* self contained script we executes in an immediately invoked function
* when loaded (`"iife"`). */
bundle?: "esm" | "iife";
/** If `true` then the sources will be typed checked, returning any
* diagnostic errors in the result. If `false` type checking will be
* skipped. Defaults to `true`.
Expand Down
38 changes: 29 additions & 9 deletions cli/module_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,10 @@ pub enum BundleType {
/// Return the emitted contents of the program as a single "flattened" ES
/// module.
Esm,
// TODO(@kitsonk) once available in swc
// Iife,
/// Return the emitted contents of the program as a single script that
/// executes the program using an immediately invoked function execution
/// (IIFE).
Iife,
/// Do not bundle the emit, instead returning each of the modules that are
/// part of the program as individual files.
None,
Expand Down Expand Up @@ -780,7 +782,8 @@ impl Graph {
let maybe_ignored_options =
ts_config.merge_tsconfig(options.maybe_config_path)?;

let s = self.emit_bundle(&root_specifier, &ts_config.into())?;
let s =
self.emit_bundle(&root_specifier, &ts_config.into(), &BundleType::Esm)?;
let stats = Stats(vec![
("Files".to_string(), self.modules.len() as u32),
("Total time".to_string(), start.elapsed().as_millis() as u32),
Expand Down Expand Up @@ -951,7 +954,7 @@ impl Graph {
"target": "esnext",
}));
let opts = match options.bundle_type {
BundleType::Esm => json!({
BundleType::Esm | BundleType::Iife => json!({
"noEmit": true,
}),
BundleType::None => json!({
Expand Down Expand Up @@ -992,7 +995,7 @@ impl Graph {

let graph = graph.lock().unwrap();
match options.bundle_type {
BundleType::Esm => {
BundleType::Esm | BundleType::Iife => {
assert!(
response.emitted_files.is_empty(),
"No files should have been emitted from tsc."
Expand All @@ -1003,7 +1006,11 @@ impl Graph {
"Only a single root module supported."
);
let specifier = &graph.roots[0];
let s = graph.emit_bundle(specifier, &config.into())?;
let s = graph.emit_bundle(
specifier,
&config.into(),
&options.bundle_type,
)?;
emitted_files.insert("deno:https:///bundle.js".to_string(), s);
}
BundleType::None => {
Expand Down Expand Up @@ -1044,14 +1051,18 @@ impl Graph {
let start = Instant::now();
let mut emit_count = 0_u32;
match options.bundle_type {
BundleType::Esm => {
BundleType::Esm | BundleType::Iife => {
assert_eq!(
self.roots.len(),
1,
"Only a single root module supported."
);
let specifier = &self.roots[0];
let s = self.emit_bundle(specifier, &config.into())?;
let s = self.emit_bundle(
specifier,
&config.into(),
&options.bundle_type,
)?;
emit_count += 1;
emitted_files.insert("deno:https:///bundle.js".to_string(), s);
}
Expand Down Expand Up @@ -1104,19 +1115,28 @@ impl Graph {
&self,
specifier: &ModuleSpecifier,
emit_options: &ast::EmitOptions,
bundle_type: &BundleType,
) -> Result<String, AnyError> {
let cm = Rc::new(swc_common::SourceMap::new(
swc_common::FilePathMapping::empty(),
));
let globals = swc_common::Globals::new();
let loader = BundleLoader::new(self, emit_options, &globals, cm.clone());
let hook = Box::new(BundleHook);
let module = match bundle_type {
BundleType::Esm => swc_bundler::ModuleType::Es,
BundleType::Iife => swc_bundler::ModuleType::Iife,
_ => unreachable!("invalid bundle type"),
};
let bundler = swc_bundler::Bundler::new(
&globals,
cm.clone(),
loader,
self,
swc_bundler::Config::default(),
swc_bundler::Config {
module,
..Default::default()
},
hook,
);
let mut entries = HashMap::new();
Expand Down
5 changes: 4 additions & 1 deletion cli/ops/runtime_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub fn init(rt: &mut deno_core::JsRuntime) {
enum RuntimeBundleType {
#[serde(rename = "esm")]
Esm,
#[serde(rename = "iife")]
Iife,
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -106,7 +108,8 @@ async fn op_emit(
})?;
let bundle_type = match args.bundle {
Some(RuntimeBundleType::Esm) => BundleType::Esm,
_ => BundleType::None,
Some(RuntimeBundleType::Iife) => BundleType::Iife,
None => BundleType::None,
};
let graph = builder.get_graph();
let debug = program_state.flags.log_level == Some(log::Level::Debug);
Expand Down
19 changes: 19 additions & 0 deletions cli/tests/compiler_api_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,22 @@ Deno.test({
assert(typeof files[`${specifier}.js.map`] === "string");
},
});

Deno.test({
name: `Deno.emit() - bundle supports iife`,
async fn() {
const { diagnostics, files } = await Deno.emit("/a.ts", {
bundle: "iife",
sources: {
"/a.ts": `import { b } from "./b.ts";
console.log(b);`,
"/b.ts": `export const b = "b";`,
},
});
assert(diagnostics);
assertEquals(diagnostics.length, 0);
assertEquals(Object.keys(files).length, 1);
assert(files["deno:https:///bundle.js"].startsWith("(function() {\n"));
assert(files["deno:https:///bundle.js"].endsWith("})();\n"));
},
});

0 comments on commit 7e9028b

Please sign in to comment.