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

breaking: remove deprecated use:enhance callback values #11282

Merged
merged 11 commits into from
Dec 13, 2023
5 changes: 5 additions & 0 deletions .changeset/chilled-fireants-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': major
---

breaking: remove deprecated `use:enhance` callback values
5 changes: 5 additions & 0 deletions .changeset/mean-moose-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': major
---

breaking: error if form without multipart/form-data enctype contains a file input
10 changes: 10 additions & 0 deletions documentation/docs/60-appendix/30-migrating-to-sveltekit-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ As such, SvelteKit 2 replaces `resolvePath` with a (slightly better named) funct

`svelte-migrate` will do the method replacement for you, though if you later prepend the result with `base`, you need to remove that yourself.

## `form` and `data` have been removed from `use:enhance` callbacks

If you provide a callback to [`use:enhance`](/docs/form-actions#progressive-enhancement-use-enhance), it will be called with an object containing various useful properties.

In SvelteKit 1, those properties included `form` and `data`. These were deprecated some time ago in favour of `formElement` and `formData`, and have been removed altogether in SvelteKit 2.

## Forms containing file inputs must use `multipart/form-data`

If a form contains an `<input type="file">` but does not have an `enctype="multipart/form-data"` attribute, non-JS submissions will omit the file. SvelteKit 2 will throw an error if it encounters a form like this during a `use:enhance` submission to ensure that your forms work correctly when JavaScript is not present.

## Updated dependency requirements

SvelteKit requires Node `18.13` or higher, Vite `^5.0`, vite-plugin-svelte `^3.0`, TypeScript `^5.0` and Svelte version 4 or higher. `svelte-migrate` will do the `package.json` bumps for you.
Expand Down
20 changes: 0 additions & 20 deletions packages/kit/src/exports/public.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1247,35 +1247,15 @@ export type SubmitFunction<
Failure extends Record<string, unknown> | undefined = Record<string, any>
> = (input: {
action: URL;
/**
* use `formData` instead of `data`
* @deprecated
*/
data: FormData;
formData: FormData;
/**
* use `formElement` instead of `form`
* @deprecated
*/
form: HTMLFormElement;
formElement: HTMLFormElement;
controller: AbortController;
submitter: HTMLElement | null;
cancel(): void;
}) => MaybePromise<
| void
| ((opts: {
/**
* use `formData` instead of `data`
* @deprecated
*/
data: FormData;
formData: FormData;
/**
* use `formElement` instead of `form`
* @deprecated
*/
form: HTMLFormElement;
formElement: HTMLFormElement;
action: URL;
result: ActionResult<Success, Failure>;
Expand Down
37 changes: 2 additions & 35 deletions packages/kit/src/runtime/app/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,6 @@ export function deserialize(result) {
return parsed;
}

/**
* @param {string} old_name
* @param {string} new_name
* @param {string} call_location
* @returns void
*/
function warn_on_access(old_name, new_name, call_location) {
if (!DEV) return;
// TODO 2.0: Remove this code
console.warn(
`\`${old_name}\` has been deprecated in favor of \`${new_name}\`. \`${old_name}\` will be removed in a future version. (Called from ${call_location})`
);
}

/**
* Shallow clone an element, so that we can access e.g. `form.action` without worrying
* that someone has added an `<input name="action">` (https://github.com/sveltejs/kit/issues/7593)
Expand Down Expand Up @@ -157,11 +143,9 @@ export function enhance(form_element, submit = () => {}) {
if (DEV && clone(form_element).enctype !== 'multipart/form-data') {
for (const value of form_data.values()) {
if (value instanceof File) {
// TODO 2.0: Upgrade to `throw Error`
console.warn(
'Your form contains <input type="file"> fields, but is missing the `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819. This will be upgraded to an error in v2.0.'
throw new Error(
'Your form contains <input type="file"> fields, but is missing the necessary `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819.'
);
break;
}
}
}
Expand All @@ -176,21 +160,12 @@ export function enhance(form_element, submit = () => {}) {
let cancelled = false;
const cancel = () => (cancelled = true);

// TODO 2.0: Remove `data` and `form`
const callback =
(await submit({
action,
cancel,
controller,
get data() {
warn_on_access('data', 'formData', 'use:enhance submit function');
return form_data;
},
formData: form_data,
get form() {
warn_on_access('form', 'formElement', 'use:enhance submit function');
return form_element;
},
formElement: form_element,
submitter: event.submitter
})) ?? fallback_callback;
Expand Down Expand Up @@ -220,15 +195,7 @@ export function enhance(form_element, submit = () => {}) {

callback({
action,
get data() {
warn_on_access('data', 'formData', 'callback returned from use:enhance submit function');
return form_data;
},
formData: form_data,
get form() {
warn_on_access('form', 'formElement', 'callback returned from use:enhance submit function');
return form_element;
},
formElement: form_element,
update: (opts) =>
fallback_callback({
Expand Down

This file was deleted.

This file was deleted.

58 changes: 5 additions & 53 deletions packages/kit/test/apps/basics/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -896,69 +896,21 @@ test.describe('Actions', () => {
expect(preSubmitContent).not.toBe(postSubmitContent);
});

test('Submitting a form with a file input but no enctype="multipart/form-data" logs a warning', async ({
test('Submitting a form with a file input but no enctype="multipart/form-data" throws an error', async ({
page,
javaScriptEnabled
}) => {
test.skip(!javaScriptEnabled, 'Skip when JavaScript is disabled');
test.skip(!process.env.DEV, 'Skip when not in dev mode');
await page.goto('/actions/file-without-enctype');
const log_promise = page.waitForEvent('console');
const error_promise = page.waitForEvent('pageerror');
await page.click('button');
const log = await log_promise;
expect(log.text()).toBe(
'Your form contains <input type="file"> fields, but is missing the `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819. This will be upgraded to an error in v2.0.'
const error = await error_promise;
expect(error.message).toBe(
'Your form contains <input type="file"> fields, but is missing the necessary `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819.'
);
});

test('Accessing v2 deprecated properties results in a warning log', async ({
page,
javaScriptEnabled
}) => {
test.skip(!javaScriptEnabled, 'skip when js is disabled');
test.skip(!process.env.DEV, 'skip when not in dev mode');
await page.goto('/actions/enhance/old-property-access');

for (const { id, old_name, new_name, call_location } of [
{
id: 'access-form-in-submit',
old_name: 'form',
new_name: 'formElement',
call_location: 'use:enhance submit function'
},
{
id: 'access-form-in-callback',
old_name: 'form',
new_name: 'formElement',
call_location: 'callback returned from use:enhance submit function'
},
{
id: 'access-data-in-submit',
old_name: 'data',
new_name: 'formData',
call_location: 'use:enhance submit function'
},
{
id: 'access-data-in-callback',
old_name: 'data',
new_name: 'formData',
call_location: 'callback returned from use:enhance submit function'
}
]) {
await test.step(id, async () => {
const log_promise = page.waitForEvent('console');
const button = page.locator(`#${id}`);
await button.click();
await expect(button).toHaveAttribute('data-processed', 'true');
const log = await log_promise;
expect(log.text()).toBe(
`\`${old_name}\` has been deprecated in favor of \`${new_name}\`. \`${old_name}\` will be removed in a future version. (Called from ${call_location})`
);
expect(log.type()).toBe('warning');
});
}
});

test('Error props are returned', async ({ page, javaScriptEnabled }) => {
await page.goto('/actions/form-errors');
await page.click('button');
Expand Down
20 changes: 0 additions & 20 deletions packages/kit/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1229,35 +1229,15 @@ declare module '@sveltejs/kit' {
Failure extends Record<string, unknown> | undefined = Record<string, any>
> = (input: {
action: URL;
/**
* use `formData` instead of `data`
* @deprecated
*/
data: FormData;
formData: FormData;
/**
* use `formElement` instead of `form`
* @deprecated
*/
form: HTMLFormElement;
formElement: HTMLFormElement;
controller: AbortController;
submitter: HTMLElement | null;
cancel(): void;
}) => MaybePromise<
| void
| ((opts: {
/**
* use `formData` instead of `data`
* @deprecated
*/
data: FormData;
formData: FormData;
/**
* use `formElement` instead of `form`
* @deprecated
*/
form: HTMLFormElement;
formElement: HTMLFormElement;
action: URL;
result: ActionResult<Success, Failure>;
Expand Down
7 changes: 7 additions & 0 deletions sites/kit.svelte.dev/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
<meta name="twitter:image" content="/images/twitter-thumbnail.jpg" />
<meta name="og:image" content="/images/twitter-thumbnail.jpg" />

<link
rel="search"
type="application/opensearchdescription+xml"
href="/opensearch.xml"
title="SvelteKit"
/>

<!-- add inline style and blocking script to prevent content flash/jump -->
<style>
.ts-version {
Expand Down
10 changes: 10 additions & 0 deletions sites/kit.svelte.dev/static/opensearch.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<ShortName>SvelteKit</ShortName>
<Description>Search SvelteKit</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="128" height="128" type="image/png">https://kit.svelte.dev/favicon.png</Image>
<Url type="text/html" method="get"
template="https://kit.svelte.dev/search?q={searchTerms}" />
<moz:SearchForm>https://kit.svelte.dev/search</moz:SearchForm>
</OpenSearchDescription>