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

Improve Remix support #39765

Open
1 of 8 tasks
samuelsycamore opened this issue Nov 6, 2023 · 13 comments
Open
1 of 8 tasks

Improve Remix support #39765

samuelsycamore opened this issue Nov 6, 2023 · 13 comments
Assignees
Labels
dx Related to developers' experience umbrella For grouping multiple issues to provide a holistic view

Comments

@samuelsycamore
Copy link
Member

samuelsycamore commented Nov 6, 2023

I've started experimenting with using Material UI and Joy UI components with Remix and I've run into a few bugs and blockers along the way. Browsing the issues here, I see several open threads where folks are discussing the same problems I've bumped into, so I thought it might be helpful to create an umbrella issue to bring all those discussions to one centralized, up-to-date location where folks can track the progress.

Here are all of the open issues I could find—some are overlapping, others are probably pretty outdated and possibly no longer relevant but I haven't dug too deeply into each one:

Open

Problems

Here are the biggest things I see after reviewing these issues:

Potential solutions

Examples and docs

There are several things we could do to improve the documentation around Remix + MUI!

If there are any other known issues or requests to improve the DX, please share them here!

@samuelsycamore samuelsycamore added umbrella For grouping multiple issues to provide a holistic view dx Related to developers' experience labels Nov 6, 2023
@samuelsycamore samuelsycamore self-assigned this Nov 6, 2023
@arunmmanoharan
Copy link

@samuelsycamore I have MUI working with renderToPipeableStream using this sample:

https://github.com/remix-run/examples/blob/main/chakra-ui/app/entry.server.tsx

@yehudamakarov
Copy link

yehudamakarov commented Nov 24, 2023

I have this issue where if I import like so:
import { useDemoData } from "@mui/x-data-grid-generator";
I get

Uncaught TypeError: Cannot read properties of undefined (reading 'A400')
    at theme.ts:25:17
(anonymous) @ theme.ts:25

The same problem came up for me before and I solved it by changing

import { Alert, Grid } from "@mui/material";

to

import Alert from "@mui/material/Alert";
import Grid from "@mui/material/Grid";

Basically to reproduce,

  1. use the remix material UI example
  2. make a new route
  3. paste in an example from Material UI datagrid that uses useDemoData

@rahad06
Copy link

rahad06 commented Dec 8, 2023

the provided remix template is old and not compatible, packages and layout is obsolete. please provide an up-to-date remix admin template for MUI with internationalization

@mbarni99
Copy link

mbarni99 commented Dec 17, 2023

@samuelsycamore I have MUI working with renderToPipeableStream using this sample:

https://github.com/remix-run/examples/blob/main/chakra-ui/app/entry.server.tsx

Hello,

I have just tried this one out and it may be outdated as I got the following error:
Module '"@remix-run/node"' has no exported member 'Response'.

I skipped importing that Response (whatever it is) and tried with the base FetchAPI Response class, and got the following error:
Argument of type 'ReadWriteStream' is not assignable to parameter of type 'BodyInit | null | undefined'.

The full code of trying this one is the following

import { CacheProvider as EmotionCacheProvider } from '@emotion/react';
import { createReadableStreamFromReadable } from '@remix-run/node';
import { PassThrough } from 'node:stream';
import { RemixServer } from '@remix-run/react';
import { renderToPipeableStream } from 'react-dom/server';
import createEmotionCache from '@emotion/cache';
import createEmotionServer from '@emotion/server/create-instance';
import isbot from 'isbot';
import type { AppLoadContext, EntryContext } from '@remix-run/node';

const ABORT_DELAY = 5000;

export default function handleRequest(
    request: Request,
    responseStatusCode: number,
    responseHeaders: Headers,
    remixContext: EntryContext,
    // This is ignored so we can keep it in the template for visibility.  Feel
    // free to delete this parameter in your app if you're not using it!
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    loadContext: AppLoadContext
) {
    return isbot(request.headers.get('user-agent'))
        ? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
        : handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
}

function handleBotRequest(request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext) {
    return new Promise((resolve, reject) => {
        const emotionCache = createEmotionCache({ key: 'css' });
        let shellRendered = false;

        const { pipe, abort } = renderToPipeableStream(
            <EmotionCacheProvider value={emotionCache}>
                <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />
            </EmotionCacheProvider>,
            {
                onAllReady() {
                    shellRendered = true;

                    const body = new PassThrough();
                    const emotionServer = createEmotionServer(emotionCache);
                    // const stream = createReadableStreamFromReadable(body);

                    const bodyWithStyles = emotionServer.renderStylesToNodeStream();
                    body.pipe(bodyWithStyles);

                    responseHeaders.set('Content-Type', 'text/html');

                    resolve(
                        new Response(bodyWithStyles, {
                            headers: responseHeaders,
                            status: responseStatusCode,
                        })
                    );

                    pipe(body);
                },
                onShellError(error: unknown) {
                    reject(error);
                },
                onError(error: unknown) {
                    responseStatusCode = 500;
                    // Log streaming rendering errors from inside the shell.  Don't log
                    // errors encountered during initial shell rendering since they'll
                    // reject and get logged in handleDocumentRequest.
                    if (shellRendered) {
                        console.error(error);
                    }
                },
            }
        );

        setTimeout(abort, ABORT_DELAY);
    });
}

