Tools: [build/polyserve] AMD transform/requirejs results in multiple requests for same import

Created on 24 Apr 2018  路  5Comments  路  Source: Polymer/tools

So, I think this is a client-side behavior of the requirejs wrapper we use that isn't correctly preventing multiple requests for the same file/url. Repro case is checking out https://github.com/Polymer/polymer/tree/3.x-tests and polymer serve --module-resolution node --npm and using Firefox to request http://127.0.0.1:8081/test/unit/utils/resolve-url.js

Have a look at the duplicates in the network tab:
screen shot 2018-04-23 at 3 23 14 pm

Critical Available Bug

Most helpful comment

This is highest on my list.

I believe the issue is that RequireJS does not (actually I think _cannot_) resolve relative module dependency URLs the way we assumed. RequireJS always resolves dependencies relative to the document base URL (or an override in a global config). So if /index.html loads "./foo/foo.js" which then loads "./bar.js", then the absolute URL that is fetched is /bar.js, not, as I naively assumed, /foo/bar.js. This is because /foo/foo.js does not know that it's within the /foo path component (incidentally, this is what import.meta.url solves).

The reason this manifests in the particular report filed here is that resolveurl.html imports "../../polymer-element.js" and "./sub/resolveurl-elements.js". resolveurl-elements.js then imports "../../../polymer-element.js". That's all correct with ES module path resolution. However, RequireJS will _not_ dedupe those URLs, because when those two paths are resolved relative to resolveurl.html, they are indeed different paths (one is a directory higher than the other). A request is then issued for both URLs, but in fact because our HTML file was only 2 path components deep, the browser ends up requesting the same absolute URL even for the ../../../ case (since that's what happens when you traverse above the root).

So, we're going to have to change the way we emit module IDs/dependency specifiers in the AMD transform. Investigating now.

All 5 comments

/cc @kevinpschaaf @aomarks

diff --git a/test/unit/sub/resolveurl-elements.js b/test/unit/sub/resolveurl-elements.js
index f8219309..cfb18916 100644
--- a/test/unit/sub/resolveurl-elements.js
+++ b/test/unit/sub/resolveurl-elements.js
@@ -12,7 +12,7 @@ import { html } from '../../../lib/utils/html-tag.js';
 import { PolymerElement } from '../../../polymer-element.js';
 import { DomModule } from '../../../lib/elements/dom-module.js';
 import { Polymer } from '../../../lib/legacy/polymer-fn.js';
-import { pathFromUrl } from '../utils/resolve-url.js';
+import { pathFromUrl } from '../../../lib/utils/resolve-url.js';
 const $_documentContainer = document.createElement('div');
 $_documentContainer.setAttribute('style', 'display: none;');
 const baseAssetPath = pathFromUrl(import.meta.url);

^ need to do this in order to run the test...

Probably related to #203, I have also noticed such kind of requests there (Firefox and Edge).

This is highest on my list.

I believe the issue is that RequireJS does not (actually I think _cannot_) resolve relative module dependency URLs the way we assumed. RequireJS always resolves dependencies relative to the document base URL (or an override in a global config). So if /index.html loads "./foo/foo.js" which then loads "./bar.js", then the absolute URL that is fetched is /bar.js, not, as I naively assumed, /foo/bar.js. This is because /foo/foo.js does not know that it's within the /foo path component (incidentally, this is what import.meta.url solves).

The reason this manifests in the particular report filed here is that resolveurl.html imports "../../polymer-element.js" and "./sub/resolveurl-elements.js". resolveurl-elements.js then imports "../../../polymer-element.js". That's all correct with ES module path resolution. However, RequireJS will _not_ dedupe those URLs, because when those two paths are resolved relative to resolveurl.html, they are indeed different paths (one is a directory higher than the other). A request is then issued for both URLs, but in fact because our HTML file was only 2 path components deep, the browser ends up requesting the same absolute URL even for the ../../../ case (since that's what happens when you traverse above the root).

So, we're going to have to change the way we emit module IDs/dependency specifiers in the AMD transform. Investigating now.

Actually my above description wasn't quite right. There is a problem with resolution of relative paths, but it is not as severe as I first thought. In general, RequireJS does resolve relative paths relative to the module ID that is requiring it, but it seems to have a bug in its normalization logic relating to relative paths reaching above the HTML base URL. Filed https://github.com/requirejs/requirejs/issues/1732 on RequireJS which describes in more detail.

Was this page helpful?
0 / 5 - 0 ratings