clojurific 0.12.3 → 0.12.5
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 -0
- package/cljf/cli.js +12 -3
- package/cljf/launcher.js +2 -2
- package/cljf/repl.js +335 -0
- package/karma-esm/adapter.js +3 -3
- package/package.json +1 -1
- package/vite-plugin-cljs/index.js +5 -5
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@ counts Clojurific's releases, starting from 1.
|
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
|
+
`npm create clojurific@latest` scaffolds a project (Vanilla, Reagent or UIx)
|
|
20
|
+
like the one below, installs it and starts the dev server.
|
|
21
|
+
|
|
19
22
|
Dependencies and source paths come from the project's `deps.edn`:
|
|
20
23
|
|
|
21
24
|
```clojure
|
|
@@ -50,8 +53,14 @@ or with the command line:
|
|
|
50
53
|
npx cljf build '{:main my.app :output-dir "out"}'
|
|
51
54
|
npx cljf -A:test watch @cljs.edn
|
|
52
55
|
npx cljf classpath
|
|
56
|
+
npx cljf repl
|
|
53
57
|
```
|
|
54
58
|
|
|
59
|
+
`cljf repl` is a ClojureScript REPL evaluating in the pages the dev server
|
|
60
|
+
runs, through its nREPL server: `cljs({ outputDir: 'target/cljs',
|
|
61
|
+
compilerOptions: { repl: { 'nrepl-port': 0 } } })` with `nrepl/nrepl` in
|
|
62
|
+
`deps.edn`.
|
|
63
|
+
|
|
55
64
|
`cljf` resolves `deps.edn` with tools.deps, adds the compiler, and removes
|
|
56
65
|
stock ClojureScript (`org.clojure/clojurescript`) that libraries depend on.
|
|
57
66
|
Dependencies are downloaded into `~/.m2/repository`, which the Clojure CLI
|
package/cljf/cli.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// cljf: builds and watches ClojureScript with the compiler (
|
|
2
|
+
// cljf: builds and watches ClojureScript with the compiler (cljf.esm), on the
|
|
3
3
|
// project's classpath resolved from its deps.edn. See usage below.
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { LauncherError } from './errors.js';
|
|
7
7
|
import { classpath, compilerCommand, findJava, setupJava, version } from './launcher.js';
|
|
8
|
+
import { repl } from './repl.js';
|
|
8
9
|
|
|
9
10
|
const usage = `Usage: cljf [options] <command> [arguments]
|
|
10
11
|
|
|
11
12
|
Commands:
|
|
12
|
-
build [options...] compile once,
|
|
13
|
+
build [options...] compile once, cljf.esm's options: EDN maps, @file.edn
|
|
13
14
|
and :profile keywords (defaults to :release)
|
|
14
15
|
watch [options...] compile, then recompile on changes (defaults to :dev)
|
|
15
16
|
classpath print the project's classpath
|
|
17
|
+
repl [--port <port>] a ClojureScript REPL into the pages running the dev
|
|
18
|
+
server's (or watch's) build, through its nREPL server
|
|
19
|
+
(:repl {:nrepl-port 0}, port from .nrepl-port)
|
|
16
20
|
setup-java [version] download Eclipse Temurin (the latest LTS by default)
|
|
17
21
|
into cljf's cache, for machines without Java
|
|
18
22
|
|
|
@@ -65,7 +69,7 @@ async function main() {
|
|
|
65
69
|
case 'build':
|
|
66
70
|
case 'watch': {
|
|
67
71
|
const cmd = await compilerCommand({ ...opts, interactive, log });
|
|
68
|
-
run(cmd.command, [...cmd.args, '-m', '
|
|
72
|
+
run(cmd.command, [...cmd.args, '-m', 'cljf.esm', command, ...args]);
|
|
69
73
|
break;
|
|
70
74
|
}
|
|
71
75
|
case 'classpath': {
|
|
@@ -73,6 +77,11 @@ async function main() {
|
|
|
73
77
|
console.log(cp.classpath.join(path.delimiter));
|
|
74
78
|
break;
|
|
75
79
|
}
|
|
80
|
+
case 'repl': {
|
|
81
|
+
const i = args.indexOf('--port');
|
|
82
|
+
process.exit(await repl({ port: i >= 0 ? Number(args[i + 1]) : undefined }));
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
76
85
|
case 'setup-java': {
|
|
77
86
|
const { java } = await setupJava({ version: args[0], log });
|
|
78
87
|
console.log(java);
|
package/cljf/launcher.js
CHANGED
|
@@ -141,8 +141,8 @@ export async function classpath({ cwd = process.cwd(), aliases = [], force = fal
|
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* The command starting clojure.main with the compiler on the project's
|
|
144
|
-
* classpath: {command, args, java, classpath},
|
|
145
|
-
* args, i.e. [...args, '-m', '
|
|
144
|
+
* classpath: {command, args, java, classpath}, cljf.esm's arguments go after
|
|
145
|
+
* args, i.e. [...args, '-m', 'cljf.esm', 'build']. Options: cwd (the
|
|
146
146
|
* project, with its deps.edn), aliases, force (resolve the classpath again),
|
|
147
147
|
* interactive (offer to install Java), env and log.
|
|
148
148
|
*/
|
package/cljf/repl.js
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
// cljf repl: a ClojureScript REPL in the terminal, evaluating in the pages
|
|
2
|
+
// running a watched build. It's an nREPL client of the watcher's nREPL server
|
|
3
|
+
// (:repl {:nrepl-port 0}, see cljf.esm.repl.nrepl), whose session it
|
|
4
|
+
// switches to ClojureScript with (cljf.esm.repl/repl).
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import fs from 'node:fs/promises';
|
|
7
|
+
import net from 'node:net';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import readline from 'node:readline';
|
|
10
|
+
import { LauncherError } from './errors.js';
|
|
11
|
+
|
|
12
|
+
// bencode, nREPL's encoding: dicts, lists, integers and (UTF-8) strings
|
|
13
|
+
|
|
14
|
+
export function bencode(v) {
|
|
15
|
+
if (typeof v === 'number') return Buffer.from(`i${Math.trunc(v)}e`);
|
|
16
|
+
if (typeof v === 'string' || Buffer.isBuffer(v)) {
|
|
17
|
+
const bytes = Buffer.isBuffer(v) ? v : Buffer.from(v);
|
|
18
|
+
return Buffer.concat([Buffer.from(`${bytes.length}:`), bytes]);
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(v)) return Buffer.concat([Buffer.from('l'), ...v.map(bencode), Buffer.from('e')]);
|
|
21
|
+
const keys = Object.keys(v).filter(k => v[k] !== undefined).sort();
|
|
22
|
+
return Buffer.concat([Buffer.from('d'), ...keys.flatMap(k => [bencode(k), bencode(v[k])]), Buffer.from('e')]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const INCOMPLETE = Symbol('incomplete');
|
|
26
|
+
|
|
27
|
+
// The value at buf[i], [value, next index], or INCOMPLETE
|
|
28
|
+
function decodeAt(buf, i) {
|
|
29
|
+
if (i >= buf.length) return INCOMPLETE;
|
|
30
|
+
const c = String.fromCharCode(buf[i]);
|
|
31
|
+
if (c === 'i') {
|
|
32
|
+
const end = buf.indexOf('e', i);
|
|
33
|
+
return end < 0 ? INCOMPLETE : [Number(buf.toString('latin1', i + 1, end)), end + 1];
|
|
34
|
+
}
|
|
35
|
+
if (c === 'l' || c === 'd') {
|
|
36
|
+
const items = [];
|
|
37
|
+
let j = i + 1;
|
|
38
|
+
while (j < buf.length && buf[j] !== 0x65) {
|
|
39
|
+
const item = decodeAt(buf, j);
|
|
40
|
+
if (item === INCOMPLETE) return INCOMPLETE;
|
|
41
|
+
items.push(item[0]);
|
|
42
|
+
j = item[1];
|
|
43
|
+
}
|
|
44
|
+
if (j >= buf.length) return INCOMPLETE;
|
|
45
|
+
if (c === 'l') return [items, j + 1];
|
|
46
|
+
const dict = {};
|
|
47
|
+
for (let k = 0; k < items.length; k += 2) dict[items[k]] = items[k + 1];
|
|
48
|
+
return [dict, j + 1];
|
|
49
|
+
}
|
|
50
|
+
if (c >= '0' && c <= '9') {
|
|
51
|
+
const colon = buf.indexOf(':', i);
|
|
52
|
+
if (colon < 0) return INCOMPLETE;
|
|
53
|
+
const start = colon + 1;
|
|
54
|
+
const end = start + Number(buf.toString('latin1', i, colon));
|
|
55
|
+
return end > buf.length ? INCOMPLETE : [buf.toString('utf8', start, end), end];
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`bencode: unexpected ${JSON.stringify(c)}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Decodes the values of a byte stream, as chunks arrive. */
|
|
61
|
+
export class Decoder {
|
|
62
|
+
#buf = Buffer.alloc(0);
|
|
63
|
+
|
|
64
|
+
/** The values chunk completes. */
|
|
65
|
+
push(chunk) {
|
|
66
|
+
this.#buf = Buffer.concat([this.#buf, chunk]);
|
|
67
|
+
const values = [];
|
|
68
|
+
for (;;) {
|
|
69
|
+
const decoded = decodeAt(this.#buf, 0);
|
|
70
|
+
if (decoded === INCOMPLETE) return values;
|
|
71
|
+
values.push(decoded[0]);
|
|
72
|
+
this.#buf = this.#buf.subarray(decoded[1]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Whether code's forms are all closed, so that the REPL evaluates it rather
|
|
79
|
+
* than reading another line: no open (, [ or {, string or regex. Extra
|
|
80
|
+
* closing brackets are the reader's to report.
|
|
81
|
+
*/
|
|
82
|
+
export function complete(code) {
|
|
83
|
+
let depth = 0;
|
|
84
|
+
for (let i = 0; i < code.length; i++) {
|
|
85
|
+
const c = code[i];
|
|
86
|
+
if (c === ';') {
|
|
87
|
+
while (i < code.length && code[i] !== '\n') i++;
|
|
88
|
+
} else if (c === '\\') {
|
|
89
|
+
i++;
|
|
90
|
+
} else if (c === '"') {
|
|
91
|
+
for (i++; i < code.length && code[i] !== '"'; i++) if (code[i] === '\\') i++;
|
|
92
|
+
if (i >= code.length) return false;
|
|
93
|
+
} else if ('([{'.includes(c)) {
|
|
94
|
+
depth++;
|
|
95
|
+
} else if (')]}'.includes(c)) {
|
|
96
|
+
depth--;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return depth <= 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** An nREPL connection: requests whose responses end with status done. */
|
|
103
|
+
export class Connection {
|
|
104
|
+
#socket;
|
|
105
|
+
#ids = 0;
|
|
106
|
+
#pending = new Map();
|
|
107
|
+
|
|
108
|
+
constructor(socket) {
|
|
109
|
+
this.#socket = socket;
|
|
110
|
+
const decoder = new Decoder();
|
|
111
|
+
socket.on('data', chunk => {
|
|
112
|
+
for (const msg of decoder.push(chunk)) {
|
|
113
|
+
const request = this.#pending.get(msg.id);
|
|
114
|
+
if (!request) continue;
|
|
115
|
+
request.onResponse(msg);
|
|
116
|
+
if (msg.status?.includes('done')) {
|
|
117
|
+
this.#pending.delete(msg.id);
|
|
118
|
+
request.resolve(msg);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** A message id for request. */
|
|
125
|
+
newId() {
|
|
126
|
+
return String(++this.#ids);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Sends msg (with an id from newId, or a new one), calls onResponse with
|
|
131
|
+
* its responses; resolves to the last.
|
|
132
|
+
*/
|
|
133
|
+
request(msg, onResponse = () => {}) {
|
|
134
|
+
const id = msg.id ?? this.newId();
|
|
135
|
+
return new Promise(resolve => {
|
|
136
|
+
this.#pending.set(id, { onResponse, resolve });
|
|
137
|
+
this.#socket.write(bencode({ ...msg, id }));
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
close() {
|
|
142
|
+
this.#socket.end();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function connect(port, host) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const socket = net.connect(port, host);
|
|
149
|
+
socket.once('connect', () => {
|
|
150
|
+
socket.off('error', reject);
|
|
151
|
+
resolve(socket);
|
|
152
|
+
});
|
|
153
|
+
socket.once('error', reject);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Connects to the nREPL server on port, or the one in cwd's .nrepl-port,
|
|
159
|
+
* waiting for it to start (the dev server writes the file once it built).
|
|
160
|
+
*/
|
|
161
|
+
export async function connectToServer({ cwd = process.cwd(), port, host = '127.0.0.1', log = () => {}, interval = 500 } = {}) {
|
|
162
|
+
const portFile = path.join(cwd, '.nrepl-port');
|
|
163
|
+
let waiting = false;
|
|
164
|
+
for (;;) {
|
|
165
|
+
const p = port ?? (existsSync(portFile) ? Number((await fs.readFile(portFile, 'utf8')).trim()) : null);
|
|
166
|
+
if (p) {
|
|
167
|
+
try {
|
|
168
|
+
return await connect(p, host);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
if (port) throw new LauncherError(`cljf repl: no nREPL server on ${host}:${port}: ${e.message}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (!waiting) {
|
|
174
|
+
log(`; waiting for the nREPL server of the dev server (npm run dev) or cljf watch, with :repl {:nrepl-port 0},\n; to write ${portFile}`);
|
|
175
|
+
waiting = true;
|
|
176
|
+
}
|
|
177
|
+
await new Promise(resolve => setTimeout(resolve, interval));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function readHistory(file) {
|
|
182
|
+
try {
|
|
183
|
+
return (await fs.readFile(file, 'utf8')).split('\n').filter(Boolean).reverse();
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The REPL: reads forms from input, evaluates them in the session switched
|
|
191
|
+
* to ClojureScript, writes their output and values to output (errors and
|
|
192
|
+
* warnings to errorOutput). Resolves to the exit code once input ends or
|
|
193
|
+
* :cljs/quit.
|
|
194
|
+
*/
|
|
195
|
+
export async function repl({
|
|
196
|
+
cwd = process.cwd(),
|
|
197
|
+
port,
|
|
198
|
+
host,
|
|
199
|
+
input = process.stdin,
|
|
200
|
+
output = process.stdout,
|
|
201
|
+
errorOutput = process.stderr,
|
|
202
|
+
terminal = Boolean(input.isTTY && output.isTTY),
|
|
203
|
+
historyFile = path.join(cwd, '.cljf', 'repl-history'),
|
|
204
|
+
} = {}) {
|
|
205
|
+
const socket = await connectToServer({ cwd, port, host, log: line => errorOutput.write(`${line}\n`) });
|
|
206
|
+
const conn = new Connection(socket);
|
|
207
|
+
let closing = false;
|
|
208
|
+
const closed = new Promise(resolve => socket.on('close', resolve));
|
|
209
|
+
socket.on('error', () => {});
|
|
210
|
+
|
|
211
|
+
const write = (stream, text) => text && stream.write(text);
|
|
212
|
+
const { 'new-session': session } = await conn.request({ op: 'clone' });
|
|
213
|
+
let failed = false;
|
|
214
|
+
await conn.request({ op: 'eval', session, code: '(cljf.esm.repl/repl)' }, msg => {
|
|
215
|
+
write(output, msg.out);
|
|
216
|
+
write(errorOutput, msg.err);
|
|
217
|
+
if (msg.ex) failed = true;
|
|
218
|
+
});
|
|
219
|
+
if (failed) {
|
|
220
|
+
conn.close();
|
|
221
|
+
throw new LauncherError('cljf repl: the nREPL server has no ClojureScript REPL (cljf.esm.repl), is it the dev server\'s?');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const history = terminal ? await readHistory(historyFile) : [];
|
|
225
|
+
const rl = readline.createInterface({ input, output, terminal, history, historySize: 1000, removeHistoryDuplicates: true });
|
|
226
|
+
if (terminal) {
|
|
227
|
+
rl.on('history', lines => {
|
|
228
|
+
fs.mkdir(path.dirname(historyFile), { recursive: true })
|
|
229
|
+
.then(() => fs.writeFile(historyFile, `${[...lines].reverse().join('\n')}\n`))
|
|
230
|
+
.catch(() => {});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let ns = 'cljs.user';
|
|
235
|
+
let pending = '';
|
|
236
|
+
let evaluating = null;
|
|
237
|
+
let interrupted = false;
|
|
238
|
+
const prompt = () => {
|
|
239
|
+
if (!terminal) return;
|
|
240
|
+
rl.setPrompt(pending ? `${' '.repeat(Math.max(0, ns.length - 1))}#_=> ` : `${ns}=> `);
|
|
241
|
+
rl.prompt();
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const done = new Promise(resolve => {
|
|
245
|
+
const quit = code => {
|
|
246
|
+
closing = true;
|
|
247
|
+
rl.close();
|
|
248
|
+
// the server forgets the session, unless it doesn't answer
|
|
249
|
+
const timeout = new Promise(r => setTimeout(r, 1000).unref());
|
|
250
|
+
Promise.race([conn.request({ op: 'close', session }), timeout]).finally(() => {
|
|
251
|
+
conn.close();
|
|
252
|
+
resolve(code);
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
closed.then(() => {
|
|
256
|
+
if (closing) return;
|
|
257
|
+
errorOutput.write('\n; the nREPL server closed the connection\n');
|
|
258
|
+
closing = true;
|
|
259
|
+
rl.close();
|
|
260
|
+
resolve(1);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
rl.on('SIGINT', () => {
|
|
264
|
+
if (evaluating) {
|
|
265
|
+
conn.request({ op: 'interrupt', session, 'interrupt-id': evaluating });
|
|
266
|
+
} else if (pending || rl.line) {
|
|
267
|
+
pending = '';
|
|
268
|
+
interrupted = false;
|
|
269
|
+
rl.write(null, { ctrl: true, name: 'u' });
|
|
270
|
+
output.write('\n');
|
|
271
|
+
prompt();
|
|
272
|
+
} else if (interrupted) {
|
|
273
|
+
quit(0);
|
|
274
|
+
} else {
|
|
275
|
+
interrupted = true;
|
|
276
|
+
output.write('\n; Ctrl-C again, Ctrl-D or :cljs/quit to quit\n');
|
|
277
|
+
prompt();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// lines are read one at a time: a form waits for the one before
|
|
282
|
+
const lines = [];
|
|
283
|
+
let busy = false;
|
|
284
|
+
const next = async () => {
|
|
285
|
+
if (busy) return;
|
|
286
|
+
busy = true;
|
|
287
|
+
while (lines.length) {
|
|
288
|
+
const line = lines.shift();
|
|
289
|
+
if (line === null) {
|
|
290
|
+
quit(0);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
interrupted = false;
|
|
294
|
+
pending += `${line}\n`;
|
|
295
|
+
if (!complete(pending)) {
|
|
296
|
+
prompt();
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const code = pending;
|
|
300
|
+
pending = '';
|
|
301
|
+
if (!code.trim()) {
|
|
302
|
+
prompt();
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (code.trim() === ':cljs/quit') {
|
|
306
|
+
quit(0);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
evaluating = conn.newId();
|
|
310
|
+
await conn.request({ op: 'eval', session, code, ns, id: evaluating }, msg => {
|
|
311
|
+
write(output, msg.out);
|
|
312
|
+
write(errorOutput, msg.err);
|
|
313
|
+
if (msg.value !== undefined) output.write(`${msg.value}\n`);
|
|
314
|
+
if (msg.ns) ns = msg.ns;
|
|
315
|
+
});
|
|
316
|
+
evaluating = null;
|
|
317
|
+
if (closing) return;
|
|
318
|
+
prompt();
|
|
319
|
+
}
|
|
320
|
+
busy = false;
|
|
321
|
+
};
|
|
322
|
+
rl.on('line', line => {
|
|
323
|
+
lines.push(line);
|
|
324
|
+
next();
|
|
325
|
+
});
|
|
326
|
+
rl.on('close', () => {
|
|
327
|
+
if (closing) return;
|
|
328
|
+
lines.push(null);
|
|
329
|
+
next();
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
prompt();
|
|
334
|
+
return done;
|
|
335
|
+
}
|
package/karma-esm/adapter.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// Karma adapter for a
|
|
2
|
-
//
|
|
1
|
+
// Karma adapter for a cljf.esm test bundle (an ES module) run by
|
|
2
|
+
// cljf.esm.karma/start. Add it to Karma's files, serve the bundle's directory
|
|
3
3
|
// (included: false), and name its entry module in client.args:
|
|
4
4
|
//
|
|
5
5
|
// files: ['<this file>', {pattern: 'build/ci-test/**/*', included: false}],
|
|
6
6
|
// client: {args: ['/base/build/ci-test/my.test-runner.js']},
|
|
7
7
|
//
|
|
8
8
|
// Karma calls start once the page has loaded, module scripts may not have run
|
|
9
|
-
// yet:
|
|
9
|
+
// yet: cljf.esm.karma/start runs the tests in whichever order the two happen.
|
|
10
10
|
window.__karma__.start = function () {
|
|
11
11
|
window.__karmaStarted = true;
|
|
12
12
|
if (window.__karmaRun) window.__karmaRun();
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ import { Worker } from 'node:worker_threads';
|
|
|
16
16
|
import { compilerCommand } from '../cljf/launcher.js';
|
|
17
17
|
import { pruneChunks, propertyRenames } from './prune.js';
|
|
18
18
|
|
|
19
|
-
const EVENT_PREFIX = '[
|
|
19
|
+
const EVENT_PREFIX = '[cljf.esm] ';
|
|
20
20
|
const NPM_AS = 'cljs-npm-as:';
|
|
21
21
|
// a ClojureScript source loaded by a page or imported from JavaScript, which
|
|
22
22
|
// the dev server serves as an import of its compiled module
|
|
@@ -227,11 +227,11 @@ export default module.exports;
|
|
|
227
227
|
* the compiler added and stock ClojureScript removed, see cljf/launcher.js.
|
|
228
228
|
* @param {string[]} [options.command] starts Clojure with the compiler on the
|
|
229
229
|
* classpath instead of the launcher, i.e. ["clojure", "-M:cljs"],
|
|
230
|
-
*
|
|
230
|
+
* cljf.esm's arguments follow
|
|
231
231
|
* @param {string} [options.cwd] the compiler's working directory, with the
|
|
232
232
|
* project's deps.edn, defaults to Vite's root (the project's directory)
|
|
233
233
|
* @param {string} [options.config] compiler options file (EDN, see
|
|
234
|
-
*
|
|
234
|
+
* cljf.esm/load-options), relative to cwd
|
|
235
235
|
* @param {string} [options.profile] profile of the config file, defaults to
|
|
236
236
|
* dev when serving and release when building
|
|
237
237
|
* @param {string} options.outputDir the compiler's output directory, relative
|
|
@@ -285,7 +285,7 @@ export default function cljs(options) {
|
|
|
285
285
|
|
|
286
286
|
function run(args, onEvent) {
|
|
287
287
|
const [cmd, ...cmdArgs] = compiler;
|
|
288
|
-
const child = spawn(cmd, [...cmdArgs, '-m', '
|
|
288
|
+
const child = spawn(cmd, [...cmdArgs, '-m', 'cljf.esm', ...args], {
|
|
289
289
|
cwd,
|
|
290
290
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
291
291
|
});
|
|
@@ -686,7 +686,7 @@ export default function cljs(options) {
|
|
|
686
686
|
server.ws.send(problem);
|
|
687
687
|
};
|
|
688
688
|
server.ws.on('connection', socket => problem && socket.send(JSON.stringify(problem)));
|
|
689
|
-
// The REPL (
|
|
689
|
+
// The REPL (cljf.esm.repl): pages running the build (cljf.esm.repl-runtime)
|
|
690
690
|
// say hello over Vite's websocket, each connection gets a runtime id. Their
|
|
691
691
|
// cljs:repl messages go to the compiler as `repl <json>` lines, the
|
|
692
692
|
// compiler's repl-send events to the page of their runtime id.
|