function handleBrowserRequest(request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext) {
    return new Promise((resolve, reject) => {
        let shellRendered = false;
        const { pipe, abort } = renderToPipeableStream(<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />, {
            onShellReady() {
                shellRendered = true;
                const body = new PassThrough();
                const stream = createReadableStreamFromReadable(body);

                responseHeaders.set('Content-Type', 'text/html');

                resolve(
                    new Response(stream, {
                        headers: responseHeaders,
                        status: responseStatusCode,
                    })
                );

                pipe(body);
            },
            onShellError(error: unknown) {
                reject(error);
            },
            onError(error: unknown) {
                responseStatusCode = 500;
                // Log streaming rendering errors from inside the shell.  Don't log
                // errors encountered during initial shell rendering since they'll
                // reject and get logged in handleDocumentRequest.
                if (shellRendered) {
                    console.error(error);
                }
            },
        });

        setTimeout(abort, ABORT_DELAY);
    });
}

@Brocktho
Copy link

Brocktho commented Dec 27, 2023

@mbarni99

...I got the following error: Module '"@remix-run/node"' has no exported member 'Response'.

I skipped importing that Response (whatever it is) and tried with the base FetchAPI Response class, and got the following error: >Argument of type 'ReadWriteStream' is not assignable to parameter of type 'BodyInit | null | undefined'.

Remix used to ship a specific Response type that allowed you to dump in a ReadWriteStream into the Response, instead of maintaining that full Response object they now maintain a createReadableStreamFromReadable You would do mostly the same as what you had posted, but before slapping it all into the body of the Response you need to put it into the createReadableStreamFromReadable function like:

   // Import
   import { createReadableStreamFromReadable } from "@remix-run/node";
    // Other Code
   //
  //
           resolve(
                    new Response(createReadableStreamFromReadable(stream), {
                        headers: responseHeaders,
                        status: responseStatusCode,
                    })
                );

@michael-land
Copy link
Contributor

Is it possible to use material ui with remix spa mode?

@mahmoudmoravej
Copy link

The current Remix example is a bit outdated and hard to integrate with new Remix templates. I created a brand new integration (with Remix 2.8 + Vite). It helps alot in quick and smooth MUI + Remix integration and also addresses some challenges mentioned here.

Headsup! I am not great with Emotions. But just cross checking with current Remix + MU integration example, it seems it is working as expected with no need to use complex cache/style management.

cc @oliviertassinari @mnajdova

@khera
Copy link

khera commented May 1, 2024

The current Remix example is a bit outdated and hard to integrate with new Remix templates. I created a brand new integration (with Remix 2.8 + Vite). It helps alot in quick and smooth MUI + Remix integration and also addresses some challenges mentioned here.

Thank you so much for this. I was pounding my head for the last 4 hours until I just found this. Incorporating your MuiProvider.tsx file into my entry files was the trick I needed to incorporate MUI into my Remix app. The current "official" example is impossible to decipher as a newbie to Remix working on the current default template.

@mnajdova
Copy link
Member

mnajdova commented May 1, 2024

The current Remix example is a bit outdated and hard to integrate with new Remix templates. I created mahmoudmoravej/remix-mui#1. It helps alot in quick and smooth MUI + Remix integration and also addresses some challenges mentioned here.

@mahmoudmoravej would you like to update the current example we have and open a PR, we can then check what changes you've made.

@mahmoudmoravej
Copy link

mahmoudmoravej commented May 2, 2024

@mnajdova I did it but I am not sure it will be so helpful, becasue:

  • It is upgraded to Remix/Vite template, so you will see a bunch of unnecssary changes.
  • The approach I used is completely different, so there will not be a good side-by-side comparison.

I still think the PR I provided above(which simply added MUI on top of the latest version of Remix/Vite template) shows a better understanding of what and how it has been doe.

@cuzzlor
Copy link

cuzzlor commented May 28, 2024

The official example uses serverModuleFormat: 'cjs' in the remix config which seems to prevent fast hot-reloading of front-end changes.

I used the starter from @mnajdova: https://github.com/mahmoudmoravej/remix-mui and it seems to work very well so far. Much simpler, streaming (defer/suspense/await) seems to work fine, hot-reloading etc all seems to work perfectly.

@incarnateTheGreat
Copy link

The current Remix example is a bit outdated and hard to integrate with new Remix templates. I created a brand new integration (with Remix 2.8 + Vite). It helps alot in quick and smooth MUI + Remix integration and also addresses some challenges mentioned here.

Headsup! I am not great with Emotions. But just cross checking with current Remix + MU integration example, it seems it is working as expected with no need to use complex cache/style management.

cc @oliviertassinari @mnajdova

Thank you so much for this! It really helped!

@lookitskris
Copy link

The current Remix example is a bit outdated and hard to integrate with new Remix templates. I created a brand new integration (with Remix 2.8 + Vite). It helps alot in quick and smooth MUI + Remix integration and also addresses some challenges mentioned here.

Headsup! I am not great with Emotions. But just cross checking with current Remix + MU integration example, it seems it is working as expected with no need to use complex cache/style management.

cc @oliviertassinari @mnajdova

my guy - if I could tip you I would. Spent a full day going round and round in circles and this example just works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dx Related to developers' experience umbrella For grouping multiple issues to provide a holistic view
Projects
None yet
Development

No branches or pull requests