Skip to content

Commit 1798f3f

Browse files
committed
Improved js_modules support
1 parent 39c5cdd commit 1798f3f

File tree

11 files changed

+96
-25
lines changed

11 files changed

+96
-25
lines changed

docs/core.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/core.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esm/custom.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export const handleCustomType = (node) => {
9999
XWorker,
100100
};
101101

102+
module.registerJSModule(interpreter, 'polyscript.js_modules', JSModules);
102103
module.registerJSModule(interpreter, 'polyscript', {
103104
js_modules: JSModules,
104105
XWorker,

esm/interpreter/ruby-wasm-wasi.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default {
2929
},
3030
// Fallback to globally defined module fields (i.e. $xworker)
3131
registerJSModule(interpreter, name, value) {
32+
name = name.replace(/\W+/g, '__');
3233
const id = `__module_${jsType}_${name}`;
3334
globalThis[id] = value;
3435
this.run(interpreter, `require "js";$${name}=JS.global[:${id}]`);

esm/script-handler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const execute = async (script, source, XWorker, isAsync) => {
6060
configurable: true,
6161
get: () => script,
6262
});
63+
module.registerJSModule(interpreter, 'polyscript.js_modules', JSModules);
6364
module.registerJSModule(interpreter, 'polyscript', {
6465
js_modules: JSModules,
6566
XWorker,

esm/utils.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ defineProperty(globalThis, js_modules, { value: jsModules });
6868

6969
export const JSModules = new Proxy(jsModules, {
7070
get: (map, name) => map.get(name),
71+
has: (map, name) => map.has(name),
72+
ownKeys: map => [...map.keys()],
7173
});
7274

7375
export const importJS = (source, name) => import(source).then(esm => {

esm/worker/_template.js

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import * as JSON from '@ungap/structured-clone/json';
88
import coincident from 'coincident/window';
99

10-
import { absoluteURL, assign, create, createFunction, createOverload, createResolved, dispatch, entries, isCSS, js_modules } from '../utils.js';
11-
import { base } from '../interpreter/_utils.js';
10+
import { assign, create, createFunction, createOverload, createResolved, dispatch } from '../utils.js';
11+
import createJSModules from './js_modules.js';
1212
import { configs, registry } from '../interpreters.js';
1313
import { getRuntime, getRuntimeID } from '../loader.js';
1414
import { patch, polluteJS, js as jsHooks, code as codeHooks } from '../hooks.js';
@@ -136,28 +136,14 @@ add('message', ({ data: { options, config: baseURL, code, hooks } }) => {
136136
const { CustomEvent, document } = window;
137137
const element = id && document.getElementById(id) || null;
138138
const notify = kind => dispatch(element, custom || type, kind, true, CustomEvent);
139+
const JSModules = createJSModules(window, sync, mainModules);
139140

140141
let target = '';
141142

142-
// set the `xworker` global reference once
143+
details.registerJSModule(interpreter, 'polyscript.js_modules', JSModules);
143144
details.registerJSModule(interpreter, 'polyscript', {
144145
xworker,
145-
js_modules: new Proxy(globalThis[js_modules], {
146-
get(map, name) {
147-
if (!map.has(name) && mainModules) {
148-
for (let [source, module] of entries(mainModules)) {
149-
if (module !== name) continue;
150-
source = absoluteURL(source, base.get(mainModules));
151-
if (isCSS(source)) sync.importCSS(source);
152-
else {
153-
sync.importJS(source, name);
154-
map.set(name, window[js_modules].get(name));
155-
}
156-
}
157-
}
158-
return map.get(name);
159-
}
160-
}),
146+
js_modules: JSModules,
161147
get target() {
162148
if (!target && element) {
163149
if (tag === 'SCRIPT') {

esm/worker/js_modules.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { absoluteURL, defineProperties, defineProperty, entries, isCSS, js_modules } from '../utils.js';
2+
import { base } from '../interpreter/_utils.js';
3+
4+
export default (window, sync, mainModules) => {
5+
const JSModules = {};
6+
const descriptors = {};
7+
const known = new Set;
8+
const ops = new Map;
9+
for (const [name, value] of globalThis[js_modules]) {
10+
known.add(name);
11+
descriptors[name] = { value };
12+
}
13+
// define lazy main modules resolution
14+
if (mainModules) {
15+
for (let [source, module] of entries(mainModules)) {
16+
// ignore modules already defined in worker
17+
if (known.has(module)) continue;
18+
let sources = ops.get(module);
19+
if (!sources) ops.set(module, (sources = []));
20+
sources.push(source);
21+
}
22+
for (const [name, sources] of ops) {
23+
descriptors[name] = {
24+
configurable: true,
25+
get() {
26+
let value;
27+
for (let source of sources) {
28+
source = absoluteURL(source, base.get(mainModules));
29+
if (isCSS(source)) sync.importCSS(source);
30+
else {
31+
sync.importJS(source, name);
32+
value = window[js_modules].get(name);
33+
}
34+
}
35+
// override the getter and make it no more configurable
36+
defineProperty(JSModules, name, { configurable: false, get: () => value });
37+
return value;
38+
}
39+
};
40+
}
41+
}
42+
return defineProperties(JSModules, descriptors);
43+
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,6 @@
8383
"sticky-module": "^0.1.1"
8484
},
8585
"worker": {
86-
"blob": "sha256-Ff8OBms0P5eTVfjUpcA1RayQJVKinKqjW+A+nsLN/ns="
86+
"blob": "sha256-gFg6QJJiDmvnxzhq0SoEdF6pDhzuRcvFEbZVZRxImpU="
8787
}
8888
}

test/modules-mpy.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
6+
<title>Polyscript JS Modules</title>
7+
<style>#main-map, #worker-map { height: 320px; } h3 { margin-bottom: 0; }</style>
8+
<script type="module" src="../core.js"></script>
9+
</head>
10+
<body>
11+
<!--
12+
main only: npx static-handler .
13+
main/worker: npx static-handler --coop --coep .
14+
15+
Note: --corp breaks the tiles server
16+
-->
17+
18+
<h3>Main</h3>
19+
<script type="micropython" config="./modules.toml">
20+
from polyscript import js_modules
21+
22+
print(js_modules.random_js.default)
23+
</script>
24+
25+
<hr>
26+
27+
<h3>Worker</h3>
28+
<script type="micropython" config="./modules.toml" worker>
29+
from polyscript.js_modules import random_js
30+
31+
print(random_js.default)
32+
</script>
33+
34+
</body>
35+
</html>

0 commit comments

Comments
 (0)