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

Exporting a loader with a name results in full document reloads on use in fetcher #7957

Closed
1 task done
ZipBrandon opened this issue Nov 9, 2023 · 2 comments
Closed
1 task done

Comments

@ZipBrandon
Copy link

ZipBrandon commented Nov 9, 2023

I have some loaders that I will also export a named version of them for use in other loaders. I have noticed that I have peculiar results with a vite build as of 2.2.0.

What version of Remix are you using?

0.0.0-nightly-8543efe-20231108

Are all your remix dependencies & dev-dependencies using the same version?

  • Yes

Steps to Reproduce

  1. clone https://github.com/ZipBrandon/remix-export-loader-fullreload and start repo
  2. http://localhost:5173/testing
  3. click fetch from api.helloWorld and it behaves as expected
  4. click fetch from api.helloWorldNamed and it causes full reload

Expected Behavior

Fetch and return data asynchronously

Actual Behavior

Causing a full reload.

import type { LoaderFunctionArgs } from "@remix-run/node";
import { defer } from "@remix-run/node";


export const namedLoader = loader; // <-- this makes the fetcher fail
export async function loader  (args: LoaderFunctionArgs)  {
  const { request, context, params } = args;

  return defer({
    data: "hello world named",
  });
};
@hi-ogawa
Copy link
Contributor

hi-ogawa commented Nov 10, 2023

Thanks for the reproduction.
This is probably due to current limitation of "remove server exports" done by remix.
I didn't check this deep at that time but #7864 (comment) was also having the same issue probably.

When I look at the network devtool, I see useFetcher triggers two requests:

The 2nd one is to load client route module, but its content looks like below. export const loader = ... is eliminated but namedLoader was left as is, which would obviously throw:

$ curl 'http://localhost:5173/app/routes/api.helloWorldNamed/route.ts?import'
export const namedLoader = loader;
;
//# sourceMappingURL=...

I cannot think of a general solution, but at least for this specific reproduction, one workaround could be to wrap loader reference ike below so that it won't throw during load time:

export const namedLoader = (args) => loader(args);

(EDIT: Another "fix" would be to move out exports/imports between route files into non-route utility file, which is also currently required for HMR to work as well https://remix.run/docs/en/main/discussion/hot-module-replacement#supported-exports)

The full reload mechanism is coming from here:

try {
let routeModule = await import(/* webpackIgnore: true */ route.module);
routeModulesCache[route.id] = routeModule;
return routeModule;
} catch (error: unknown) {
// User got caught in the middle of a deploy and the CDN no longer has the
// asset we're trying to import! Reload from the server and the user
// (should) get the new manifest--unless the developer purged the static
// assets, the manifest path, but not the documents 😬
window.location.reload();

Currently there's no logging and it's quite puzzling at first. So, maybe it might make sense to add console.error to help debugging (at least while remix/vite is unstable). If I patch it, the error log looks like this:

loader is not defined
at app/routes/api.helloWorldNamed/route.ts?import:1:28

@pcattori
Copy link
Contributor

With Vite, Remix is forced to become stricter about allowed route exports. Exporting user-defined names like namedLoader is no longer valid.

For rationale see #8171 and https://remix.run/docs/en/dev/future/vite#strict-route-exports

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

4 participants