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

URLSearchParams polyfill breaks fetch #674

Closed
huww98 opened this issue Oct 21, 2019 · 12 comments
Closed

URLSearchParams polyfill breaks fetch #674

huww98 opened this issue Oct 21, 2019 · 12 comments
Labels

Comments

@huww98
Copy link
Contributor

huww98 commented Oct 21, 2019

I upgraded to @vue/cli@4, which use core-js@3. And my fetch breaks on WeChat (based on chrome 66, as shown in UA).

I'm using it like this:

const res = await fetch('/api/xxx', {
    method: 'POST',
    body: new URLSearchParams({ a: 'b' }),
})

Before upgrade, this will add header 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8', and use 'a=b' as body. Now it just send a blank body and does not add header.

I think it is because the URLSearchParams polyfill. fetch can no longer recognize the polyfill as an URLSearchParams. Manually adding header and converting body to string do work, however, is it possible to fix this? I think this can be hard, since we don't know how Chrome determine whether an object is an URLSearchParams

@zloirock
Copy link
Owner

zloirock commented Oct 21, 2019

How do you include core-js? What happens if you call body: new URLSearchParams({ a: 'b' }).toString() directly? If you use another initializer like body: new URLSearchParams('a=b')?

@huww98
Copy link
Contributor Author

huww98 commented Oct 21, 2019

I'm working on a project created by @vue/cli. To my understanding, this project use babel with @vue/cli-plugin-babel/preset, which just require @vue/babel-preset-app, which should use @babel/preset-env with useBuiltIns: 'usage' and corejs: 3

Use this works:

const res = await fetch('/api/xxx', {
    method: 'POST',
    body: (new URLSearchParams({ a: 'b' })).toString(),
    header: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
    }
})

But as in https://developer.mozilla.org/en-US/docs/Web/API/Request/Request, body should work directly with URLSearchParams

URLSearchParams itself works fine, it just does not work with fetch.

@zloirock
Copy link
Owner

Ok, I see the problem. Seems required one more wrapper for fetch...

@zloirock zloirock added the bug label Oct 21, 2019
@zloirock
Copy link
Owner

I can't understand, why do spec writers love to over complicate simple things... KISS

@zloirock
Copy link
Owner

zloirock commented Oct 23, 2019

@huww98 could you check it with the version from the master branch?

@huww98
Copy link
Contributor Author

huww98 commented Oct 24, 2019

Thanks for your work.

How can I test an unreleased version? core-js is not a direct dependency of my project. I've tried to clone this repo and do npm install /path/to/core-js/packages/core-js. My project builds successfully, however, I get error from browser:

Cannot assign to read only property 'exports' of object '#<Object>'
image

I have no idea how to resolve this.

@huww98
Copy link
Contributor Author

huww98 commented Oct 24, 2019

OK, I resolved this by delete the symbolic link created by npm and copy /path/to/core-js/packages/core-js to my node_modules. Then remove cache and rebuild.

I can confirm the version from master branch fixes my problem. thanks.

@vkurko
Copy link

vkurko commented Jan 22, 2021

Ok, I see the problem. Seems required one more wrapper for fetch...

Sorry, but how is this supposed to work with @babel/plugin-transform-runtime? In pure version the global fetch doesn't get wrapped and it looks like babel runtime doesn't transform the fetch calls into the wrapped version.

@zloirock
Copy link
Owner

zloirock commented Jan 22, 2021

@vkurko it will not work with the current version of @babel/plugin-transform-runtime. Maybe it will be added in the next iterations of development. You could manually wrap fetch result to Promise.resolve.

@vkurko
Copy link

vkurko commented Jan 23, 2021

@zloirock thanks for your answer. But the issue is not related to Promise. It is related to URLSearchParams not setting correct Content-type header when used as body in fetch. You added a wrapper for fetch to fix this issue but it has no effect in pure version.

@zloirock
Copy link
Owner

zloirock commented Jan 23, 2021

@vkurko sorry, I mixed up the contexts. Here the same situation, just change Promise.resolve() from the answer to String() on URLSearchParams-)

We can't make @babel/plugin-transform-runtime work with this case right now with the current approaches. However, I will take note of this as something that should be fixed in the next iterations, thanks.

@vkurko
Copy link

vkurko commented Jan 23, 2021

@zloirock Unfortunately wrapping URLSearchParams with String has no effect. So the following code (after being transformed with babel runtime) will produce HTTP request in Safari 13.1.2 with Content-type set to text/plain;charset=UTF-8 instead of application/x-www-form-urlencoded;charset=UTF-8:

fetch(url, {
    method: 'POST',
    body: String(new URLSearchParams({ a: 'b' }))
})

So if the only way of sending a correct request is to set headers explicitly then the wrapper that is added by core-js-pure for the native fetch function seems to be useless (it actually does not touch the global native fetch) and it would be great if the code of this wrapper did not present in the resulting code especially for libraries using babel runtime and trying to keep their size as small as possible.

Thanks

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

No branches or pull requests

3 participants