-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Auto import and core refactoring #2216
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/** | ||
* Auto-import <script src="system-module.js"></script> registrations | ||
* Allows the browser preloader to work directly with SystemJS optimization | ||
*/ | ||
import { systemJSPrototype, REGISTRY } from '../system-core.js'; | ||
import { hasDocument } from '../common.js'; | ||
|
||
var autoImports = {}; | ||
|
||
var systemRegister = systemJSPrototype.register; | ||
systemJSPrototype.register = function (deps, declare) { | ||
if (hasDocument && document.readyState === 'loading' && typeof deps !== 'string') { | ||
var scripts = document.getElementsByTagName('script'); | ||
var lastScript = scripts[scripts.length - 1]; | ||
if (lastScript && lastScript.src) { | ||
// Only import if not already in the registry. | ||
// This avoids re-importing an inline dynamic System.import dependency. | ||
// There is still a risk if a user dynamically injects a custom System.register script during DOM load that does an | ||
// anomymous registration that is able to execute before DOM load completion, and thus is incorrectly matched to the | ||
// last script when it wasn't causing a System.import of that last script, but this is deemed an acceptable edge case | ||
// since due to custom user registration injection. | ||
// Not using document.currentScript is done to ensure IE11 equivalence. | ||
if (!this[REGISTRY][lastScript.src]) { | ||
autoImports[lastScript.src] = [deps, declare]; | ||
// Auto import = immediately import the registration | ||
// It is up to the user to manage execution order for deep preloading. | ||
this.import(lastScript.src); | ||
} | ||
return; | ||
} | ||
} | ||
return systemRegister.call(this, deps, declare); | ||
}; | ||
|
||
var systemInstantiate = systemJSPrototype.instantiate; | ||
systemJSPrototype.instantiate = function (url) { | ||
var autoImport = autoImports[url]; | ||
if (autoImport) { | ||
delete autoImports[url]; | ||
return autoImport; | ||
} | ||
return systemInstantiate.apply(this, arguments); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* SystemJS browser attachments for script and import map processing | ||
*/ | ||
import { baseUrl, resolveAndComposeImportMap, hasDocument, IMPORT_MAP, resolveUrl } from '../common.js'; | ||
import { systemJSPrototype } from '../system-core.js'; | ||
import { errMsg } from '../err-msg.js'; | ||
|
||
var importMapPromise = Promise.resolve({ imports: {}, scopes: {} }); | ||
|
||
// Scripts are processed immediately, on the first System.import, and on DOMReady. | ||
// Import map scripts are processed only once (by being marked) and in order for each phase. | ||
// This is to avoid using DOM mutation observers in core, although that would be an alternative. | ||
var processFirst = hasDocument; | ||
systemJSPrototype.prepareImport = function () { | ||
if (processFirst) { | ||
processScripts(); | ||
processFirst = false; | ||
} | ||
var loader = this; | ||
return importMapPromise.then(function (importMap) { | ||
loader[IMPORT_MAP] = importMap; | ||
}); | ||
}; | ||
if (hasDocument) { | ||
processScripts(); | ||
window.addEventListener('DOMContentLoaded', processScripts); | ||
} | ||
|
||
function processScripts () { | ||
[].forEach.call(document.querySelectorAll('script'), function (script) { | ||
// TODO: deprecate systemjs-module in next major now that we have auto import | ||
if (script.type === 'systemjs-module') { | ||
if (!script.src) | ||
return; | ||
System.import(script.src.slice(0, 7) === 'import:' ? script.src.slice(7) : resolveUrl(script.src, baseUrl)); | ||
} | ||
else if (script.type === 'systemjs-importmap') { | ||
if (script.sp) // sp marker = systemjs processed | ||
return; | ||
script.sp = true; | ||
importMapPromise = importMapPromise.then(function (importMap) { | ||
if (script.src) | ||
return fetch(script.src).then(function (res) { | ||
return res.text(); | ||
}).then(function (text) { | ||
return extendImportMap(importMap, text, script.src); | ||
}); | ||
return extendImportMap(importMap, script.innerHTML, baseUrl); | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
function extendImportMap (importMap, newMapText, newMapUrl) { | ||
try { | ||
var newMap = JSON.parse(newMapText); | ||
} catch (err) { | ||
throw Error(process.env.SYSTEM_PRODUCTION ? errMsg(1) : errMsg(1, "systemjs-importmap contains invalid JSON")); | ||
} | ||
return resolveAndComposeImportMap(newMap, newMapUrl, importMap); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { BASE_URL, baseUrl, resolveImportMap, resolveIfNotPlainOrUrl, IMPORT_MAP } from '../common.js'; | ||
import { systemJSPrototype } from '../system-core.js'; | ||
import { errMsg } from '../err-msg.js'; | ||
|
||
systemJSPrototype.resolve = function (id, parentUrl) { | ||
parentUrl = parentUrl || !process.env.SYSTEM_BROWSER && this[BASE_URL] || baseUrl; | ||
return resolveImportMap(this[IMPORT_MAP], resolveIfNotPlainOrUrl(id, parentUrl) || id, parentUrl) || throwUnresolved(id, parentUrl); | ||
}; | ||
|
||
function throwUnresolved (id, parentUrl) { | ||
throw Error(errMsg(8, process.env.SYSTEM_PRODUCTION ? [id, parentUrl].join(', ') : "Unable to resolve bare specifier '" + id + (parentUrl ? "' from " + parentUrl : "'"))); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,4 +12,3 @@ if (hasSelf && typeof importScripts === 'function') | |
return loader.getRegister(); | ||
}); | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import './features/import-map.js'; | ||
import './features/resolve.js'; | ||
import './features/browser-scripts.js'; | ||
import './features/script-load.js'; | ||
import './features/auto-import.js'; | ||
import './features/worker-load.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
import './features/import-map.js'; | ||
import './features/resolve.js'; | ||
import './features/browser-scripts.js'; | ||
import './features/script-load.js'; | ||
import './features/auto-import.js'; | ||
import './features/worker-load.js'; | ||
import './extras/global.js'; | ||
import './extras/module-types.js'; | ||
import './features/registry.js'; | ||
import './features/registry.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
System.register([], function(_export) { | ||
return { | ||
execute: function () { | ||
_export('auto', 'import'); | ||
} | ||
}; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, when using the condition
document.readystate === 'loading'
, it is not guaranteed that the lastscript
of the page is indeed the one who calledregister()
. More specifically, this can happen when the first auto-imported script is calling a dynamic import (System.import()
) while there are still somescript
tags being parsed in the page (either statically or dynamically)I'll try to come up with a way to differentiate these dynamic imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh that makes sense. We should be able to specifically opt-out of SystemJS own-injected scripts from this mechanism somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this is very similar to the problem discussed below 🙈 , except that:
System.import
) during load, which will cause aSystem.register
later on ofcIn other words, it doesn't seem such an edge case. 😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh weird, maybe that code path isn't working for some reason? I didn't fully test it yet - but yes that logic should be doing the avoidance here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure your race conditions aren't just the expected ordering ones?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, in my setup I have only one auto-imported script. In that script, there is a dynamic import to load the main chunk of the page. When
System.register
of the chunk is being called, I can see it takes thesrc
of an unrelated script further down the page. So, in that sense, I don't expect any other ones. 😊There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok then it sounds like this top-out path is not working as it is supposed to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect the issue is that
lastScript
is being checked in that dynamic import script, and not matching its own script as it is dynamic.A timing-based fix with the registration system should be possible here... I will aim to take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, indeed. I don't think there is a full proof way in IE to distinguish
System.register
's being called in the dynamic-import way vs the auto import way, asdocument.currentScript
cannot exactly be faked.I see a couple of workarounds though, but they are never ideal:
document.readyState === 'loading'
to check a specific attribute of thelastScript
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use the existing mechanism which is based on the sync timing of the register callback itself to register the script to the right URL. Integrating this with this code path will involve some timing tricks though and likely requires moving all this logic into an async step with checks.