-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Problem
When consuming webpack bundles with SystemJS, it is necessary to dynamically set the webpack public path, so that webpack code splits know the base url to find other assets from. This cannot be set at build time, since the webpack bundle could be hosted on a variety of domains that aren't known at build time.
The System.resolve() api is great for giving you the url to use for your webpack public path. However, it is asynchronous when using system.js and import maps, which makes it impossible to set the public path before webpack starts processing its imports and code splits). This means that webpack will attempt to download code splits at the wrong url.
Repo that reproduces problem
See https://github.com/joeldenning/systemjs-webpack-public-path for a repo that clearly shows this problem. Of particular note is the set-public-path.js file.
Related
See "Use Case 1" in #1918 (comment). Also see webpack/webpack#8833 (comment) where it was decided that to start out webpack would continue downloading code splits via webpackJsonp instead of using SystemJS module.import().
Workaround
The url for the webpack public path can be synchronously known/calculated by monkey patching System.resolve and storing the resolved urls in a way you can access them synchronously:
const moduleMap = {};
window.getPublicPath = function(name) {
const path = moduleMap[name];
if (path) {
return path.slice(0, path.lastIndexOf("/") + 1);
} else {
throw Error("Cannot find public path for " + name);
}
};
const originalResolve = window.System.resolve;
window.System.resolve = function(name) {
return originalResolve.apply(this, arguments).then(function(resolved) {
moduleMap[name] = resolved;
return resolved;
});
};Proposed solutions
Expose resolved urls via new System API
Create a resolveSync API that returns null if resolution hasn't happened or completed yet, but returns the string path if it has.
const fullUrl = System.resolveSync('main')
__webpack_public_path__ = fullUrl.slice(0, fullUrl.lastIndexOf('/') + 1)Expose read-only import map synchronously
const fullUrl = System.getImportMap().imports.main
__webpack_public_path__ = fullUrl.slice(0, fullUrl.lastIndexOf('/') + 1)Implement and use _context.meta.url
See _context.meta.url. This one would require the most work I think, since (it appears that) SystemJS does not currently provide _context in v3.1.6. Also, it would require a change to webpack that would make it possible for a webpack user to access _context.meta.url -- right now that's not really possible because webpack doesn't even know that _context exists.
System.register([], function(_export, _context) {
const fullUrl = _context.meta.url
__webpack_public_path__ = fullUrl.slice(0, fullUrl.lastIndexOf('/') + 1)
})