mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 13:04:30 -08:00
loading external modules from FileSystem access API
This commit is contained in:
@@ -13,18 +13,51 @@ self.addEventListener('activate', function(event) {
|
|||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let data
|
let dir_handle
|
||||||
|
|
||||||
self.addEventListener('message', async function(e) {
|
self.addEventListener('message', async function(e) {
|
||||||
const msg = e.data
|
const msg = e.data
|
||||||
let reply
|
let reply
|
||||||
if(msg.type == 'SET') {
|
if(msg.type == 'SET') {
|
||||||
data = msg.data
|
dir_handle = msg.data
|
||||||
reply = null
|
reply = null
|
||||||
} else if(msg.type == 'GET') {
|
} else if(msg.type == 'GET') {
|
||||||
reply = data
|
reply = dir_handle
|
||||||
} else {
|
} else {
|
||||||
throw new Error('unknown message type: ' + msg.type)
|
throw new Error('unknown message type: ' + msg.type)
|
||||||
}
|
}
|
||||||
e.ports[0].postMessage(reply)
|
e.ports[0].postMessage(reply)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Fake URL base prepended by code responsible for module loading
|
||||||
|
const FAKE_URL_BASE = 'https://leporello.import/'
|
||||||
|
|
||||||
|
self.addEventListener("fetch", event => {
|
||||||
|
if(event.request.url.startsWith(FAKE_URL_BASE)) {
|
||||||
|
if(dir_handle != null) {
|
||||||
|
const headers = new Headers([
|
||||||
|
['Content-Type', 'text/javascript']
|
||||||
|
])
|
||||||
|
const path = event.request.url.replace(FAKE_URL_BASE, '')
|
||||||
|
const response = read_file(dir_handle, path).then(file =>
|
||||||
|
new Response(file, {headers})
|
||||||
|
)
|
||||||
|
event.respondWith(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const read_file = async (dir_handle, filename) => {
|
||||||
|
if(typeof(filename) == 'string') {
|
||||||
|
filename = filename.split('/')
|
||||||
|
}
|
||||||
|
const [first, ...rest] = filename
|
||||||
|
if(rest.length == 0) {
|
||||||
|
const fhandle = await dir_handle.getFileHandle(first)
|
||||||
|
const file_data = await fhandle.getFile()
|
||||||
|
return await file_data.text()
|
||||||
|
} else {
|
||||||
|
const nested_dir_handle = await dir_handle.getDirectoryHandle(first)
|
||||||
|
return read_file(nested_dir_handle, rest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
9
src/effects.js
vendored
9
src/effects.js
vendored
@@ -10,7 +10,14 @@ const load_external_imports = async state => {
|
|||||||
}
|
}
|
||||||
const urls = state.loading_external_imports_state.external_imports
|
const urls = state.loading_external_imports_state.external_imports
|
||||||
const results = await Promise.allSettled(
|
const results = await Promise.allSettled(
|
||||||
urls.map(u => import(u))
|
urls.map(u => import(
|
||||||
|
/^\w+:\/\//.test(u)
|
||||||
|
? // starts with protocol, import as is
|
||||||
|
u
|
||||||
|
: //local path, load using File System Access API, see service_worker.js
|
||||||
|
// Append fake host that will be intercepted in service worker
|
||||||
|
'https://leporello.import/' + u
|
||||||
|
))
|
||||||
)
|
)
|
||||||
const modules = Object.fromEntries(
|
const modules = Object.fromEntries(
|
||||||
results.map((r, i) => (
|
results.map((r, i) => (
|
||||||
|
|||||||
@@ -154,39 +154,6 @@ export const find_definitions = (ast, scope = {}, closure_scope = {}, module_nam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// see https://stackoverflow.com/a/29855511
|
|
||||||
|
|
||||||
// Joins path segments. Preserves initial "/" and resolves ".." and "."
|
|
||||||
// Does not support using ".." to go above/outside the root.
|
|
||||||
// This means that join("foo", "../../bar") will not resolve to "../bar"
|
|
||||||
|
|
||||||
const join = new Function(`
|
|
||||||
// Split the inputs into a list of path commands.
|
|
||||||
var parts = [];
|
|
||||||
for (var i = 0, l = arguments.length; i < l; i++) {
|
|
||||||
parts = parts.concat(arguments[i].split("/"));
|
|
||||||
}
|
|
||||||
// Interpret the path commands to get the new resolved path.
|
|
||||||
var newParts = [];
|
|
||||||
for (i = 0, l = parts.length; i < l; i++) {
|
|
||||||
var part = parts[i];
|
|
||||||
// Remove leading and trailing slashes
|
|
||||||
// Also remove "." segments
|
|
||||||
if (!part || part === ".") continue;
|
|
||||||
// Interpret ".." to pop the last segment
|
|
||||||
if (part === "..") newParts.pop();
|
|
||||||
// Push new path segments.
|
|
||||||
else newParts.push(part);
|
|
||||||
}
|
|
||||||
// Preserve the initial slash if there was one.
|
|
||||||
if (parts[0] === "") newParts.unshift("");
|
|
||||||
// Turn back into a single string path.
|
|
||||||
return newParts.join("/") || (newParts.length ? "/" : ".");
|
|
||||||
`)
|
|
||||||
|
|
||||||
const concat_path = (base, imported) =>
|
|
||||||
base == '' ? join(imported) : join(base, '..', imported)
|
|
||||||
|
|
||||||
export const find_export = (name, module) => {
|
export const find_export = (name, module) => {
|
||||||
return map_find(module.stmts, n => {
|
return map_find(module.stmts, n => {
|
||||||
if(n.type != 'export') {
|
if(n.type != 'export') {
|
||||||
@@ -197,6 +164,16 @@ export const find_export = (name, module) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BASE = 'dummy://dummy/'
|
||||||
|
const concat_path = (base, i) => {
|
||||||
|
const result = new URL(i, BASE + base).toString()
|
||||||
|
if(result.lastIndexOf(BASE) == 0) {
|
||||||
|
return result.replace(BASE, '')
|
||||||
|
} else {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
export const topsort_modules = (modules) => {
|
export const topsort_modules = (modules) => {
|
||||||
const sort_module_deps = (module) => {
|
const sort_module_deps = (module) => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export const globals = new Set([
|
|||||||
'globalThis',
|
'globalThis',
|
||||||
// TODO Promise,
|
// TODO Promise,
|
||||||
// TODO Symbol
|
// TODO Symbol
|
||||||
|
'URL',
|
||||||
'Set',
|
'Set',
|
||||||
'Map',
|
'Map',
|
||||||
"Infinity",
|
"Infinity",
|
||||||
|
|||||||
@@ -2310,7 +2310,7 @@ const y = x()`
|
|||||||
on_async_call: (calls) => {console.log('test on async call', calls)}
|
on_async_call: (calls) => {console.log('test on async call', calls)}
|
||||||
})
|
})
|
||||||
globalThis.__run_async_call()
|
globalThis.__run_async_call()
|
||||||
delete globalThis.__run_async_call
|
//delete globalThis.__run_async_call
|
||||||
}),
|
}),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user