feat: Proof-of-concept for loading config as ES modules#318
feat: Proof-of-concept for loading config as ES modules#318ian-h-chamberlain wants to merge 1 commit into
Conversation
The basic idea:
- Register a `glide://` protocol handler, which serves TSBlank'd files
relative to the resolved `glide.ts`
- In the top-level config sandbox evaluation, run
`import("glide://config/glide.ts")`
- Config and subsequent imports are run in module mode
| // document: props.document, // hmm needed? | ||
| glide: props.glide, | ||
|
|
||
| sandboxName: props.name, |
There was a problem hiding this comment.
oops, this was supposed to go in the sandbox props, not proto.
| // console: props.console, | ||
| // document: props.document, // hmm needed? |
There was a problem hiding this comment.
These are read-only props on window, so if they need to be overridden then some alternative (proxying or something) might be necessary.
The actual props.window has to be used for the sandbox prototype in order to make a script loader available; creating a new proto object here (prior to my changes) fails to import anything with something like
JavaScript error: glide://config/glide.ts, line 2: Error: No ScriptLoader found for the current context
This is the biggest security concern I have with these changes; The sandbox implementation does a lot to make sure these imports are safe but I don't know enough about it to tell whether using the window directly like this is actually likely to be dangerous in any way.
| // For nice module resolution we could probably check existence of files, like | ||
| // fname + `.js`, etc. | ||
| const relpath = uri.pathname.replace(/([.]m?)js$/, '$1ts'); | ||
| const filepath = PathUtils.joinRelative('/Users/ianchamberlain/Documents/Development/glide/engine', relpath.replace(/^\//, '')); |
There was a problem hiding this comment.
Oops, forgot I had hardcoded this path for prototyping; in principle I think it should be straightforward to just share logic here to get the same result as load_config_at_path would
| "scheme": "glide", | ||
| "flags": [ | ||
| "URI_STD", | ||
| "URI_LOADABLE_BY_ANYONE", |
There was a problem hiding this comment.
Some of these flags probably should be adjusted, e.g. maybe URI_IS_LOCAL_FILE, URI_IS_UI_RESOURCE, URI_IS_LOCAL_RESOURCE? Not sure exactly what the right combination would be but this is probably important to get right.
Note: this is absolutely a proof-of-concept, there may be security issues and nice error handling is definitely lacking, but I wanted to be able to use modules for config so I spent some time trying to figure out how to implement it and this is the result.
I'm leaving this as a draft to see if this direction seems worth pursuing; I am not a browser expert so I'm not sure if there might be security implications (scary!) of doing something like this or any other issues, before I spend more time cleaning up the implementation.
The basic idea how this works:
glide://protocol handler, which serves TSBlank'd files relative to the resolved top-levelglide.tsconfigimport("glide://config/glide.ts")instead of evaluating the file contents directlyimportvia relative paths and suchA nice side effect is that you can look at the "effective configuration" by loading up
glide://config/glide.js(or.js) in the browser, and load errors in:replcan be clicked to lead directly to the source of the error (even for imported modules).To build this, I am utilizing the existing
gemini://protocol handler since it already implemented a lot of boilerplate, but things seems to "basically work" using these changes. Things I'd want to do to properly upstream:glide://protocol handler, obviously don't want to actually replace thegemini://protocol with thisglide://handler can't resolve a file or something that should be surfaced to the user instead of just serving an error messageimport from './test'instead of requiring.js. Maybe it's possible to make theview-source:glide://config/...lead to the original TypeScript source, whileglide://config/...contains JS?about:configflag maybe? Similar toglide.gemini.enabledthis seems like it could break people's config so it might be best to make it experimentalExample file setup to test it out: