summaryrefslogtreecommitdiff
path: root/deno_typescript/bundle_loader.js
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/bundle_loader.js
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/bundle_loader.js')
-rw-r--r--deno_typescript/bundle_loader.js124
1 files changed, 124 insertions, 0 deletions
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;
+ };
+})();