summaryrefslogtreecommitdiff
path: root/deno_typescript
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2019-11-14 02:35:56 +1100
committerRy Dahl <ry@tinyclouds.org>2019-11-13 10:35:56 -0500
commit8d03397293b388317299dfb0648b541a7005807d (patch)
tree38aeb4deb371e81f47b6750110d96de46b9f5b05 /deno_typescript
parentee1b8dc883db1531d913f7b10a8d1160f3209d93 (diff)
Make bundles fully standalone (#3325)
- Bundles are fully standalone. They now include the shared loader with `deno_typescript`. - Refactor of the loader in `deno_typescript` to perform module instantiation in a more - Change of behaviour when an output file is not specified on the CLI. Previously a default name was determined and the bundle written to that file, now the bundle will be sent to `stdout`. - Refactors in the TypeScript compiler to be able to support the concept of a request type. This provides a cleaner abstraction and makes it easier to support things like single module transpiles to the userland. - Remove a "dangerous" circular dependency between `os.ts` and `deno.ts`, and define `pid` and `noColor` in a better way. - Don't bind early to `console` in `repl.ts`. - Add an integration test for generating a bundle.
Diffstat (limited to 'deno_typescript')
-rw-r--r--deno_typescript/amd_runtime.js54
-rw-r--r--deno_typescript/bundle_loader.js124
-rw-r--r--deno_typescript/lib.rs15
3 files changed, 134 insertions, 59 deletions
diff --git a/deno_typescript/amd_runtime.js b/deno_typescript/amd_runtime.js
deleted file mode 100644
index 1c4f0007a..000000000
--- a/deno_typescript/amd_runtime.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-
-// A very very basic AMD preamble to support the output of TypeScript outFile
-// bundles.
-
-/**
- * @type {(name: string) => any}
- */
-let require;
-
-/**
- * @type {(name: string, deps: ReadonlyArray<string>, factory: (...deps: any[]) => void) => void}
- */
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-let define;
-
-(function() {
- /**
- * @type {Map<string, { name: string, exports: any }>}
- */
- const modules = new Map();
-
- /**
- * @param {string} name
- */
- function createOrLoadModule(name) {
- let m = modules.get(name);
- if (!m) {
- m = { name, exports: {} };
- modules.set(name, m);
- }
- return m;
- }
-
- require = name => {
- return createOrLoadModule(name).exports;
- };
-
- define = (name, deps, factory) => {
- const currentModule = createOrLoadModule(name);
- const localExports = currentModule.exports;
- const args = deps.map(dep => {
- if (dep === "require") {
- return require;
- } else if (dep === "exports") {
- return localExports;
- } else {
- const depModule = createOrLoadModule(dep);
- return depModule.exports;
- }
- });
- factory(...args);
- };
-})();
diff --git a/deno_typescript/bundle_loader.js b/deno_typescript/bundle_loader.js
new file mode 100644
index 000000000..682754628
--- /dev/null
+++ b/deno_typescript/bundle_loader.js
@@ -0,0 +1,124 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+
+// A script preamble that provides the ability to load a single outfile
+// TypeScript "bundle" where a main module is loaded which recursively
+// instantiates all the other modules in the bundle. This code is used to load
+// bundles when creating snapshots, but is also used when emitting bundles from
+// Deno cli.
+
+/**
+ * @type {(name: string, deps: ReadonlyArray<string>, factory: (...deps: any[]) => void) => void}
+ */
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+let define;
+
+/**
+ * @type {(mod: string | string[]) => void}
+ */
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+let instantiate;
+
+/**
+ * @callback Factory
+ * @argument {...any[]} args
+ * @returns {object | void}
+ */
+
+/**
+ * @typedef ModuleMetaData
+ * @property {ReadonlyArray<string>} dependencies
+ * @property {(Factory | object)=} factory
+ * @property {object} exports
+ */
+
+(function() {
+ /**
+ * @type {Map<string, ModuleMetaData>}
+ */
+ const modules = new Map();
+
+ /**
+ * Bundles in theory can support "dynamic" imports, but for internal bundles
+ * we can't go outside to fetch any modules that haven't been statically
+ * defined.
+ * @param {string[]} deps
+ * @param {(...deps: any[]) => void} resolve
+ * @param {(err: any) => void} reject
+ */
+ const require = (deps, resolve, reject) => {
+ try {
+ if (deps.length !== 1) {
+ throw new TypeError("Expected only a single module specifier.");
+ }
+ if (!modules.has(deps[0])) {
+ throw new RangeError(`Module "${deps[0]}" not defined.`);
+ }
+ resolve(getExports(deps[0]));
+ } catch (e) {
+ if (reject) {
+ reject(e);
+ } else {
+ throw e;
+ }
+ }
+ };
+
+ define = (id, dependencies, factory) => {
+ if (modules.has(id)) {
+ throw new RangeError(`Module "${id}" has already been defined.`);
+ }
+ modules.set(id, {
+ dependencies,
+ factory,
+ exports: {}
+ });
+ };
+
+ /**
+ * @param {string} id
+ * @returns {any}
+ */
+ function getExports(id) {
+ const module = modules.get(id);
+ if (!module) {
+ // because `$deno$/ts_global.d.ts` looks like a real script, it doesn't
+ // get erased from output as an import, but it doesn't get defined, so
+ // we don't have a cache for it, so because this is an internal bundle
+ // we can just safely return an empty object literal.
+ return {};
+ }
+ if (!module.factory) {
+ return module.exports;
+ } else if (module.factory) {
+ const { factory, exports } = module;
+ delete module.factory;
+ if (typeof factory === "function") {
+ const dependencies = module.dependencies.map(id => {
+ if (id === "require") {
+ return require;
+ } else if (id === "exports") {
+ return exports;
+ }
+ return getExports(id);
+ });
+ factory(...dependencies);
+ } else {
+ Object.assign(exports, factory);
+ }
+ return exports;
+ }
+ }
+
+ instantiate = dep => {
+ define = undefined;
+ if (Array.isArray(dep)) {
+ for (const d of dep) {
+ getExports(d);
+ }
+ } else {
+ getExports(dep);
+ }
+ // clean up, or otherwise these end up in the runtime environment
+ instantiate = undefined;
+ };
+})();
diff --git a/deno_typescript/lib.rs b/deno_typescript/lib.rs
index d130ee4c6..509bce56f 100644
--- a/deno_typescript/lib.rs
+++ b/deno_typescript/lib.rs
@@ -22,7 +22,7 @@ use std::sync::Mutex;
static TYPESCRIPT_CODE: &str = include_str!("typescript/lib/typescript.js");
static COMPILER_CODE: &str = include_str!("compiler_main.js");
-static AMD_RUNTIME_CODE: &str = include_str!("amd_runtime.js");
+static BUNDLE_LOADER: &str = include_str!("bundle_loader.js");
pub fn ts_version() -> String {
let data = include_str!("typescript/package.json");
@@ -181,11 +181,13 @@ pub fn mksnapshot_bundle(
let source_code_vec = std::fs::read(bundle)?;
let source_code = std::str::from_utf8(&source_code_vec)?;
- js_check(runtime_isolate.execute("amd_runtime.js", AMD_RUNTIME_CODE));
+ js_check(runtime_isolate.execute("bundle_loader.js", BUNDLE_LOADER));
js_check(runtime_isolate.execute(&bundle.to_string_lossy(), &source_code));
let main = state.lock().unwrap().main_module_name();
- js_check(runtime_isolate.execute("anon", &format!("require('{}')", main)));
+ js_check(
+ runtime_isolate.execute("anon", &format!("instantiate('{}')", main)),
+ );
write_snapshot(runtime_isolate, bundle)?;
@@ -202,12 +204,14 @@ pub fn mksnapshot_bundle_ts(
let source_code_vec = std::fs::read(bundle)?;
let source_code = std::str::from_utf8(&source_code_vec)?;
- js_check(runtime_isolate.execute("amd_runtime.js", AMD_RUNTIME_CODE));
+ js_check(runtime_isolate.execute("bundle_loader.js", BUNDLE_LOADER));
js_check(runtime_isolate.execute("typescript.js", TYPESCRIPT_CODE));
js_check(runtime_isolate.execute(&bundle.to_string_lossy(), &source_code));
let main = state.lock().unwrap().main_module_name();
- js_check(runtime_isolate.execute("anon", &format!("require('{}')", main)));
+ js_check(
+ runtime_isolate.execute("anon", &format!("instantiate('{}')", main)),
+ );
write_snapshot(runtime_isolate, bundle)?;
@@ -249,6 +253,7 @@ pub fn get_asset(name: &str) -> Option<&'static str> {
};
}
match name {
+ "bundle_loader.js" => Some(include_str!("bundle_loader.js")),
"lib.deno_core.d.ts" => Some(include_str!("lib.deno_core.d.ts")),
"typescript.d.ts" => inc!("typescript.d.ts"),
"lib.esnext.d.ts" => inc!("lib.esnext.d.ts"),