Skip to content
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

Discuss interaction with speculative parsing/fetching #241

Merged
merged 3 commits into from
Jan 12, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ _Or, how to control the behavior of JavaScript imports_
- [Installation](#installation)
- [Dynamic import map example](#dynamic-import-map-example)
- [Scope](#scope)
- [Interaction with speculative parsing/fetching](#interaction-with-speculative-parsingfetching)
- [Alternatives considered](#alternatives-considered)
- [The Node.js module resolution algorithm](#the-nodejs-module-resolution-algorithm)
- [A programmable resolution hook](#a-programmable-resolution-hook)
Expand Down Expand Up @@ -433,6 +434,68 @@ This, in addition to general simplicity, is in part what motivates the above res

Since an application's import map changes the resolution algorithm for every module in the module map, they are not impacted by whether a module's source text was originally from a cross-origin URL. If you load a module from a CDN that uses bare import specifiers, you'll need to know ahead of time what bare import specifiers that module adds to your app, and include them in your application's import map. (That is, you need to know what all of your application's transitive dependencies are.) It's important that control of which URLs are used for each package stay with the application author, so they can holistically manage versioning and sharing of modules.

### Interaction with speculative parsing/fetching

Most browsers have a speculative HTML parser which tries to discover resources declared in HTML markup while the HTML parser is waiting for blocking scripts to be fetched and executed. This is not yet specified, although there are ongoing efforts to do so in [whatwg/html#5959](https://github.com/whatwg/html/pull/5959). This section discusses some of the potential interactions to be aware of.

First, note that although to our knowledge no browsers do so currently, it would be possible for a speculative parser to fetch `https://example.com/foo.mjs` in the following example, while it waits for the blocking script `https://example.com/blocking-1.js`:

```html
<!DOCTYPE html>
<!-- This file is https://example.com/ -->
<script src="blocking-1.js"></script>
<script type="module">
import "./foo.mjs";
</script>
```

Similarly, a browser could speculatively fetch `https://example.com/foo.mjs` and `https://example.com/bar.mjs` in the following example, by parsing the import map as part of the speculative parsing process:

```html
<!DOCTYPE html>
<!-- This file is https://example.com/ -->
<script src="blocking-2.js"></script>
<script type="importmap">
{
"imports": {
"foo": "./foo.mjs",
"https://other.example/bar.mjs": "./bar.mjs"
}
}
</script>
<script type="module">
import "foo";
import "https://other.example/bar.mjs";
</script>
```

One interaction to notice here is that browsers which do speculatively parse inline JS modules, but do not support import maps, would probably speculate incorrectly for this example: they might speculatively fetch `https://other.example/bar.mjs`, instead of the `https://example.com/bar.mjs` it is mapped to.

More generally, import map-based speculations can be subject to the same sort of mistakes as other speculations. For example, if the contents of `blocking-1.js` were

```js
const el = document.createElement("base");
el.href = "/subdirectory/";
document.currentScript.after(el);
```

then the speculative fetch of `https://example.com/foo.mjs` in the no-import map example would be wasted, as by the time came to perform the actual evaluation of the module, we'd re-compute the relative specifier `"./foo.mjs"` and realize that what's actually requested is `https://example.com/subdirectory/foo.mjs`.

Similarly for the import map case, if the contents of `blocking-2.js` were

```js
document.write(`<script type="importmap">
{
"imports": {
"foo": "./other-foo.mjs",
"https://other.example/bar.mjs": "./other-bar.mjs"
}
}
</script>`);
```

then the speculative fetches of `https://example.com/foo.mjs` and `https://example.com/bar.mjs` would be wasted, as the newly-written import map would be in effect instead of the one that was seen inline in the HTML.

## Alternatives considered

### The Node.js module resolution algorithm
Expand Down