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

Select module type by mime-type #2005

Closed
justinfagnani opened this issue Aug 26, 2019 · 14 comments
Closed

Select module type by mime-type #2005

justinfagnani opened this issue Aug 26, 2019 · 14 comments

Comments

@justinfagnani
Copy link

Matching the spec here will help head off potential errors that could be caused by misconfigured servers or server-side transforms that expect spec compliance.

Consider a server-side transform that UA-sniffs to detect JSON module support, and if the browser doesn't support them transforms foo.json to a JS module. The transform cannot rename the file, but it can set the mime-type.

I saw the explanation for selecting based on file-extension, but I wonder if inject script tags is really necessary. Could scripts not be executed by using fetch + a wrapped + eval? The wrapper can put the script in strict mode and ensure that top-level this is undefined, and even make top-level await work.

@joeldenning
Copy link
Collaborator

Could scripts not be executed by using fetch + a wrapped + eval?

Yes, that is how systemjs@0.21 worked. Here are the downsides that I am aware of:

  1. Sourcemaps aren't good in IE11 and maybe other browsers when you eval, from what I remember. cc @blittle who could elaborate.
  2. performance overhead of creating a javascript string for a large js module is lots of memory being allocated.
  3. maybe other performance overhead related to eval vs script? Maybe no compiler cache of the js file?

Would be happy to learn more about this - my comment isn't comprehensive.

@guybedford
Copy link
Member

One of the primary features of SystemJS is being CSP compatible.

@justinfagnani
Copy link
Author

Script tags require the 'unsafe-inline' script-src policy, don't they?

@dmail
Copy link
Contributor

dmail commented Aug 26, 2019

How using script makes it csp compatible while eval would not?

@guybedford
Copy link
Member

For example, here is GitHub's policy:

default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com; manifest-src 'self'; media-src 'none'; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com

which would support SystemJS but not eval.

@guybedford
Copy link
Member

guybedford commented Aug 26, 2019

Ideally we could apply a fetch, check the MIME type, and then inject a script, and if the same cache was used that would be ok (we'd avoid another network request). But I'm not sure there is a way to run fetch such that it fully cache-aligns with script tag injection? If there was that could be a path forward here.

Alternatively a separate mode / extra would be the way to go for this, and would be straightforward too.

Say a small format-mime extra or something like that, that then uses eval providing exact compatibility at the cost of CSP.

I'd be glad to support these paths further, and other suggestions welcome too.

@LarsDenBakker
Copy link
Contributor

LarsDenBakker commented Aug 26, 2019

We're migrating a large codebase from HTML Imports to es modules, and use a server-side transform to es module / systemjs. So we're serving .html files with mimetype text/javascript which we need running as javascript.

If I'm not mistaken, fetch is already use for file extensions other than .js? Then you could maybe special-case .js, and still use mime-type checking for the rest which uses fetch.

@guybedford
Copy link
Member

@LarsDenBakker so you mean we could fetch the module for CSS / Wasm / HTML extensions, and if it i application/javascript "opt-out" and then do an eval specifically in those cases?

Thus the CSP support is only lost for those specific files.

That seems like a really nice compromise actually!

@LarsDenBakker
Copy link
Contributor

Yes that's what I mean. The use case of transforming .js into something else is a lot less, I think.

@guybedford
Copy link
Member

@justinfagnani would @LarsDenBakker's suggestion as above work for your use cases?

@guybedford guybedford added this to the 6.0.0 milestone Aug 26, 2019
@justinfagnani
Copy link
Author

Possibly. I would love to see it fixed fully generally though.

Could you attach a script with a blob URL?

const scriptEl = document.createElement('script');
const blob = new Blob(sourceText, {type: 'application/javascript'});
const objectURL = URL.createObjectURL(blob);
scriptEl.src = objectURL;
// ...

@guybedford
Copy link
Member

@justinfagnani blob URLs will usually fail the script-src CSP directive, and rightly so as they are an execution injection.

The only general solution I can see is if we could guarantee that the fetch cache and script cache were shared, so that we could still inject a script after checking the MIME from the fetch call. But I believe Chrome explicitly has separate caching between scripts and fetch.

I'd be happy to include the compromise approach in v6 though, and it does sound like the best bet to me without new information here.

@guybedford
Copy link
Member

I've gone ahead and implemented this approach in #2006.

@guybedford
Copy link
Member

The eval fallback approach has been released in 6.0.0.

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

No branches or pull requests

5 participants