laravel/precognition

Module not found when build SSR with laravel inertia react

hendivalon opened this issue · 9 comments

Laravel Precognition Plugin Version

0.3.2

Laravel Version

10.14.1

Plugin

React w/ Inertia

Description

No issue using client side. But in SSR, I found this problem when using the package.
I just install fresh laravel with inertia-react as test project then install the precognation

See below :

Inertia SSR server started.
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/hendi/Sites/testing/node_modules/laravel-precognition/dist/client' imported from /Users/hendi/Sites/testing/node_modules/laravel-precognition/dist/index.js
    at new NodeError (node:internal/errors:399:5)
    at finalizeResolution (node:internal/modules/esm/resolve:326:11)
    at moduleResolve (node:internal/modules/esm/resolve:945:10)
    at defaultResolve (node:internal/modules/esm/resolve:1153:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)
    at link (node:internal/modules/esm/module_job:76:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Steps To Reproduce

Here i just done

Hi @hendivalon,

This seems to be related to Vite externalizing SSR dependencies.

If I add the following to vite.config.js, then it resolves the error for me.

  export default defineConfig({
      // ...

+     ssr: {
+         noExternal: [
+             'laravel-precognition',
+             'laravel-precognition-react',
+             'laravel-precognition-react-inertia',
+         ],
+     }
});

I'll have a chat with @timacdonald and see if there's something we can do to prevent needing this, otherwise, we could potentially apply it automatically in the Laravel Vite plugin.

I can't see any reason for needing this, however I also am unable to diagnose why this is happening.

If I manually change the import to include a file extension, it seems to fix SSR.

- export { client } from './client';
+ export { client } from './client.js';

But I again have no idea why this would be the case.

I would appreciate assistance if anyone has any ideas on this one.

Honestly @timacdonald, I have made it since inertia ssr out. Just like this all time on every project, vite.config.js.

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.tsx',
            ssr: 'resources/js/ssr.tsx',
            refresh: true,
        }),
        react(),
    ],
    build: {
        chunkSizeWarningLimit: 1500,
    },
    ssr: {
        noExternal: [
            '@uiw/react-md-editor',
            'react-markdown',
            '@uiw/react-markdown-preview',
            'lodash',
            '@tabler/icons-react',
            'react-share',
            'react-copy-to-clipboard',
            'laravel-precognition',
            'laravel-precognition-react',
            'laravel-precognition-react-inertia',
        ],
    },
});

There must be something about these dependencies that means they can't be externalised, though?

We have complete control over precognition, so I would like to address the issue so we don't have to do this. I just don't know what the thing that we need to do is! haha

Okay, I totally understand what you saying.

I believe this comes down to the runtime difference. SSR uses Node behind the scenes. When using ESM with Node, you are required to add file extensions when using import.

This is done automatically for you when run client-side only. Hence why we're not getting an error outside of SSR.

Check this out - https://nodejs.org/api/esm.html#terminology.

I can't see any reason for needing this, however I also am unable to diagnose why this is happening.

If I manually change the import to include a file extension, it seems to fix SSR.

- export { client } from './client';

+ export { client } from './client.js';

But I again have no idea why this would be the case.

I would appreciate assistance if anyone has any ideas on this one.

Fyi, extension-less imports are basically deprecated / no longer supported.

Ref: vitejs/vite#178 (comment)

Thanks, @NickSdot! I spent far to long figuring this out, but we now have a fix up: #37

Gonna close this in favour of the PR. Thanks for the help, ya'll