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
Brainstorm -- synchronously setting public path for webpack bundles. #1939
Comments
Both It's been awhile since I read through the import-map proposal, but I am under the impression that the import-map spec doesn't really have a clean way of figuring this out either, right? If that's true, it may be worth it to also open an issue there and start a conversation about it? |
Implement and use _context.meta.urlThis seems to me a great route forward if it can work for you? SystemJS definitely provides Ideally you could just write: __webpack_public_path__ = import.meta.url.slice(0, import.meta.url.lastIndexOf('/') + 1); in your own code before it goes into webpack, and have Webpack turn that into a This would also provide better compatibility with the System format in Webpack itself. Does that sound doable? |
This path is the hardest one -- right now webpack does not support I think one of the tricky things to decide would be if Going down this path would also mean that people having webpack compile to AMD/UMD would not be able to get the resolved url synchronously. They would have to switch to System format. |
In AMD/UMD it's available via |
Sorry it's |
Ah I didn't know about If this is the best option, I can start looking into what it would take to PR webpack to support My guess is it would take at least a few months before it were in a webpack release, but I can try it 😄 Could you comment on the other proposed solutions, and what you see as pros/cons of them? |
Main con is just adding another System api that is niche? |
I agree So having it correspond to the output doesn't necessarily make sense you're right. And then tracking that into Webpack isn't a straightforward feature, yes. It seems annoying though as the context is all there... just not accessible! Could you just make the As for the other proposals, I don't want to expose the import map as that would need to be a clone to avoid mutations, which seems expensive, and also inspection of the import maps is not currently a feature of import maps, so exposing it in SystemJS shouldn't be done lightly. For a syncResolve function, we could have like a core syncResolve which the asyncResolve wraps. I guess something around that could be worked out. But I'm just so weary of what happens when they get out of sync which seems like it would happen so easily? Especially when we introduce dynamic import map loading. Having a function that bails with an error seems non-ideal. Would top-level await help your use case? Because the chunk could be deferred on async code? Perhaps implementing top-level await in webpack is an option too!? (System format supports it via async declaration function). |
hmm maybe, although I don't think so. With the following example, I think that (within webpack) await System.resolve('my-entry-module')
.then(url => __webpack_public__path = url.slice(0, url.lastIndexOf('/') + 1)
import './a'
That's is a pretty good idea -- that PR to webpack would be a lot easier to implement and probably a lot easier for the webpack team to accept. I like that as the best option. I'll try out a webpack PR for it. |
I just created a PR in webpack for this ^ It turned out to be a one-liner that I hope is easy for the maintainers to accept. |
@guybedford after more thought, I think we should revisit this problem again. I think the webpack PR is a good one to get in there. However, for people on webpack@<4.30 or for those who simply do not know about My other two proposed solutions are |
@joeldenning I believe the intention will be to expose individual import maps as the |
Yeah an |
Here's my workaround for now. Pretty nasty, but works. <!-- in your index.html file, before you do any System.import() calls -->
<script>
(function() {
var originalResolve = System.resolve
var moduleMap = {}
System.resolve = function(name) {
return originalResolve.apply(this, arguments).then(resolved => {
moduleMap[name] = resolved;
return resolved;
});
}
window.getModuleUrl = function(name) {
if (moduleMap[name]) {
return moduleMap[name];
} else {
throw Error(`Could not find url for module '${name}'`)
}
}
}()
</script> // At the very very top of your webpack entry file
import './set-public-path'; // The set-public-path.js file
const fullUrl = window.getModuleUrl('nameOfModuleInImporMap')
__webpack_public_path__ = fullUrl.slice(0, fullUrl.lastIndexOf('/') + 1) |
@joeldenning I really like us moving this approach over to #1985 since that also aligns with the import maps spec and how dynamic import map injection might work too. Would you be happy to close this to track the feature there? |
Yeah let's close it and use #1985 to track. For any future readers of this thread, the proposed change will make it so you can call const systemjsUrl = System.resolve('my-module-name')
__webpack_public_path__ = systemjsUrl.slice(0, systemjsUrl.lastIndexOf('/') + 1) |
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:
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.Expose read-only import map synchronously
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.The text was updated successfully, but these errors were encountered: