Hi,
I migrated a larger project from Remix V1 to V2. I did a step by step refactoring.
When testing the app I received the following error message when I tried to send a remix form. It didn’t matter whether I used POST or GET.
» Warning: Missing form submission function handler
Request from ::1: POST /?index=&_data=routes%2F_index
Response with status 404 in 2 ms.
» Warning: Missing form submission function handler
Request from ::1: POST /index.html?index=&_data=routes%2F_index
Response with status 404 in 1 ms.
» Warning: Missing form submission function handler
Request from ::1: POST /index.htm?index=&_data=routes%2F_index
Response with status 404 in 0 ms.
After a long time troubleshooting my source code, I created a simple Hello World page and tested it. It turns out that it must be the Netlify CLI because the test app worked with a Remix template, but produced the error shown with the Netlify template. I carried out many different tests until I came up with the idea of testing the test page in the classic remix setup. I then notice that it runs clean there.
Here are my configurations and the index route.
netlify.toml
[build]
command = "npm run build"
publish = "public"
[dev]
command = "npm run dev"
targetPort = 3000
# Set immutable caching for static files, because they have fingerprinted filenames
[[headers]]
for = "/build/*"
[headers.values]
"Cache-Control" = "public, max-age=31560000, immutable"
remix.config.js
import { config } from "@netlify/remix-adapter";
/** @type {import('@remix-run/dev').AppConfig} */
export default {
...(process.env.NODE_ENV === "production" ? config : undefined),
// This works out of the box with the Netlify adapter, but you can
// add your own custom config here if you want to.
//
// See https://remix.run/file-conventions/remix-config
};
package.json
{
"name": "",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "netlify serve",
"typecheck": "tsc -b"
},
"dependencies": {
"@netlify/functions": "^2.0.0",
"@netlify/remix-adapter": "^2.0.0",
"@remix-run/node": "^2.4.1",
"@remix-run/react": "^2.4.1",
"cross-env": "^7.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^2.4.1",
"@remix-run/eslint-config": "^2.4.1",
"@remix-run/serve": "^2.4.1",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"autoprefixer": "^10.4.16",
"eslint": "^8.27.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.2.2"
},
"engines": {
"node": ">=18"
}
}
_index.tsx
import { json } from "@remix-run/node";
import {
Form,
useActionData,
} from "@remix-run/react";
import type { ActionFunctionArgs } from "@remix-run/node";
export function headers({
loaderHeaders,
parentHeaders,
}: {
loaderHeaders: Headers;
parentHeaders: Headers;
}) {
console.log(
"This is an example of how to set caching headers for a route, feel free to change the value of 60 seconds or remove the header"
);
return {
// This is an example of how to set caching headers for a route
// For more info on headers in Remix, see: https://remix.run/docs/en/v1/route/headers
"Cache-Control": "public, max-age=60, s-maxage=60",
};
}
export const action = async ({
params,
request,
}: ActionFunctionArgs) => {
const formData = await request.formData();
return json("works");
};
export default function Index() {
const actionResult = useActionData<typeof action>();
console.log(actionResult);
return (
<main style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1 className="text-3xl font-bold">
Hello world!
</h1>
<ul>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/blog"
rel="noreferrer noopener"
>
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/jokes"
rel="noreferrer noopener"
>
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/docs"
rel="noreferrer noopener"
>
Remix Docs
</a>
</li>
</ul>
<div>
<Form method="post">
<button name="_action" value="test" type="submit">Do it</button>
</Form>
</div>
</main>
);
}
As I said, I can run this exact page and form with a Remix template without errors. If I copy the index route into the Netlify environment, I always get the same error, even though the submission handler is obviously there.
What am I missing here? Tomorrow I have to present my customer with a working version on my Netlify instance. This is not possible with this error.
I’m scared shitless because I can’t find the solution. Btw my actual app also runs without any problems in the classic remix setup.
I hope you can help me here.
Best regards,
Enriko