Skip to content

Request: allow override to retrieve auto-imported script element #2243

Closed
@tmsns

Description

@tmsns

Description of Proposed Feature

Auto-import is a great feature we rely on to load our app inlined. However, in some cases, the retrieval of the current running script will not be correct, as the last script might not always be the running script. (https://github.com/systemjs/systemjs/blob/master/src/features/script-load.js#L40)

systemJSPrototype.register = function (deps, declare) {
  if (hasDocument && document.readyState === 'loading' && typeof deps !== 'string') {
    var scripts = document.getElementsByTagName('script');
    var lastScript = scripts[scripts.length - 1]; // not always the running script
    var url = lastScript && lastScript.src;
    if (url) {
      lastAutoImportUrl = url;

This proposal would extract the retrieval of the current script into a separate, overridable, hook:

systemJSPrototype.getCurrentScript = function () {
  var scripts = document.getElementsByTagName('script');
  return scripts[scripts.length - 1];
};

systemJSPrototype.register = function (deps, declare) {
  if (hasDocument && document.readyState === 'loading' && typeof deps !== 'string') {
    var lastScript = systemJSPrototype.getCurrentScript();
    var url = lastScript && lastScript.src;
    if (url) {
      lastAutoImportUrl = url;

In what way would you use it?

In the end state, when we drop support for IE 11 in our app, we would use document.currentScript in order to always have the correct current script:

systemJSPrototype.getCurrentScript = function () {
  return document.currentScript;
};

In the meantime, we would use the hook to return the correct script element dynamically. It would also allow us to prevent the import of incorrectly matched last scripts when dynamic loads have been used.

Activity

guybedford

guybedford commented on Sep 3, 2020

@guybedford
Member

Thanks for posting. If it's never not correct that's a bug though, do you have any replications you can share?

guybedford

guybedford commented on Sep 3, 2020

@guybedford
Member

Are you specifically seeing issues in IE11?

guybedford

guybedford commented on Sep 3, 2020

@guybedford
Member

A stack-based error approach may make sense for an IE11 specific fix...

guybedford

guybedford commented on Sep 3, 2020

@guybedford
Member

(ie using document.currentScript and falling back to a stack approach in IE11)

But the timing approach as currently should work I believe, and the whole nice thing about it was avoiding the need for the above.

tmsns

tmsns commented on Sep 4, 2020

@tmsns
Author

So, the issue happens both in IE11 and Chrome.
Our html page looks like this:

<body>
  ...
  <!-- 
    The bundle is loaded correctly and on time. In some cases, depending on the page a 
    dynamic load will be done using System.js as well.
   -->
  <script src="bundle.js"></script>
  ...
  <!-- 
    This external-vendor.js will add some additional, external scripts dynamically on the page, 
    and might prolong the time the page is in "loading" state. This depends per page, but also 
    per connection, ie. refreshing might take longer at one try, or be shorter on the other
  -->
  <script src="external-vendor.js"></script>
</body>

Using document.currentScript fixes the issue for non-IE browsers. :-) As IE has recently got a support end date for Microsoft 365 apps, it's probable IE support will be dropped somewhere next year as well. In the mean time, this proposal would allow to write some workaround code for IE.

It's also important to note that this is a more complex integration scenario. Most usage of SystemJS is probably done on an empty page. In that case, the current IE-proof solution (to get the current script element using the last script element) is working correctly. This is the reason why we proposed this as a hook to be implemented to allow users to change this behavior if their use case requires it. (without breaking other users's setup with more complex internal solutions)

It's also a bit difficult to have a correct replication, as the external-script.js is extending the loading state of the document because of extra request/responses (so network related), but also with extra code of course. I will try however, to still reproduce this. But I cannot guarantee it will work.. :-/

guybedford

guybedford commented on Sep 4, 2020

@guybedford
Member

There is a chance there could be a bug in what we previously implemented, so I would very much like to try to fix that first and foremost here. Thanks for trying to find a replication. If it's something you can only send privately we could arrange that as well.

Will await further feedback.

tmsns

tmsns commented on Sep 7, 2020

@tmsns
Author

I was finally able to reproduce it! πŸ˜ƒ
https://plnkr.co/edit/dMPuci6LJh0smbyu
image

Some remarks about the repro:

  • the document.write in index.html is used in order to fake a sync third party library, but I wanted to use a file in the same project for it (animals/chicken.js)
  • in order to micic the slower call I used flash.siwalik.in (a https variant of Slowwly)
  • the core of the issue lies in the retrieval of the dependencies of a dynamic import (eg. triton.js). These dependencies are retrieved with a url that is constructed using the wrong base url. That wrong base url is coming from document.getElementsByTagName('scripts') which retrieves the last script instead of the current script.
  • notice that nothing is wrong on the page. In most cases the wrong url will not resolve (if it does not exist). Users do get errors though.

Let me know if can help more!

guybedford

guybedford commented on Sep 11, 2020

@guybedford
Member

Thanks so much @tmsns for the very clear replication here. I've posted a fix in the PR at #2245.

guybedford

guybedford commented on Sep 13, 2020

@guybedford
Member

@tmsns this fix was released in 6.6.0 and 6.6.1, just let me know if you hit any further issues here or need to reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Request: allow override to retrieve auto-imported script element Β· Issue #2243 Β· systemjs/systemjs