bare-stow 0.1.1 → 0.1.3
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 +9 -7
- package/index.d.ts +3 -2
- package/index.js +39 -2
- package/lib/target/bare-sidecar.js +25 -6
- package/lib/target/bare-worker.js +82 -0
- package/lib/target.js +2 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ await ipc.ready
|
|
|
118
118
|
|
|
119
119
|
Bundle the module graph rooted at `entry` for a `target` runtime and write the resulting artifacts to disk at and alongside `out`. Returns an async generator that yields `{ url }` objects as each artifact is written, allowing callers to observe progress.
|
|
120
120
|
|
|
121
|
-
`entry` is a `URL` (or `URL`-coercible string) pointing at the entry module. `target` selects the target runtime, given either as
|
|
121
|
+
`entry` is a `URL` (or `URL`-coercible string) pointing at the entry module. `target` selects the target runtime, given either as a built-in name (`'bare-sidecar'` or `'bare-worker'`) or as a [target provider](#targets-and-rpc-providers) object. Other targets ship as their own packages; require one and pass it as the provider. The target determines the harness format, bundle extension, host triples, and whether assets and addons are linked into the bundle or offloaded as sibling files. `out` is the output `URL` of the harness; the bundle is written next to it with the target's extension.
|
|
122
122
|
|
|
123
123
|
The harness artifacts are yielded first: The harness itself at `out`, followed by a TypeScript declaration (`.d.ts`) alongside it so hosts importing the harness are typed. The bundle is yielded next, then any offloaded assets and native addons when the target supports offloading.
|
|
124
124
|
|
|
@@ -139,7 +139,7 @@ opts = {
|
|
|
139
139
|
- `server`: The RPC library to wire into the bundle entry shim as a server, given either as a built-in name (`'bare-rpc'`) or as an [RPC provider](#targets-and-rpc-providers) object.
|
|
140
140
|
- `base`: The base `URL` of the module graph. Defaults to the directory containing `entry`.
|
|
141
141
|
- `hosts`: An array of host triples to build for. Must be a subset of the host triples supported by the target; passing a host the target does not support throws. Defaults to all host triples supported by the target.
|
|
142
|
-
- `resolveTarget`: A function mapping a target name to a [target provider](#targets-and-rpc-providers) object, called when `target` is a name not in the built-in registry (which
|
|
142
|
+
- `resolveTarget`: A function mapping a target name to a [target provider](#targets-and-rpc-providers) object, called when `target` is a name not in the built-in registry (which knows `'bare-sidecar'` and `'bare-worker'`).
|
|
143
143
|
- `resolveRPC`: A function mapping an RPC library name to an [RPC provider](#targets-and-rpc-providers) object, called when `client` or `server` is a name not in the built-in registry (which only knows `'bare-rpc'`).
|
|
144
144
|
|
|
145
145
|
Any additional options are forwarded to `bare-pack`. See <https://github.com/holepunchto/bare-pack> for the full set, including `builtins`, `imports`, `defer`, and `resolve`.
|
|
@@ -171,9 +171,9 @@ target = {
|
|
|
171
171
|
format, // The bundle encoding: 'bundle', 'bundle.cjs', 'bundle.mjs', or 'bundle.json'.
|
|
172
172
|
encoding, // The string encoding for encoded formats, or null for raw bytes.
|
|
173
173
|
extension, // The bundle file extension, e.g. '.bundle'.
|
|
174
|
-
module, //
|
|
174
|
+
module, // Optional. Pins the harness module system to 'esm' or 'cjs'.
|
|
175
175
|
hosts, // The host triples the target supports.
|
|
176
|
-
generate({ bundleSpecifier, ipc, rpc, client }) {
|
|
176
|
+
generate({ bundleSpecifier, ipc, rpc, module, client }) {
|
|
177
177
|
// Return an array of harness artifacts.
|
|
178
178
|
}
|
|
179
179
|
}
|
|
@@ -181,7 +181,9 @@ target = {
|
|
|
181
181
|
|
|
182
182
|
For a target, each artifact is a file. The first has no `extension` and is written to `out`; each remaining artifact is written next to `out` with its own `extension` substituted for the harness extension (e.g. `{ extension: '.d.ts' }` becomes `index.d.ts`). The built-in targets emit two artifacts: The harness and its TypeScript declaration.
|
|
183
183
|
|
|
184
|
-
`generate()` receives `bundleSpecifier`, the relative specifier from the harness to the bundle artifact; `ipc`, the identifier the harness should bind the IPC stream to; `rpc`, the identifier the RPC client setup binds its instance to; and `client`, the resolved RPC client (or `null` when no client is requested). When present, `client` is `{ source, type }`: `source` is the runtime setup to splice into the harness (referencing `ipc` and binding `rpc`), and `type` is the TypeScript type of the bound instance to splice into the declaration. The target owns `linked`, `offload`, `format`, `encoding`, and `extension`; they are not overridable through `opts`.
|
|
184
|
+
`generate()` receives `bundleSpecifier`, the relative specifier from the harness to the bundle artifact; `ipc`, the identifier the harness should bind the IPC stream to; `rpc`, the identifier the RPC client setup binds its instance to; `module`, the harness module system (`'esm'` or `'cjs'`) so the harness can emit the matching module and import forms; and `client`, the resolved RPC client (or `null` when no client is requested). When present, `client` is `{ source, type }`: `source` is the runtime setup to splice into the harness (referencing `ipc` and binding `rpc`), and `type` is the TypeScript type of the bound instance to splice into the declaration. The target owns `linked`, `offload`, `format`, `encoding`, and `extension`; they are not overridable through `opts`.
|
|
185
|
+
|
|
186
|
+
The harness `module` system is derived from the output path: `out` ending in `.mjs` is ESM and `.cjs` is CommonJS, while an ambiguous `.js` (or other) extension follows the `type` of the closest enclosing `package.json` (`"module"` is ESM, otherwise CommonJS). A target may set its own `module` to pin the harness to one system regardless of the output path.
|
|
185
187
|
|
|
186
188
|
An RPC provider generates the wiring that binds an RPC instance to the IPC stream, used on both the client (harness) and server (shim) side:
|
|
187
189
|
|
|
@@ -194,7 +196,7 @@ rpc = {
|
|
|
194
196
|
}
|
|
195
197
|
```
|
|
196
198
|
|
|
197
|
-
For an RPC provider, each artifact is a fragment contributed to the harness file with the matching extension. The artifact with no `extension` is the runtime setup (reading `ipc`, binding `rpc`); the `{ extension: '.d.ts' }` artifact is the TypeScript type of the bound instance. `generate()` receives `ipc`, the identifier of the IPC stream in scope; `rpc`, the identifier to bind the RPC instance to; `module`, the surrounding module system (`'esm'` or `'cjs'`) so the runtime fragment can emit the matching import form; and `role`, either `'client'` or `'server'`. The bundler owns the `ipc` and `rpc` binding names and threads them to both the target and the RPC provider so neither has to assume them. It renders the client in the
|
|
199
|
+
For an RPC provider, each artifact is a fragment contributed to the harness file with the matching extension. The artifact with no `extension` is the runtime setup (reading `ipc`, binding `rpc`); the `{ extension: '.d.ts' }` artifact is the TypeScript type of the bound instance. `generate()` receives `ipc`, the identifier of the IPC stream in scope; `rpc`, the identifier to bind the RPC instance to; `module`, the surrounding module system (`'esm'` or `'cjs'`) so the runtime fragment can emit the matching import form; and `role`, either `'client'` or `'server'`. The bundler owns the `ipc` and `rpc` binding names and threads them to both the target and the RPC provider so neither has to assume them. It renders the client in the harness `module` and the server as `'esm'` (the shim is always an ES module), splicing the runtime fragment and, for the client, the type fragment into the target's artifacts. The shim is not a typed, host-facing module, so the server's type fragment is unused.
|
|
198
200
|
|
|
199
201
|
## CLI
|
|
200
202
|
|
|
@@ -218,7 +220,7 @@ Stow the module graph rooted at `<entry>`, writing the harness and bundle to the
|
|
|
218
220
|
|
|
219
221
|
##### `--target <name>`
|
|
220
222
|
|
|
221
|
-
The target runtime. Required. The built-in `bare-sidecar`
|
|
223
|
+
The target runtime. Required. The built-in `bare-sidecar` and `bare-worker` are resolved directly; any other `<name>` is loaded from its `bare-stow-target-<name>` package, or from `<name>` itself as a full module specifier, resolved from the working directory.
|
|
222
224
|
|
|
223
225
|
##### `--client <name>` and `--server <name>`
|
|
224
226
|
|
package/index.d.ts
CHANGED
|
@@ -5,12 +5,13 @@ interface Artifact {
|
|
|
5
5
|
source: string
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
type TargetName = 'bare-sidecar'
|
|
8
|
+
type TargetName = 'bare-sidecar' | 'bare-worker'
|
|
9
9
|
|
|
10
10
|
interface TargetContext {
|
|
11
11
|
bundleSpecifier: string
|
|
12
12
|
ipc: string
|
|
13
13
|
rpc: string
|
|
14
|
+
module: 'esm' | 'cjs'
|
|
14
15
|
client: RPCClient | null
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -21,7 +22,7 @@ interface Target {
|
|
|
21
22
|
format: 'bundle' | 'bundle.cjs' | 'bundle.mjs' | 'bundle.json'
|
|
22
23
|
encoding: string | null
|
|
23
24
|
extension: string
|
|
24
|
-
module
|
|
25
|
+
module?: 'esm' | 'cjs'
|
|
25
26
|
hosts: string[]
|
|
26
27
|
generate(context: TargetContext): Artifact[]
|
|
27
28
|
}
|
package/index.js
CHANGED
|
@@ -23,6 +23,9 @@ module.exports = async function* stow(entry, target, out, opts = {}) {
|
|
|
23
23
|
out = new URL(out)
|
|
24
24
|
base = base ? new URL(base) : new URL('./', entry)
|
|
25
25
|
|
|
26
|
+
// The target may pin a module system; otherwise it follows the output path.
|
|
27
|
+
const module = t.module || (await resolveModule(out))
|
|
28
|
+
|
|
26
29
|
if (hosts) {
|
|
27
30
|
for (const host of hosts) {
|
|
28
31
|
if (!t.hosts.includes(host)) {
|
|
@@ -93,8 +96,8 @@ module.exports = async function* stow(entry, target, out, opts = {}) {
|
|
|
93
96
|
const artifacts = rpc(client, resolveRPC).generate({
|
|
94
97
|
ipc: 'ipc',
|
|
95
98
|
rpc: 'rpc',
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
role: 'client',
|
|
100
|
+
module
|
|
98
101
|
})
|
|
99
102
|
|
|
100
103
|
clientSetup = {
|
|
@@ -107,6 +110,7 @@ module.exports = async function* stow(entry, target, out, opts = {}) {
|
|
|
107
110
|
bundleSpecifier,
|
|
108
111
|
ipc: 'ipc',
|
|
109
112
|
rpc: 'rpc',
|
|
113
|
+
module,
|
|
110
114
|
client: clientSetup
|
|
111
115
|
})
|
|
112
116
|
|
|
@@ -171,6 +175,39 @@ function collectOffloaded(base, out, sink) {
|
|
|
171
175
|
}
|
|
172
176
|
}
|
|
173
177
|
|
|
178
|
+
async function resolveModule(out) {
|
|
179
|
+
switch (path.extname(out.pathname)) {
|
|
180
|
+
case '.mjs':
|
|
181
|
+
return 'esm'
|
|
182
|
+
case '.cjs':
|
|
183
|
+
return 'cjs'
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// For an ambiguous extension (e.g. '.js') the module system follows the
|
|
187
|
+
// `type` of the closest enclosing `package.json`, defaulting to CommonJS.
|
|
188
|
+
return (await packageType(new URL('./', out))) === 'module' ? 'esm' : 'cjs'
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function packageType(dir) {
|
|
192
|
+
while (true) {
|
|
193
|
+
let source = null
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
source = await fs.readFile(new URL('package.json', dir))
|
|
197
|
+
} catch {
|
|
198
|
+
// No `package.json` in this directory; keep searching upwards.
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (source !== null) return JSON.parse(source).type ?? null
|
|
202
|
+
|
|
203
|
+
const parent = new URL('../', dir)
|
|
204
|
+
|
|
205
|
+
if (parent.pathname === dir.pathname) return null
|
|
206
|
+
|
|
207
|
+
dir = parent
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
174
211
|
function siblingURL(out, extension) {
|
|
175
212
|
const dir = new URL('./', out)
|
|
176
213
|
const base = path.basename(out.pathname, path.extname(out.pathname))
|
|
@@ -4,7 +4,6 @@ exports.offload = true
|
|
|
4
4
|
exports.format = 'bundle'
|
|
5
5
|
exports.encoding = null
|
|
6
6
|
exports.extension = '.bundle'
|
|
7
|
-
exports.module = 'cjs'
|
|
8
7
|
exports.hosts = [
|
|
9
8
|
'darwin-arm64',
|
|
10
9
|
'darwin-x64',
|
|
@@ -15,7 +14,9 @@ exports.hosts = [
|
|
|
15
14
|
]
|
|
16
15
|
|
|
17
16
|
exports.generate = function generate(opts) {
|
|
18
|
-
const { bundleSpecifier, ipc, rpc, client = null } = opts
|
|
17
|
+
const { bundleSpecifier, ipc, rpc, module = 'cjs', client = null } = opts
|
|
18
|
+
|
|
19
|
+
const esm = module === 'esm'
|
|
19
20
|
|
|
20
21
|
const returned = client ? `{ ${ipc}, ${rpc} }` : `{ ${ipc} }`
|
|
21
22
|
|
|
@@ -23,9 +24,25 @@ exports.generate = function generate(opts) {
|
|
|
23
24
|
? `{ ${ipc}: import('bare-stow/host').IPC; ${rpc}: ${client.type} }`
|
|
24
25
|
: `{ ${ipc}: import('bare-stow/host').IPC }`
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const source = esm
|
|
28
|
+
? `\
|
|
29
|
+
import Sidecar from 'bare-sidecar'
|
|
30
|
+
import stow from 'bare-stow/host'
|
|
31
|
+
import { fileURLToPath } from 'url'
|
|
32
|
+
|
|
33
|
+
const bundle = fileURLToPath(new URL(${JSON.stringify(bundleSpecifier)}, import.meta.url))
|
|
34
|
+
|
|
35
|
+
export async function start(opts = {}) {
|
|
36
|
+
const sidecar = new Sidecar(bundle, opts)
|
|
37
|
+
|
|
38
|
+
const ${ipc} = stow.wrap(sidecar)
|
|
39
|
+
${client ? '\n' + indent(client.source, 2) : ''}
|
|
40
|
+
await ${ipc}.ready
|
|
41
|
+
|
|
42
|
+
return ${returned}
|
|
43
|
+
}
|
|
44
|
+
`
|
|
45
|
+
: `\
|
|
29
46
|
const path = require('path')
|
|
30
47
|
const Sidecar = require('bare-sidecar')
|
|
31
48
|
const stow = require('bare-stow/host')
|
|
@@ -44,7 +61,9 @@ ${client ? '\n' + indent(client.source, 4) : ''}
|
|
|
44
61
|
}
|
|
45
62
|
}
|
|
46
63
|
`
|
|
47
|
-
|
|
64
|
+
|
|
65
|
+
return [
|
|
66
|
+
{ source },
|
|
48
67
|
{
|
|
49
68
|
extension: '.d.ts',
|
|
50
69
|
source: `\
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
exports.name = 'bare-worker'
|
|
2
|
+
exports.linked = false
|
|
3
|
+
exports.offload = true
|
|
4
|
+
exports.format = 'bundle'
|
|
5
|
+
exports.encoding = null
|
|
6
|
+
exports.extension = '.bundle'
|
|
7
|
+
exports.hosts = [
|
|
8
|
+
'darwin-arm64',
|
|
9
|
+
'darwin-x64',
|
|
10
|
+
'linux-arm64',
|
|
11
|
+
'linux-x64',
|
|
12
|
+
'win32-arm64',
|
|
13
|
+
'win32-x64'
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
exports.generate = function generate(opts) {
|
|
17
|
+
const { bundleSpecifier, ipc, rpc, module = 'cjs', client = null } = opts
|
|
18
|
+
|
|
19
|
+
const esm = module === 'esm'
|
|
20
|
+
|
|
21
|
+
const returned = client ? `{ ${ipc}, ${rpc} }` : `{ ${ipc} }`
|
|
22
|
+
|
|
23
|
+
const handle = client
|
|
24
|
+
? `{ ${ipc}: import('bare-stow/host').IPC; ${rpc}: ${client.type} }`
|
|
25
|
+
: `{ ${ipc}: import('bare-stow/host').IPC }`
|
|
26
|
+
|
|
27
|
+
const source = esm
|
|
28
|
+
? `\
|
|
29
|
+
import Worker from 'bare-worker'
|
|
30
|
+
import stow from 'bare-stow/host'
|
|
31
|
+
import { fileURLToPath } from 'bare-url'
|
|
32
|
+
|
|
33
|
+
const bundle = fileURLToPath(new URL(${JSON.stringify(bundleSpecifier)}, import.meta.url))
|
|
34
|
+
|
|
35
|
+
export async function start(opts = {}) {
|
|
36
|
+
const worker = new Worker(bundle, opts)
|
|
37
|
+
|
|
38
|
+
const ${ipc} = stow.wrap(worker.IPC)
|
|
39
|
+
${client ? '\n' + indent(client.source, 2) : ''}
|
|
40
|
+
await ${ipc}.ready
|
|
41
|
+
|
|
42
|
+
return ${returned}
|
|
43
|
+
}
|
|
44
|
+
`
|
|
45
|
+
: `\
|
|
46
|
+
const path = require('bare-path')
|
|
47
|
+
const Worker = require('bare-worker')
|
|
48
|
+
const stow = require('bare-stow/host')
|
|
49
|
+
|
|
50
|
+
const bundle = path.join(__dirname, ${JSON.stringify(bundleSpecifier)})
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
async start(opts = {}) {
|
|
54
|
+
const worker = new Worker(bundle, opts)
|
|
55
|
+
|
|
56
|
+
const ${ipc} = stow.wrap(worker.IPC)
|
|
57
|
+
${client ? '\n' + indent(client.source, 4) : ''}
|
|
58
|
+
await ${ipc}.ready
|
|
59
|
+
|
|
60
|
+
return ${returned}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
`
|
|
64
|
+
|
|
65
|
+
return [
|
|
66
|
+
{ source },
|
|
67
|
+
{
|
|
68
|
+
extension: '.d.ts',
|
|
69
|
+
source: `\
|
|
70
|
+
export function start(opts?: import('bare-worker').WorkerOptions): Promise<${handle}>
|
|
71
|
+
`
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function indent(source, spaces) {
|
|
77
|
+
const pad = ' '.repeat(spaces)
|
|
78
|
+
return source
|
|
79
|
+
.split('\n')
|
|
80
|
+
.map((line) => (line.length === 0 ? line : pad + line))
|
|
81
|
+
.join('\n')
|
|
82
|
+
}
|
package/lib/target.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-stow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Module bundling and harness generation for Bare",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./package": "./package.json",
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"bin.js",
|
|
41
41
|
"lib"
|
|
42
42
|
],
|
|
43
|
+
"workspaces": [
|
|
44
|
+
"test/fixtures/*",
|
|
45
|
+
"test/fixtures/*/*"
|
|
46
|
+
],
|
|
43
47
|
"scripts": {
|
|
44
48
|
"format": "prettier --write . && lunte --fix",
|
|
45
49
|
"lint": "prettier --check . && lunte",
|
|
@@ -72,6 +76,7 @@
|
|
|
72
76
|
"devDependencies": {
|
|
73
77
|
"bare-rpc": "^1.3.2",
|
|
74
78
|
"bare-sidecar": "^0.5.0",
|
|
79
|
+
"bare-worker": "^4.3.0",
|
|
75
80
|
"brittle": "^4.0.2",
|
|
76
81
|
"lunte": "^1.7.0",
|
|
77
82
|
"prettier": "^3.3.3",
|