@backtickjs/bundler 0.1.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -17
- package/dist/bundle/buildBundle.d.ts +3 -3
- package/dist/bundle/buildBundle.js +66 -56
- package/dist/bundle/buildBundle.js.map +1 -1
- package/dist/bundle/expandServerComponents.d.ts +1 -1
- package/dist/bundle/expandServerComponents.js +29 -27
- package/dist/bundle/expandServerComponents.js.map +1 -1
- package/dist/bundle/params.d.ts +1 -0
- package/dist/bundle/params.js +9 -0
- package/dist/bundle/params.js.map +1 -1
- package/dist/bundler.d.ts +17 -13
- package/dist/bundler.js +12 -7
- package/dist/bundler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/print/code.d.ts +2 -1
- package/dist/print/code.js +12 -5
- package/dist/print/code.js.map +1 -1
- package/dist/print/printBundle.js +17 -0
- package/dist/print/printBundle.js.map +1 -1
- package/package.json +2 -2
- package/src/bundle/buildBundle.ts +71 -69
- package/src/bundle/expandServerComponents.ts +29 -27
- package/src/bundle/params.ts +12 -0
- package/src/bundler.ts +24 -15
- package/src/index.ts +1 -1
- package/src/print/code.ts +14 -5
- package/src/print/printBundle.ts +21 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type
|
|
1
|
+
export { type Build, type BuildOptions, bundler, type OutputChunk, type OutputOptions, } from "./bundler.js";
|
|
2
2
|
export { type Modules, supports } from "./modules.js";
|
package/dist/print/code.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface Names {
|
|
|
11
11
|
local: string;
|
|
12
12
|
}>;
|
|
13
13
|
readonly modules: Modules;
|
|
14
|
+
exec: boolean;
|
|
14
15
|
}
|
|
15
16
|
export declare function createNames(modules: Modules): Names;
|
|
16
17
|
export declare function string(value: string): string;
|
|
@@ -22,6 +23,6 @@ export declare function array(elements: readonly string[]): string;
|
|
|
22
23
|
export declare function object(entries: readonly (readonly [string, string])[]): string;
|
|
23
24
|
/** An export of a module the client provides, imported by the bundle. */
|
|
24
25
|
export declare function imported(names: Names, { from, name, version }: ClientImport<unknown>): string;
|
|
25
|
-
/** An import declaration of one export
|
|
26
|
+
/** An import declaration of one export, or the namespace (`*`), by its local name. */
|
|
26
27
|
export declare function importDeclaration(from: string, name: string, local: string): string;
|
|
27
28
|
export declare function requireDeclaration(from: string, name: string, local: string): string;
|
package/dist/print/code.js
CHANGED
|
@@ -4,7 +4,7 @@ import { supports } from "../modules.js";
|
|
|
4
4
|
// for the framework's compiler. Everything is code, as a string.
|
|
5
5
|
const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
6
6
|
export function createNames(modules) {
|
|
7
|
-
return { imports: new Map(), modules };
|
|
7
|
+
return { imports: new Map(), modules, exec: false };
|
|
8
8
|
}
|
|
9
9
|
// A string, as a literal: `<` escaped, so no `</script>` or `<!--` appears
|
|
10
10
|
// when the bundle is inlined in a page, and the line and paragraph separators,
|
|
@@ -60,9 +60,10 @@ export function imported(names, { from, name, version }) {
|
|
|
60
60
|
throw new Error(`Can't import \`${name}\` from "${from}": the client provides ` +
|
|
61
61
|
`${listed.join(", ") || "no modules"}.`);
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
// Typed against one version, it works with a later one of the same major.
|
|
64
|
+
if (!supports(names.modules, from, `^${version}`)) {
|
|
65
|
+
throw new Error(`Can't import \`${name}\` from "${from}": it's typed against ` +
|
|
66
|
+
`${version}, and the client provides ${from}@${provided}.`);
|
|
66
67
|
}
|
|
67
68
|
const key = `${from}\0${name}`;
|
|
68
69
|
let entry = names.imports.get(key);
|
|
@@ -72,13 +73,19 @@ export function imported(names, { from, name, version }) {
|
|
|
72
73
|
}
|
|
73
74
|
return entry.local;
|
|
74
75
|
}
|
|
75
|
-
/** An import declaration of one export
|
|
76
|
+
/** An import declaration of one export, or the namespace (`*`), by its local name. */
|
|
76
77
|
export function importDeclaration(from, name, local) {
|
|
78
|
+
if (name === "*") {
|
|
79
|
+
return `import * as ${local} from ${string(from)};`;
|
|
80
|
+
}
|
|
77
81
|
const exported = IDENTIFIER.test(name) ? name : string(name);
|
|
78
82
|
return `import { ${exported} as ${local} } from ${string(from)};`;
|
|
79
83
|
}
|
|
80
84
|
// The same import as CommonJS writes it: `const { name: local } = require(…);`.
|
|
81
85
|
export function requireDeclaration(from, name, local) {
|
|
86
|
+
if (name === "*") {
|
|
87
|
+
return `const ${local} = require(${string(from)});`;
|
|
88
|
+
}
|
|
82
89
|
const exported = IDENTIFIER.test(name) ? name : string(name);
|
|
83
90
|
return `const { ${exported}: ${local} } = require(${string(from)});`;
|
|
84
91
|
}
|
package/dist/print/code.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/print/code.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvD,6EAA6E;AAC7E,+EAA+E;AAC/E,iEAAiE;AAEjE,MAAM,UAAU,GAAG,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/print/code.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,20 @@ const RUNTIME = `const $require = (id) => {
|
|
|
11
11
|
}
|
|
12
12
|
return $exports[id];
|
|
13
13
|
};`;
|
|
14
|
+
// Another bundle, executed as this one is, to its value. As CommonJS, handed the
|
|
15
|
+
// `require` this bundle was: inside the module table, `require` is the
|
|
16
|
+
// table's own.
|
|
17
|
+
const EXEC_CJS = `const $exec = async (bundle) => {
|
|
18
|
+
const module = { exports: {} };
|
|
19
|
+
new Function("module", "exports", "require", bundle)(module, module.exports, require);
|
|
20
|
+
return module.exports;
|
|
21
|
+
};`;
|
|
22
|
+
// As an ES module, imported whole, the page's import map answering its
|
|
23
|
+
// imports as it answers this bundle's.
|
|
24
|
+
const EXEC_ES = `const $exec = async (bundle) => {
|
|
25
|
+
const module = await import("data:text/javascript," + encodeURIComponent(bundle));
|
|
26
|
+
return module.default;
|
|
27
|
+
};`;
|
|
14
28
|
/**
|
|
15
29
|
* A bundle tree as a module whose default export is the tree's root: the value
|
|
16
30
|
* bundled, as its scripts wrote it.
|
|
@@ -36,6 +50,9 @@ export function printBundle(tree, format) {
|
|
|
36
50
|
for (const { from, name, local } of names.imports.values()) {
|
|
37
51
|
module.line(declaration(from, name, local));
|
|
38
52
|
}
|
|
53
|
+
if (names.exec) {
|
|
54
|
+
module.line(format === "es" ? EXEC_ES : EXEC_CJS);
|
|
55
|
+
}
|
|
39
56
|
// Each script a module table's entry, as webpack's and Metro's are: its body
|
|
40
57
|
// under its id, run once by `$require`. The modules they require are the
|
|
41
58
|
// client's, each imported whole, once.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printBundle.js","sourceRoot":"","sources":["../../src/print/printBundle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,SAAS,GAAG,WAAW,CAAC;AAE9B,+EAA+E;AAC/E,mBAAmB;AACnB,MAAM,OAAO,GAAG;;;;;;;;GAQb,CAAC;AAEJ;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CACzB,IAAgB,EAChB,MAAoB;IAEpB,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IACvB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,uEAAuE;QACvE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAC7E,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,6EAA6E;IAC7E,yEAAyE;IACzE,uCAAuC;IACvC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,YAAY,GAAG;QACnB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;KACzE,CAAC;IACF,YAAY,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,CACxC,MAAM,CAAC,IAAI,CACT,MAAM,KAAK,IAAI;QACb,CAAC,CAAC,sBAAsB,KAAK,SAAS,MAAM,CAAC,SAAS,CAAC,GAAG;QAC1D,CAAC,CAAC,gBAAgB,KAAK,cAAc,MAAM,CAAC,SAAS,CAAC,IAAI,CAC7D,CACF,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAClC,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAClC,YAAY,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,CACxC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,KAAK,GAAG,CAAC,CACtD,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,KAAK,eAAe,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;IACzE,CAAC;IACD,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,SAAS,KAAK,MAAM,IAAI,GAAG,CAAC,CAAC;IAC3C,CAAC;IACD,mEAAmE;IACnE,MAAM,CAAC,KAAK,CACV,MAAM,KAAK,IAAI;QACb,CAAC,CAAC,mBAAmB,IAAI,CAAC,IAAI,IAAI;QAClC,CAAC,CAAC,qBAAqB,IAAI,CAAC,IAAI,IAAI,CACvC,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC;AAClD,CAAC;AAED,sEAAsE;AACtE,MAAM,YAAY;IAChB,IAAI,GAAG,EAAE,CAAC;IACV,KAAK,GAAG,CAAC,CAAC;IACV,OAAO,GAAG,CAAC,CAAC;IACZ,SAAS,GAAgE,EAAE,CAAC;IAE5E,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,MAAM,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,IAAI,CAAC,IAAY;QACf,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,sEAAsE;IACtE,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,EAAgB;QAChC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAClB,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE;YAClD,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAW;SAC/B,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,8EAA8E;IAC9E,GAAG;QACD,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,IAAI,CAAC,SAAS;SACzB,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"printBundle.js","sourceRoot":"","sources":["../../src/print/printBundle.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtickjs/bundler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Runs Backtick server components and bundles a screen per request: one JavaScript file for the client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backtick",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@backtickjs/core": "^0.
|
|
42
|
+
"@backtickjs/core": "^0.2.0",
|
|
43
43
|
"semver": "^7.8.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type
|
|
2
|
+
type ScriptModule,
|
|
3
3
|
type ClientScript,
|
|
4
|
+
isClientExec,
|
|
4
5
|
isClientImport,
|
|
5
6
|
isClientScript,
|
|
6
7
|
isJsxElement,
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
} from "@backtickjs/core";
|
|
9
10
|
|
|
10
11
|
import { expandServerComponents } from "./expandServerComponents.js";
|
|
11
|
-
import { bindingsOf, capturesOf } from "./params.js";
|
|
12
|
+
import { bindingsOf, capturesOf, isValue } from "./params.js";
|
|
12
13
|
import { sourceName } from "./bindingKey.js";
|
|
13
14
|
import {
|
|
14
15
|
array,
|
|
@@ -28,7 +29,7 @@ import type { Modules } from "../modules.js";
|
|
|
28
29
|
* root, as code; and what they import.
|
|
29
30
|
*/
|
|
30
31
|
export interface BundleTree {
|
|
31
|
-
readonly modules: readonly (readonly [string,
|
|
32
|
+
readonly modules: readonly (readonly [string, ScriptModule])[];
|
|
32
33
|
// The functions and `once` values the bundle makes once, each under its
|
|
33
34
|
// label, in the order they're finished: after what they read.
|
|
34
35
|
readonly constants: readonly (readonly [string, string])[];
|
|
@@ -69,7 +70,7 @@ const rootScope = (): Scope => ({ bindings: new Set(), read: new Set() });
|
|
|
69
70
|
// intermediate script that binds a same-looking variable has a different
|
|
70
71
|
// unique name, so there is nothing to disambiguate and nothing to rename.
|
|
71
72
|
export async function buildBundle(
|
|
72
|
-
|
|
73
|
+
spliceable: unknown,
|
|
73
74
|
provided: Modules,
|
|
74
75
|
): Promise<BundleTree> {
|
|
75
76
|
const names = createNames(provided);
|
|
@@ -137,25 +138,22 @@ export async function buildBundle(
|
|
|
137
138
|
const labelOf = (target: ClientScript): string =>
|
|
138
139
|
`$cs${numbers.get(target)!}`;
|
|
139
140
|
|
|
140
|
-
//
|
|
141
|
-
// thunk a splice is handed over as. One whose code reads nothing of the
|
|
141
|
+
// The thunk a splice is handed over as. One whose code reads nothing of the
|
|
142
142
|
// scope it's written in, beyond its own parameters, is the same function
|
|
143
143
|
// wherever it's written, so the bundle makes it once, as a constant, and
|
|
144
|
-
// the same code anywhere else is that constant: a
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
// still rendered where it stands.
|
|
144
|
+
// the same code anywhere else is that constant: a value spliced at every
|
|
145
|
+
// level of a deep composition is written once per level, not once per path.
|
|
146
|
+
// A thunk is the bundle's own, never the script's, so sharing one isn't
|
|
147
|
+
// observable; everything is still rendered where it stands.
|
|
149
148
|
const constants: (readonly [string, string])[] = [];
|
|
150
149
|
const byCode = new Map<string, string>();
|
|
151
|
-
// `write` renders a
|
|
152
|
-
//
|
|
150
|
+
// `write` renders a thunk's code in a scope that records what it reads: a
|
|
151
|
+
// constant's label if it read nothing of `scope` beyond `own`, its
|
|
153
152
|
// parameters, or else the code, written where it's used.
|
|
154
|
-
const
|
|
153
|
+
const thunk = (
|
|
155
154
|
scope: Scope,
|
|
156
155
|
own: readonly string[],
|
|
157
156
|
write: (inner: Scope) => string,
|
|
158
|
-
name: string,
|
|
159
157
|
): string => {
|
|
160
158
|
const read = new Set<string>();
|
|
161
159
|
const code = write({
|
|
@@ -171,31 +169,40 @@ export async function buildBundle(
|
|
|
171
169
|
}
|
|
172
170
|
let label = byCode.get(code);
|
|
173
171
|
if (label === undefined) {
|
|
174
|
-
label = `$
|
|
172
|
+
label = `$thunk${constants.length}`;
|
|
175
173
|
byCode.set(code, label);
|
|
176
174
|
constants.push([label, code]);
|
|
177
175
|
}
|
|
178
176
|
return label;
|
|
179
177
|
};
|
|
180
178
|
|
|
181
|
-
// A `once` script
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
// function that each make a
|
|
185
|
-
//
|
|
186
|
-
//
|
|
179
|
+
// A function, a class and a `once` script are each one value (see
|
|
180
|
+
// `isValue`): its code run at the top of the bundle, where nothing encloses
|
|
181
|
+
// it, and every read is that constant. One per script, not per code: two
|
|
182
|
+
// runs of a host function that each make a function are two functions, and
|
|
183
|
+
// two that each make a context two contexts, as in plain TypeScript.
|
|
184
|
+
//
|
|
185
|
+
// A function or a class that reads a variable of the scope it's read in,
|
|
186
|
+
// itself or through what it's handed, is made there instead, as one
|
|
187
|
+
// declared in a function is. A `once` script that does is refused.
|
|
187
188
|
const values = new Map<ClientScript, string>();
|
|
188
|
-
const valueOf = (script: ClientScript): string => {
|
|
189
|
+
const valueOf = (script: ClientScript, scope: Scope): string => {
|
|
189
190
|
let label = values.get(script);
|
|
190
|
-
if (label
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
191
|
+
if (label !== undefined) {
|
|
192
|
+
return label;
|
|
193
|
+
}
|
|
194
|
+
const at: Scope = script.once
|
|
195
|
+
? rootScope()
|
|
196
|
+
: { bindings: scope.bindings, read: new Set() };
|
|
197
|
+
const code = call(labelOf(scriptFor(script)), exprCallArgs(script, at));
|
|
198
|
+
const outside = [...at.read].filter((key) => scope.bindings.has(key));
|
|
199
|
+
if (outside.length > 0) {
|
|
200
|
+
outside.forEach((key) => scope.read.add(key));
|
|
201
|
+
return code;
|
|
198
202
|
}
|
|
203
|
+
label = `$value${constants.length}`;
|
|
204
|
+
values.set(script, label);
|
|
205
|
+
constants.push([label, code]);
|
|
199
206
|
return label;
|
|
200
207
|
};
|
|
201
208
|
|
|
@@ -204,41 +211,39 @@ export async function buildBundle(
|
|
|
204
211
|
// what to hand it; everything else is its literal form. Rendered in order,
|
|
205
212
|
// one value after the other, so the table follows the order rendering first
|
|
206
213
|
// reached each script. Expansion has refused cycles, so it ends.
|
|
207
|
-
const render = (
|
|
208
|
-
if (isClientScript(
|
|
209
|
-
if (
|
|
210
|
-
return valueOf(
|
|
214
|
+
const render = (spliceable: unknown, scope: Scope = rootScope()): string => {
|
|
215
|
+
if (isClientScript(spliceable)) {
|
|
216
|
+
if (isValue(spliceable)) {
|
|
217
|
+
return valueOf(spliceable, scope);
|
|
211
218
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
return closure(
|
|
217
|
-
scope,
|
|
218
|
-
[],
|
|
219
|
-
(inner) => call(labelOf(target), exprCallArgs(value, inner)),
|
|
220
|
-
"$function",
|
|
219
|
+
return call(
|
|
220
|
+
labelOf(scriptFor(spliceable)),
|
|
221
|
+
exprCallArgs(spliceable, scope),
|
|
221
222
|
);
|
|
222
223
|
}
|
|
223
|
-
if (isJsxElement(
|
|
224
|
-
return renderJsx(
|
|
224
|
+
if (isJsxElement(spliceable)) {
|
|
225
|
+
return renderJsx(spliceable);
|
|
226
|
+
}
|
|
227
|
+
if (isClientImport(spliceable)) {
|
|
228
|
+
return imported(names, spliceable);
|
|
225
229
|
}
|
|
226
|
-
if (
|
|
227
|
-
|
|
230
|
+
if (isClientExec(spliceable)) {
|
|
231
|
+
names.exec = true;
|
|
232
|
+
return "$exec";
|
|
228
233
|
}
|
|
229
234
|
if (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
typeof
|
|
233
|
-
typeof
|
|
234
|
-
typeof
|
|
235
|
-
typeof
|
|
235
|
+
spliceable === null ||
|
|
236
|
+
spliceable === undefined ||
|
|
237
|
+
typeof spliceable === "number" ||
|
|
238
|
+
typeof spliceable === "bigint" ||
|
|
239
|
+
typeof spliceable === "string" ||
|
|
240
|
+
typeof spliceable === "boolean"
|
|
236
241
|
) {
|
|
237
|
-
return literal(
|
|
242
|
+
return literal(spliceable);
|
|
238
243
|
}
|
|
239
|
-
if (Array.isArray(
|
|
244
|
+
if (Array.isArray(spliceable)) {
|
|
240
245
|
const elements: string[] = [];
|
|
241
|
-
for (const element of
|
|
246
|
+
for (const element of spliceable) {
|
|
242
247
|
elements.push(render(element, scope));
|
|
243
248
|
}
|
|
244
249
|
return array(elements);
|
|
@@ -246,8 +251,8 @@ export async function buildBundle(
|
|
|
246
251
|
// A host function is host code, which never reaches the client: client
|
|
247
252
|
// code is written in a script, and reaches another as one.
|
|
248
253
|
// A server component among them, written as a tag: `<$Rule />`.
|
|
249
|
-
if (typeof
|
|
250
|
-
const { name } =
|
|
254
|
+
if (typeof spliceable === "function") {
|
|
255
|
+
const { name } = spliceable;
|
|
251
256
|
throw new Error(
|
|
252
257
|
(name === ""
|
|
253
258
|
? "Can't splice a host function"
|
|
@@ -258,7 +263,7 @@ export async function buildBundle(
|
|
|
258
263
|
`\`{\${<${/^[A-Z]/.test(name) ? name : "Name"} />}}\`.`,
|
|
259
264
|
);
|
|
260
265
|
}
|
|
261
|
-
if (typeof
|
|
266
|
+
if (typeof spliceable !== "object") {
|
|
262
267
|
throw new Error(
|
|
263
268
|
"Can't splice a symbol: a bundle can't write one that is the same " +
|
|
264
269
|
"symbol on the client. Splice a string, and make the symbol from it " +
|
|
@@ -270,16 +275,16 @@ export async function buildBundle(
|
|
|
270
275
|
// vanish — so fail loudly instead. An object with behaviour is built by a
|
|
271
276
|
// client function: `state` for what it holds, arrows for what may be done
|
|
272
277
|
// to it.
|
|
273
|
-
const prototype = Object.getPrototypeOf(
|
|
278
|
+
const prototype = Object.getPrototypeOf(spliceable);
|
|
274
279
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
275
|
-
const name =
|
|
280
|
+
const name = spliceable.constructor?.name ?? "an unknown class";
|
|
276
281
|
throw new Error(
|
|
277
282
|
`Can't splice this \`${name}\` instance: only plain objects cross into ` +
|
|
278
283
|
"a client script. Build one with a client function instead.",
|
|
279
284
|
);
|
|
280
285
|
}
|
|
281
286
|
const entries: [string, string][] = [];
|
|
282
|
-
for (const [key, entry] of Object.entries(
|
|
287
|
+
for (const [key, entry] of Object.entries(spliceable)) {
|
|
283
288
|
entries.push([key, render(entry, scope)]);
|
|
284
289
|
}
|
|
285
290
|
return object(entries);
|
|
@@ -320,11 +325,8 @@ export async function buildBundle(
|
|
|
320
325
|
const passed = [...passKeys(target, index), ...capturesOf(target)];
|
|
321
326
|
// A thunk taking them, the splice rendered inside it.
|
|
322
327
|
parts.push(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
passed,
|
|
326
|
-
(inner) => arrow(passed.map(displayName), render(arg, inner)),
|
|
327
|
-
"$thunk",
|
|
328
|
+
thunk(scope, passed, (inner) =>
|
|
329
|
+
arrow(passed.map(displayName), render(arg, inner)),
|
|
328
330
|
),
|
|
329
331
|
);
|
|
330
332
|
}
|
|
@@ -356,7 +358,7 @@ export async function buildBundle(
|
|
|
356
358
|
|
|
357
359
|
// Every server component first, so siblings run at once; then the drawing,
|
|
358
360
|
// in order. Nothing encloses the root, so nothing it holds can capture.
|
|
359
|
-
const root = render(await expandServerComponents(
|
|
361
|
+
const root = render(await expandServerComponents(spliceable));
|
|
360
362
|
// In table order, which is the order rendering first reached each script.
|
|
361
363
|
const modules = [...numbers.keys()].map(
|
|
362
364
|
(script) => [labelOf(script), script.module] as const,
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
isClientScript,
|
|
5
5
|
isJsxElement,
|
|
6
6
|
} from "@backtickjs/core";
|
|
7
|
+
import { isValue } from "./params.js";
|
|
7
8
|
|
|
8
9
|
const CYCLE_ERROR =
|
|
9
10
|
"Can't splice a value that contains itself: a bundle writes each value " +
|
|
@@ -34,70 +35,71 @@ const contains = (ancestors: Ancestors | null, value: object): boolean => {
|
|
|
34
35
|
// the client code it bottoms out in reaches the bundle. A value holding no
|
|
35
36
|
// server component comes back as the same object.
|
|
36
37
|
//
|
|
37
|
-
// A `once` script
|
|
38
|
-
// many places read it: a server
|
|
38
|
+
// A function, a class and a `once` script are each one value (see `isValue`),
|
|
39
|
+
// so what one splices is expanded once, however many places read it: a server
|
|
40
|
+
// component inside it runs once. `values` holds
|
|
39
41
|
// each one's expansion for the call.
|
|
40
42
|
export async function expandServerComponents(
|
|
41
|
-
|
|
43
|
+
spliceable: unknown,
|
|
42
44
|
ancestors: Ancestors | null = null,
|
|
43
45
|
values = new Map<ClientScript, Promise<unknown>>(),
|
|
44
46
|
): Promise<unknown> {
|
|
45
|
-
if (typeof
|
|
46
|
-
return
|
|
47
|
+
if (typeof spliceable !== "object" || spliceable === null) {
|
|
48
|
+
return spliceable;
|
|
47
49
|
}
|
|
48
|
-
if (contains(ancestors,
|
|
50
|
+
if (contains(ancestors, spliceable)) {
|
|
49
51
|
throw new Error(CYCLE_ERROR);
|
|
50
52
|
}
|
|
51
|
-
const inside: Ancestors = { value, parent: ancestors };
|
|
53
|
+
const inside: Ancestors = { value: spliceable, parent: ancestors };
|
|
52
54
|
const all = (entries: readonly unknown[]) =>
|
|
53
55
|
Promise.all(
|
|
54
56
|
entries.map((entry) => expandServerComponents(entry, inside, values)),
|
|
55
57
|
);
|
|
56
58
|
|
|
57
|
-
if (isJsxElement(
|
|
58
|
-
const { type } =
|
|
59
|
+
if (isJsxElement(spliceable)) {
|
|
60
|
+
const { type } = spliceable;
|
|
59
61
|
// A tag the client draws is left for rendering to refuse.
|
|
60
62
|
if (typeof type !== "function" || isClientImport(type)) {
|
|
61
|
-
return
|
|
63
|
+
return spliceable;
|
|
62
64
|
}
|
|
63
65
|
return expandServerComponents(
|
|
64
|
-
await type(
|
|
66
|
+
await type(spliceable.props as never),
|
|
65
67
|
inside,
|
|
66
68
|
values,
|
|
67
69
|
);
|
|
68
70
|
}
|
|
69
|
-
if (isClientScript(
|
|
71
|
+
if (isClientScript(spliceable)) {
|
|
70
72
|
const expanded = async (): Promise<unknown> => {
|
|
71
|
-
const args = await all(
|
|
72
|
-
return args.every((arg, index) => arg ===
|
|
73
|
-
?
|
|
74
|
-
: { ...
|
|
73
|
+
const args = await all(spliceable.args);
|
|
74
|
+
return args.every((arg, index) => arg === spliceable.args[index])
|
|
75
|
+
? spliceable
|
|
76
|
+
: { ...spliceable, args };
|
|
75
77
|
};
|
|
76
|
-
if (!
|
|
78
|
+
if (!isValue(spliceable)) {
|
|
77
79
|
return expanded();
|
|
78
80
|
}
|
|
79
|
-
let made = values.get(
|
|
81
|
+
let made = values.get(spliceable);
|
|
80
82
|
if (made === undefined) {
|
|
81
83
|
made = expanded();
|
|
82
|
-
values.set(
|
|
84
|
+
values.set(spliceable, made);
|
|
83
85
|
}
|
|
84
86
|
return made;
|
|
85
87
|
}
|
|
86
|
-
if (Array.isArray(
|
|
87
|
-
const elements = await all(
|
|
88
|
-
return elements.every((element, index) => element ===
|
|
89
|
-
?
|
|
88
|
+
if (Array.isArray(spliceable)) {
|
|
89
|
+
const elements = await all(spliceable);
|
|
90
|
+
return elements.every((element, index) => element === spliceable[index])
|
|
91
|
+
? spliceable
|
|
90
92
|
: elements;
|
|
91
93
|
}
|
|
92
94
|
// Only plain objects cross; rendering refuses anything else.
|
|
93
|
-
const prototype = Object.getPrototypeOf(
|
|
95
|
+
const prototype = Object.getPrototypeOf(spliceable);
|
|
94
96
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
95
|
-
return
|
|
97
|
+
return spliceable;
|
|
96
98
|
}
|
|
97
|
-
const entries = Object.entries(
|
|
99
|
+
const entries = Object.entries(spliceable);
|
|
98
100
|
const expanded = await all(entries.map(([, entry]) => entry));
|
|
99
101
|
if (expanded.every((entry, index) => entry === entries[index]![1])) {
|
|
100
|
-
return
|
|
102
|
+
return spliceable;
|
|
101
103
|
}
|
|
102
104
|
// Defined, not assigned, so a `__proto__` key stays a key.
|
|
103
105
|
return Object.fromEntries(
|
package/src/bundle/params.ts
CHANGED
|
@@ -7,6 +7,18 @@ export function bindingsOf(param: Param | undefined): readonly string[] {
|
|
|
7
7
|
return param?.kind === "splice" ? param.bindings : [];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
// Whether a script is one value for the bundle, made once at its top: a
|
|
11
|
+
// `once` script, a function and a class, as a module-level one is. A function
|
|
12
|
+
// or a class that reads a variable of the script around it, itself or through
|
|
13
|
+
// what it's handed, is made where it's read instead (see `valueOf`).
|
|
14
|
+
export function isValue(script: ClientScript): boolean {
|
|
15
|
+
return (
|
|
16
|
+
script.once === true ||
|
|
17
|
+
script.module.kind === "function" ||
|
|
18
|
+
script.module.kind === "class"
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
// The binding keys a script captures, in parameter order.
|
|
11
23
|
export function capturesOf(script: ClientScript): readonly string[] {
|
|
12
24
|
return script.module.params.flatMap((param) =>
|
package/src/bundler.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Spliceable, SplicesAs } from "@backtickjs/core";
|
|
1
|
+
import type { Bundle, Spliceable, Spliced, SplicesAs } from "@backtickjs/core";
|
|
2
2
|
import { buildBundle } from "./bundle/buildBundle.js";
|
|
3
3
|
import type { Modules } from "./modules.js";
|
|
4
4
|
import { printBundle } from "./print/printBundle.js";
|
|
@@ -23,39 +23,45 @@ export interface OutputOptions {
|
|
|
23
23
|
readonly sourcemap?: false | "inline" | "hidden";
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
/**
|
|
27
|
+
* What `generate` writes: the bundle, which runs to a `T`, and its map where
|
|
28
|
+
* one was asked for.
|
|
29
|
+
*/
|
|
30
|
+
export interface OutputChunk<T = unknown> {
|
|
31
|
+
readonly code: Bundle<T>;
|
|
29
32
|
readonly map: string | null;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
/** What `build` makes of a value that is a `T` on the client, written out by
|
|
36
|
+
* `generate`. */
|
|
37
|
+
export interface Build<T = unknown> {
|
|
38
|
+
generate(options: OutputOptions): OutputChunk<T>;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
42
|
* What runs your components and hands back what they drew, shaped as Rollup
|
|
39
43
|
* is: a build, then output from it.
|
|
40
44
|
*
|
|
41
|
-
* const
|
|
42
|
-
* const { code, map } =
|
|
45
|
+
* const build = await bundler.build({ input: <Home />, modules });
|
|
46
|
+
* const { code, map } = build.generate({ format: "es", sourcemap: "hidden" });
|
|
43
47
|
*
|
|
44
|
-
*
|
|
45
|
-
* namespace rather than a bare function, so `
|
|
46
|
-
* give what comes back.
|
|
48
|
+
* `code` is the bundle, a module whose default export is the value (CommonJS:
|
|
49
|
+
* `module.exports`). A namespace rather than a bare function, so `build`
|
|
50
|
+
* stays a name a caller can give what comes back.
|
|
47
51
|
*/
|
|
48
52
|
export const bundler = {
|
|
49
53
|
async build<T extends [T] extends [SplicesAs<T>] ? unknown : Spliceable>({
|
|
50
54
|
input,
|
|
51
55
|
modules,
|
|
52
|
-
}: BuildOptions<T>): Promise<
|
|
56
|
+
}: BuildOptions<T>): Promise<Build<Spliced<T>>> {
|
|
53
57
|
// Scripts come compiled for their framework when their host was built, so
|
|
54
58
|
// the bundle is only put together: nothing is compiled or parsed here.
|
|
55
59
|
const tree = await buildBundle(input, modules);
|
|
56
60
|
return {
|
|
57
61
|
generate: ({ format, sourcemap = false }) => {
|
|
58
|
-
const
|
|
62
|
+
const printed = printBundle(tree, format);
|
|
63
|
+
const code = printed.code as Bundle<Spliced<T>>;
|
|
64
|
+
const map = printed.map;
|
|
59
65
|
if (sourcemap === false) {
|
|
60
66
|
return { code, map: null };
|
|
61
67
|
}
|
|
@@ -63,7 +69,10 @@ export const bundler = {
|
|
|
63
69
|
return { code, map };
|
|
64
70
|
}
|
|
65
71
|
const url = `data:application/json;charset=utf-8,${encodeURIComponent(map)}`;
|
|
66
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
code: `${code}\n//# sourceMappingURL=${url}` as Bundle<Spliced<T>>,
|
|
74
|
+
map,
|
|
75
|
+
};
|
|
67
76
|
},
|
|
68
77
|
};
|
|
69
78
|
},
|
package/src/index.ts
CHANGED