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

Handle inline scripts when systemjs itself is inline #2369

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

dmail
Copy link
Contributor

@dmail dmail commented Nov 2, 2021

Description

When systemjs is inlined in the HMTL file, it won't execute inline scripts

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf8" />
    <link rel="icon" href="data:," />
    <script>
      // Here goes systemjs/dist/s.js inlined
    </script>
  </head>
  <body>
    <script>
      System.register([], function () {
        "use strict"

        return {
          execute: function () {
            alert("executed") // -> not executed by systemjs
          },
        }
      })
    </script>
  </body>
</html>

This pull request should fix this use case, it is a follow up of #2357

@github-actions
Copy link

github-actions bot commented Nov 2, 2021

File size impact

Merging main into main will impact 2 files in 1 group.

browser (2/2)
File raw gzip brotli Event
dist/s.min.js +61 (7,661) +38 (3,030) +37 (2,749) modified
dist/system.min.js +61 (11,950) +36 (4,613) +31 (4,155) modified
Total size impact +122 (19,611) +74 (7,643) +68 (6,904)
node (0/1)

No impact on files in node group.

extras (0/8)

No impact on files in extras group.

Generated by file size impact during size-impact#1526193853

@dmail
Copy link
Contributor Author

dmail commented Nov 2, 2021

Sorry the commit is incorrect will push the right commit shortly

Done

@dmail
Copy link
Contributor Author

dmail commented Nov 9, 2021

The build failed but it seems unrelated, I think it would pass if restarted but I don't have the rights to restart the Travis build.

Copy link
Collaborator

@joeldenning joeldenning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good to me. Can you think of a way to add tests? Seems to be hard since the tests are all run in the same HTML file that loads systemjs via <script src> rather than inline.

The lastScript logic that's already present in systemjs doesn't seem to be the best approach, since multiple inline scripts would have the same lastAutoImportUrl logic in them. Using document.currentScript would be better, but isn't supported in IE11. I wonder if we could use document.scripts[document.scripts.length - 1] rather than the current approach? Got that idea from https://makandracards.com/makandra/497684-emulating-document-currentscript-in-old-browsers. If we can switch to that, I think it would be better.

}
else {
inlineScriptCount++
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
inlineScriptCount++
inlineScriptCount++;

systemJSPrototype.register = function (deps, declare) {
if (hasDocument && document.readyState === 'loading' && typeof deps !== 'string') {
var scripts = document.querySelectorAll('script[src]');
var lastScript = scripts[scripts.length - 1];
var lastAutoImportUrl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you move this inside of register? To avoid race conditions with multiple scripts being executed in the same tick of the event loop? I didn't think it would be possible for two inline scripts to execute before a setTimeout tick occurs.

systemJSPrototype.register = function (deps, declare) {
if (hasDocument && document.readyState === 'loading' && typeof deps !== 'string') {
var scripts = document.querySelectorAll('script[src]');
var lastScript = scripts[scripts.length - 1];
var lastAutoImportUrl;
lastAutoImportDeps = deps;
if (lastScript) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the ideal implementation would use the src if it's present and the __inline_script__ if it's not. Something like this:

Suggested change
if (lastScript) {
if (lastScript.src) {

@dmail
Copy link
Contributor Author

dmail commented Nov 15, 2021

Thanks for the review, for now I don't have time to handle your feedback but I'll come back to this PR when possible ;)

@dmail
Copy link
Contributor Author

dmail commented Dec 1, 2021

I have just pushed a commit to address the review.

About how to test this scenario where systemjs itself is inlined:
I don't know how I could do it properly with the test tools you have in place.
However if I can introduce playwright I know how I could do it:

  • start a static file server injecting systemjs inline into html
  • launch a chrome headless using playwright
  • write an html page reproducing what we want to test (systemjs inline + an inline System.register)
  • make chrome navigate to this html page and assert the file is properly executed

But I would like your approval about this strategy before writing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants