jq79 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jq79",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Mini reactive component library: single-file components, Svelte-style setup scripts, fine-grained proxy reactivity. Single-file build, zero dependencies.",
5
5
  "keywords": [
6
6
  "reactive",
package/src/jq79.ts CHANGED
@@ -1681,6 +1681,45 @@ const componentPartsFrom = (elements: Element[], hashSource: string): ComponentP
1681
1681
  const importResource = (url: string): Promise<any> =>
1682
1682
  /\.html?([?#]|$)/.test(url) ? fetchComponent(url) : import(url)
1683
1683
 
1684
+ // a relative specifier means "next to the file that wrote it", so it is
1685
+ // resolved against the component's own URL before importResource sees it -
1686
+ // neither of that function's two branches would otherwise land there. The
1687
+ // native import() inside it resolves against *this module* (dist/jq79.js), and
1688
+ // fetch() against the document; a component in a subdirectory gets a 404 from
1689
+ // the first and the page's directory from the second.
1690
+ //
1691
+ // What comes back is always a fully absolute URL, and that is the load-bearing
1692
+ // part rather than a detail of formatting. A *path* would be resolved by that
1693
+ // same native import() against the library module's ORIGIN - and the library
1694
+ // is the one file on the page most likely to come from somewhere else:
1695
+ //
1696
+ // page http://localhost:8024/craft/app.html
1697
+ // jq79 https://jgermade.github.io/jq79/jq79.js
1698
+ // "/craft/services/x.js" -> https://jgermade.github.io/craft/services/x.js
1699
+ //
1700
+ // which is a CORS error naming a host the app never mentioned. Only an
1701
+ // absolute URL means the same thing to both branches.
1702
+ //
1703
+ // For the same reason a *root-absolute* specifier is resolved too, not passed
1704
+ // through: `/x.js` means the page's root to whoever wrote it, and the page is
1705
+ // the only base under which the two branches agree. Bare specifiers ("lodash")
1706
+ // are the exception that stays untouched - they belong to the import map or
1707
+ // the bundler, and resolving one would quietly turn it into a path.
1708
+ //
1709
+ // The base is absolutized first, the way hotKey does and for the same reason:
1710
+ // the filename may itself be relative ("./card.html", from an import() in a
1711
+ // parent), and a relative URL cannot be a base
1712
+ const RESOLVABLE_SPECIFIER_RE = /^(?:\.\.?\/|\/|[a-z][a-z0-9+.-]*:)/i
1713
+
1714
+ const resolveSpecifier = (spec: string, filename: string | undefined): string => {
1715
+ if (!RESOLVABLE_SPECIFIER_RE.test(spec)) return spec
1716
+ try {
1717
+ return new URL(spec, new URL(filename ?? "", document.baseURI)).href
1718
+ } catch {
1719
+ return spec
1720
+ }
1721
+ }
1722
+
1684
1723
  // ---------------------------------------------------------------------------
1685
1724
  // naming scripts for devtools
1686
1725
  //
@@ -2353,10 +2392,15 @@ export class Component79 {
2353
2392
 
2354
2393
  // import() calls whose specifier was pre-resolved by a bundler (the
2355
2394
  // modules map) get the bundled module; everything else falls back to the
2356
- // runtime importResource (fetch for .html, native import otherwise)
2395
+ // runtime importResource (fetch for .html, native import otherwise),
2396
+ // relative to this component's file. The map is keyed by the literal
2397
+ // specifier the script wrote, so it is consulted *before* resolution -
2398
+ // what the bundler hoisted and what the source says are the same string
2357
2399
  const modules = this.modules
2358
2400
  const $import = (url: string): Promise<any> =>
2359
- modules && url in modules ? Promise.resolve(modules[url]) : importResource(url)
2401
+ modules && url in modules
2402
+ ? Promise.resolve(modules[url])
2403
+ : importResource(resolveSpecifier(url, this.filename))
2360
2404
 
2361
2405
  // the writeback half of :model, from the child's side: one argument is the
2362
2406
  // value for the default model (the bare :model), two are a name and a