-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Any way to access loaders with "inline code" (vm.Script, eval, etc.) #116
Comments
I think the loader itself need to export some function, as the loaders API only deals with transforming URLs to a source string – or you could do |
Right, but that forces one to have to replicate the entire machinery. The As a thought experiment, imagine that instead of current The typescript-loader.js import { compile } from "typescript-compiler";
// This module has no need for a `resolve` function at all. HTTP/HTTPS requests that return
// mime-type: text/typescript work out of the box, data URLs that specify text/typescript work
// out of the box, and files with the file extension .ts work out of the box. If anyone ever
// implements a different storage loader (like ftp:// or something), that will also just work.
export const MimeType = "text/typescript";
export const FileExtensions = ["ts"];
export default function evaluate({ mimeType, source }, nextEvaluate) {
nextEvaluate({ mimeType:"text/javascript", source: compile(source) });
} Similarly, the https-loader.js const isHTTPS = specifier => specifier && .startsWith('https://');
export function fetch(specifier, context, nextFetch) {
const { parentURL = null } = context;
const HTTPSURL =
isHTTPS(specifier) ? new URL(specifier) :
isHTTPS(parentURL) ? new URL(specifier, parentURL) :
false;
if (!HTTPSURL)
return nextFetch(specifier);
// Normally Node.js would error on specifiers starting with 'https://', but here
// we can load the data ourselves.
return new Promise((resolve, reject) => {
get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve({
mimeType: res.getHeader("Content-Type"),
shortCircuit: true,
source: data,
}));
}).on('error', (err) => reject(err));
});
}
} As you can see, the HTTPS loader now only needs one function, and doesn't have to make the assumption about the format of the returned code. Similarly, a future CoffeeScript transpiler doesn't have to do an extreneous early recursive call to Just to demonstrate parity with the current API's abilities, a hypothetical "github:" github-loader.js export function fetch(specifier, context, nextFetch) {
if (!specifier.startWith("github:"))
return nextFetch(specifier, context);
return nextFetch(`https://github.com/${specifier}`, context);
} This now allows you to load from Back to the original issue though, this now provides a good foundation to have "loader" support (which is a bit of a loaded term since loaders do everything from loading to transpiling) anywhere code might show up. Whether it be in |
A quick note: I would not necessarily call the two functions |
An earlier version of the Loaders API had four hooks: We did this to make chaining more practical. If there are separate We’re approaching stable status for the API, so reevaluating the hooks is not something that I would welcome at this point. Refactoring them into All this said, your original question of having a way for loaders to apply to |
Hi @GeoffreyBooth, thanks for the response and the context! If the reasoning is around not wanting to change the API further, then I totally get that. However, I am wondering if you looked at all of the examples I provided -- the https loader in my system is (I think?) quite simpler and easier to follow than the one in the current docs (linked here again for comparison: https://nodejs.org/api/esm.html#https-loader). I only bring this up because I don't think this system is weighted towards transpiling at all, and leaves resolution equally simple for specifier/url changes, and more ergonomic for "just download" cases. If you look at the https loader in my example, it is of course shorter than the one in the node docs, but more importantly, requires implementing only one function (which I think makes way more sense, vs. having to implement I provided the 3 line "github" resolver example in my post to show how you still get super simple resolution with the "fetch/evaluate" system (to reiterate here, fetch doesn't force you to actually do the downloading if you just need to change the specifier/url, you can still send that off to the nextResolver). This one is short enough to just paste back in here: export function fetch(specifier, context, nextFetch) {
if (!specifier.startWith("github:"))
return nextFetch(specifier, context);
return nextFetch(`https://github.com/${specifier}`, context);
} I think the two big ideas are that 1) to your point, neither use case should be favored: and thus in most instances they should both require implementing just one function. And 2) we should adopt the existing mime-type standard for handling data, that we'd get for free from any sort of loader that interacts with the internet, as opposed to having an implicit system that relies on the code having to infer the type from the filesystem extension in both methods. Anyways, again, if the API is done then no worries, just wanted to make sure my concerns and explanation was clear, and also hopefully point out that this system isn't meant to in any way target transpilation at the expense of resolution -- I think both are simpler here, and their respective roles are clearler (as opposed to both handling identification for example). |
@tolmasky resolution and fetching are separate though. You need to resolve a specifier into a URL which allows returning the same module binding in the case multiple modules import the same module using different specifiers. Imagine: main.js import "https://example.com/foo.js";
import "https://example.com/etc.js"; import "./etc.js"; In this case the specifiers I do 100% agree we need a way to programmatically access the loader API. I'm working on a hot reloadable loader right now. Since nodejs caches modules forever eventually we run out of memory. I was hoping to move to |
If REPL support is included in Milestone 3, I think it would also makes sense to include support for |
Do you want to open an issue to update the readme? I don't think |
Assuming you meant PR, I opened one in #174 RE: ESM in I'm not sure how Since it's seems to accept statements, I'm curious what's preventing ESM import statements from working? |
I don't know, I've never looked into it. I assumed the current |
If you have serialized "content" of a specific loader format (say for example TypeScript, or whatever), it would be nice to be able to use the existing loader functionality to be able to evaluate it "inline". One might for example expect that
vm.Script
, given that it allows you specify afilename
option, might automatically choose the right loader:As far as I'm aware though, there is no way to do this currently (please correct me if I am mistaken!). I tried seeing if I could call load() directly to go through the loading machinery and just passing in the
source
property, but I also couldn't find an API to do that:The text was updated successfully, but these errors were encountered: