mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
parent
87d3b9b5cc
commit
0ed3046a9a
6 changed files with 314 additions and 0 deletions
16
bundle/README.md
Normal file
16
bundle/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# bundle
|
||||
|
||||
These are modules that help support bundling with Deno.
|
||||
|
||||
## Usage
|
||||
|
||||
The main usage is to load and run bundles. For example, to run a bundle named
|
||||
`bundle.js` in your current working directory:
|
||||
|
||||
```sh
|
||||
deno run https://deno.land/std/bundle/run.ts bundle.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
11
bundle/run.ts
Normal file
11
bundle/run.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { evaluate, instantiate, load } from "./utils.ts";
|
||||
|
||||
async function main(args: string[]): Promise<void> {
|
||||
const text = await load(args);
|
||||
const result = evaluate(text);
|
||||
instantiate(...result);
|
||||
}
|
||||
|
||||
main(Deno.args);
|
111
bundle/test.ts
Normal file
111
bundle/test.ts
Normal file
|
@ -0,0 +1,111 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { test } from "../testing/mod.ts";
|
||||
import {
|
||||
assert,
|
||||
AssertionError,
|
||||
assertStrictEq,
|
||||
assertThrowsAsync
|
||||
} from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../testing/pretty.ts";
|
||||
import { evaluate, instantiate, load, ModuleMetaData } from "./utils.ts";
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
declare global {
|
||||
namespace globalThis {
|
||||
var __results: [string, string] | undefined;
|
||||
}
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-namespace */
|
||||
|
||||
const fixture = `
|
||||
define("data", [], { "baz": "qat" });
|
||||
define("modB", ["require", "exports", "data"], function(require, exports, data) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.foo = "bar";
|
||||
exports.baz = data.baz;
|
||||
});
|
||||
define("modA", ["require", "exports", "modB"], function(require, exports, modB) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
globalThis.__results = [modB.foo, modB.baz];
|
||||
});
|
||||
`;
|
||||
|
||||
const fixtureQueue = ["data", "modB", "modA"];
|
||||
const fixtureModules = new Map<string, ModuleMetaData>();
|
||||
fixtureModules.set("data", {
|
||||
dependencies: [],
|
||||
factory: {
|
||||
baz: "qat"
|
||||
},
|
||||
exports: {}
|
||||
});
|
||||
fixtureModules.set("modB", {
|
||||
dependencies: ["require", "exports", "data"],
|
||||
factory(_require, exports, data): void {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.foo = "bar";
|
||||
exports.baz = data.baz;
|
||||
},
|
||||
exports: {}
|
||||
});
|
||||
fixtureModules.set("modA", {
|
||||
dependencies: ["require", "exports", "modB"],
|
||||
factory(_require, exports, modB): void {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
globalThis.__results = [modB.foo, modB.baz];
|
||||
},
|
||||
exports: {}
|
||||
});
|
||||
|
||||
test(async function loadBundle(): Promise<void> {
|
||||
const result = await load(["", "./bundle/testdata/bundle.js"]);
|
||||
assert(result != null);
|
||||
assert(
|
||||
result.includes(
|
||||
`define("subdir/print_hello", ["require", "exports"], function(`
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test(async function loadBadArgs(): Promise<void> {
|
||||
await assertThrowsAsync(
|
||||
async (): Promise<void> => {
|
||||
await load(["bundle/test.ts"]);
|
||||
},
|
||||
AssertionError,
|
||||
"Expected exactly two arguments."
|
||||
);
|
||||
});
|
||||
|
||||
test(async function loadMissingBundle(): Promise<void> {
|
||||
await assertThrowsAsync(
|
||||
async (): Promise<void> => {
|
||||
await load([".", "bad_bundle.js"]);
|
||||
},
|
||||
AssertionError,
|
||||
`Expected "bad_bundle.js" to exist.`
|
||||
);
|
||||
});
|
||||
|
||||
test(async function evaluateBundle(): Promise<void> {
|
||||
assert(globalThis.define == null, "Expected 'define' to be undefined");
|
||||
const [queue, modules] = evaluate(fixture);
|
||||
assert(globalThis.define == null, "Expected 'define' to be undefined");
|
||||
assertEquals(queue, ["data", "modB", "modA"]);
|
||||
assert(modules.has("modA"));
|
||||
assert(modules.has("modB"));
|
||||
assert(modules.has("data"));
|
||||
assertStrictEq(modules.size, 3);
|
||||
});
|
||||
|
||||
test(async function instantiateBundle(): Promise<void> {
|
||||
assert(globalThis.__results == null);
|
||||
instantiate(fixtureQueue, fixtureModules);
|
||||
assertEquals(globalThis.__results, ["bar", "qat"]);
|
||||
delete globalThis.__results;
|
||||
});
|
67
bundle/testdata/bundle.js
vendored
Normal file
67
bundle/testdata/bundle.js
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
define("subdir/print_hello", ["require", "exports"], function(
|
||||
require,
|
||||
exports
|
||||
) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
function printHello() {
|
||||
console.log("Hello");
|
||||
}
|
||||
exports.printHello = printHello;
|
||||
});
|
||||
define("subdir/subdir2/mod2", [
|
||||
"require",
|
||||
"exports",
|
||||
"subdir/print_hello"
|
||||
], function(require, exports, print_hello_ts_1) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
function returnsFoo() {
|
||||
return "Foo";
|
||||
}
|
||||
exports.returnsFoo = returnsFoo;
|
||||
function printHello2() {
|
||||
print_hello_ts_1.printHello();
|
||||
}
|
||||
exports.printHello2 = printHello2;
|
||||
});
|
||||
define("subdir/mod1", ["require", "exports", "subdir/subdir2/mod2"], function(
|
||||
require,
|
||||
exports,
|
||||
mod2_ts_1
|
||||
) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
function returnsHi() {
|
||||
return "Hi";
|
||||
}
|
||||
exports.returnsHi = returnsHi;
|
||||
function returnsFoo2() {
|
||||
return mod2_ts_1.returnsFoo();
|
||||
}
|
||||
exports.returnsFoo2 = returnsFoo2;
|
||||
function printHello3() {
|
||||
mod2_ts_1.printHello2();
|
||||
}
|
||||
exports.printHello3 = printHello3;
|
||||
function throwsError() {
|
||||
throw Error("exception from mod1");
|
||||
}
|
||||
exports.throwsError = throwsError;
|
||||
});
|
||||
define("005_more_imports", ["require", "exports", "subdir/mod1"], function(
|
||||
require,
|
||||
exports,
|
||||
mod1_ts_1
|
||||
) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
mod1_ts_1.printHello3();
|
||||
if (mod1_ts_1.returnsHi() !== "Hi") {
|
||||
throw Error("Unexpected");
|
||||
}
|
||||
if (mod1_ts_1.returnsFoo2() !== "Foo") {
|
||||
throw Error("Unexpected");
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZmlsZTovLy9Vc2Vycy9ra2VsbHkvZ2l0aHViL2Rlbm8vdGVzdHMvc3ViZGlyL3ByaW50X2hlbGxvLnRzIiwiZmlsZTovLy9Vc2Vycy9ra2VsbHkvZ2l0aHViL2Rlbm8vdGVzdHMvc3ViZGlyL3N1YmRpcjIvbW9kMi50cyIsImZpbGU6Ly8vVXNlcnMva2tlbGx5L2dpdGh1Yi9kZW5vL3Rlc3RzL3N1YmRpci9tb2QxLnRzIiwiZmlsZTovLy9Vc2Vycy9ra2VsbHkvZ2l0aHViL2Rlbm8vdGVzdHMvMDA1X21vcmVfaW1wb3J0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7SUFBQSxTQUFnQixVQUFVO1FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdkIsQ0FBQztJQUZELGdDQUVDOzs7OztJQ0FELFNBQWdCLFVBQVU7UUFDeEIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRkQsZ0NBRUM7SUFFRCxTQUFnQixXQUFXO1FBQ3pCLDJCQUFVLEVBQUUsQ0FBQztJQUNmLENBQUM7SUFGRCxrQ0FFQzs7Ozs7SUNORCxTQUFnQixTQUFTO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUZELDhCQUVDO0lBRUQsU0FBZ0IsV0FBVztRQUN6QixPQUFPLG9CQUFVLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRkQsa0NBRUM7SUFFRCxTQUFnQixXQUFXO1FBQ3pCLHFCQUFXLEVBQUUsQ0FBQztJQUNoQixDQUFDO0lBRkQsa0NBRUM7SUFFRCxTQUFnQixXQUFXO1FBQ3pCLE1BQU0sS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7SUFDckMsQ0FBQztJQUZELGtDQUVDOzs7OztJQ2RELHFCQUFXLEVBQUUsQ0FBQztJQUVkLElBQUksbUJBQVMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN4QixNQUFNLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztLQUMzQjtJQUVELElBQUkscUJBQVcsRUFBRSxLQUFLLEtBQUssRUFBRTtRQUMzQixNQUFNLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztLQUMzQiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBwcmludEhlbGxvKCk6IHZvaWQge1xuICBjb25zb2xlLmxvZyhcIkhlbGxvXCIpO1xufVxuIiwiaW1wb3J0IHsgcHJpbnRIZWxsbyB9IGZyb20gXCIuLi9wcmludF9oZWxsby50c1wiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmV0dXJuc0ZvbygpOiBzdHJpbmcge1xuICByZXR1cm4gXCJGb29cIjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByaW50SGVsbG8yKCk6IHZvaWQge1xuICBwcmludEhlbGxvKCk7XG59XG4iLCJpbXBvcnQgeyByZXR1cm5zRm9vLCBwcmludEhlbGxvMiB9IGZyb20gXCIuL3N1YmRpcjIvbW9kMi50c1wiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmV0dXJuc0hpKCk6IHN0cmluZyB7XG4gIHJldHVybiBcIkhpXCI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXR1cm5zRm9vMigpOiBzdHJpbmcge1xuICByZXR1cm4gcmV0dXJuc0ZvbygpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRIZWxsbzMoKTogdm9pZCB7XG4gIHByaW50SGVsbG8yKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0aHJvd3NFcnJvcigpOiB2b2lkIHtcbiAgdGhyb3cgRXJyb3IoXCJleGNlcHRpb24gZnJvbSBtb2QxXCIpO1xufVxuIiwiaW1wb3J0IHsgcmV0dXJuc0hpLCByZXR1cm5zRm9vMiwgcHJpbnRIZWxsbzMgfSBmcm9tIFwiLi9zdWJkaXIvbW9kMS50c1wiO1xuXG5wcmludEhlbGxvMygpO1xuXG5pZiAocmV0dXJuc0hpKCkgIT09IFwiSGlcIikge1xuICB0aHJvdyBFcnJvcihcIlVuZXhwZWN0ZWRcIik7XG59XG5cbmlmIChyZXR1cm5zRm9vMigpICE9PSBcIkZvb1wiKSB7XG4gIHRocm93IEVycm9yKFwiVW5leHBlY3RlZFwiKTtcbn1cbiJdfQ==
|
108
bundle/utils.ts
Normal file
108
bundle/utils.ts
Normal file
|
@ -0,0 +1,108 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertStrictEq, assert } from "../testing/asserts.ts";
|
||||
import { exists } from "../fs/exists.ts";
|
||||
|
||||
export interface DefineFactory {
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
(...args: any): object | void;
|
||||
}
|
||||
|
||||
export interface ModuleMetaData {
|
||||
dependencies: string[];
|
||||
factory?: DefineFactory | object;
|
||||
exports: object;
|
||||
}
|
||||
|
||||
type Define = (
|
||||
id: string,
|
||||
dependencies: string[],
|
||||
factory: DefineFactory
|
||||
) => void;
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
declare global {
|
||||
namespace globalThis {
|
||||
var define: Define | undefined;
|
||||
}
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-namespace */
|
||||
|
||||
/** Evaluate the bundle, returning a queue of module IDs and their data to
|
||||
* instantiate.
|
||||
*/
|
||||
export function evaluate(
|
||||
text: string
|
||||
): [string[], Map<string, ModuleMetaData>] {
|
||||
const queue: string[] = [];
|
||||
const modules = new Map<string, ModuleMetaData>();
|
||||
|
||||
globalThis.define = function define(
|
||||
id: string,
|
||||
dependencies: string[],
|
||||
factory: DefineFactory
|
||||
): void {
|
||||
modules.set(id, {
|
||||
dependencies,
|
||||
factory,
|
||||
exports: {}
|
||||
});
|
||||
queue.push(id);
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Deno as any).core.evalContext(text);
|
||||
// Deleting `define()` so it isn't accidentally there when the modules
|
||||
// instantiate.
|
||||
delete globalThis.define;
|
||||
|
||||
return [queue, modules];
|
||||
}
|
||||
|
||||
/** Drain the queue of module IDs while instantiating the modules. */
|
||||
export function instantiate(
|
||||
queue: string[],
|
||||
modules: Map<string, ModuleMetaData>
|
||||
): void {
|
||||
let id: string | undefined;
|
||||
while ((id = queue.shift())) {
|
||||
const module = modules.get(id)!;
|
||||
assert(module != null);
|
||||
assert(module.factory != null);
|
||||
|
||||
const dependencies = module.dependencies.map(
|
||||
(id): object => {
|
||||
if (id === "require") {
|
||||
// TODO(kitsonk) support dynamic import by passing a `require()` that
|
||||
// can return a local module or dynamically import one.
|
||||
return (): void => {};
|
||||
} else if (id === "exports") {
|
||||
return module.exports;
|
||||
}
|
||||
const dep = modules.get(id)!;
|
||||
assert(dep != null);
|
||||
return dep.exports;
|
||||
}
|
||||
);
|
||||
|
||||
if (typeof module.factory === "function") {
|
||||
module.factory!(...dependencies);
|
||||
} else if (module.factory) {
|
||||
// when bundling JSON, TypeScript just emits it as an object/array as the
|
||||
// third argument of the `define()`.
|
||||
module.exports = module.factory;
|
||||
}
|
||||
delete module.factory;
|
||||
}
|
||||
}
|
||||
|
||||
/** Load the bundle and return the contents asynchronously. */
|
||||
export async function load(args: string[]): Promise<string> {
|
||||
// TODO(kitsonk) allow loading of remote bundles via fetch.
|
||||
assertStrictEq(args.length, 2, "Expected exactly two arguments.");
|
||||
const [, bundleFileName] = args;
|
||||
assert(
|
||||
await exists(bundleFileName),
|
||||
`Expected "${bundleFileName}" to exist.`
|
||||
);
|
||||
return new TextDecoder().decode(await Deno.readFile(bundleFileName));
|
||||
}
|
1
test.ts
1
test.ts
|
@ -2,6 +2,7 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
import "./archive/tar_test.ts";
|
||||
import "./bytes/test.ts";
|
||||
import "./bundle/test.ts";
|
||||
import "./colors/test.ts";
|
||||
import "./datetime/test.ts";
|
||||
import "./encoding/test.ts";
|
||||
|
|
Loading…
Reference in a new issue