Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): Deno.emit supports bundling as IIFE #9291

Merged
merged 2 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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:///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:///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:///bundle.js"].startsWith("(function() {\n"));
assert(files["deno:///bundle.js"].endsWith("})();\n"));
},
});