denoland / fresh

The next-gen web framework.
https://fresh.deno.dev
MIT License
12.54k stars 648 forks source link

Using Material UI / Preact compatible component library #411

Closed AravindPrabhs closed 2 years ago

AravindPrabhs commented 2 years ago

Hi,

I was trying to include Material UI since it is compatible with preact: https://twitter.com/preactjs/status/1152267975078154240?lang=en-GB

And including MUI core as a dependency as in normal deno: https://github.com/denoland/deno/issues/7282

However I run into [object Object] is not a valid HTML tag name: https://github.com/denoland/deno/issues/7282 when doing it both as a route and as an island.

Would in general all the packages in https://preactjs.com/about/libraries-addons/ technically be usable with Fresh ?

raymclee commented 2 years ago

https://mui.com/material-ui/guides/server-rendering/ I think MUI need some setup for server side rendering like the twind in fresh demo

AravindPrabhs commented 2 years ago

To my understanding this extra configuration is a bonus to make sure there is no flickering since we re-render on the client side - so I assume purely using an island should also work.

However, I did give this a go, but this feels very non-standard and I was unsure how to inject html and css. I end-up getting React not defined error.

import { h } from "preact";
import {CssBaseline} from '@mui';
import { ThemeProvider } from 'mui/styles';
import createCache from 'https://esm.sh/@emotion/cache';
import { CacheProvider } from 'https://esm.sh/@emotion/react';
import createEmotionServer from 'https://esm.sh/@emotion/server/create-instance';
import render from 'preact-render-to-string';
import theme from './theme.ts';

export function createEmotionCache() {
  return createCache({ key: 'css' });
}

export function serverMUI(App: any) {
    const cache = createEmotionCache();
    const { extractCriticalToChunks, constructStyleTagsFromChunks } =
        createEmotionServer(cache);

    // Render the component to a string.
    const html: string = render(
        <CacheProvider value={cache}>
            <ThemeProvider theme={theme}>
                {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
                <CssBaseline />
                <App />
            </ThemeProvider>
        </CacheProvider>
    );

    // Grab the CSS from emotion
    const emotionChunks = extractCriticalToChunks(html);
    const emotionCss: string = constructStyleTagsFromChunks(emotionChunks);

    return <div dangerouslySetInnerHTML={{__html: emotionCss.concat(html)}}/>
}
export * from "mui";

For any component that I want rendered with MUI I just wrap it in a serverMUI call. Note that replicating the theming and caching and an island gets the same exact error - the previous error described happens if you remove the wrapping CacheProvider etc.

AravindPrabhs commented 2 years ago

Actually I realise the better way to do the above is using the request handlers instead but I still get the same error.

raymclee commented 2 years ago

maybe try adding "react": "preact " in import_map ?

Actually I realise the better way to do the above is using the request handlers instead but I still get the same error.

AravindPrabhs commented 2 years ago

that isn't a valid map

tylrw commented 2 years ago

The approach here might work for you.

SalvadorLekan commented 2 years ago

I got it to work by adding this to the import_map.json. (I tested with this example from MUI's Website and I got an alert in the browser) "@mui/material": "https://esm.sh/@mui/material@5.8.7?alias=react:preact/compat,react/jsx-runtime:preact/compat/jsx-runtime&deps=preact@10.8.1"

AravindPrabhs commented 2 years ago

Thanks guys that works well !

marsidev commented 2 years ago

Actually I realise the better way to do the above is using the request handlers instead but I still get the same error.

Can you share your final working code? I also want to implement Material UI. I tried using a request handler inside routes/index.tsx but I'm getting the following error:

An error occured during route handling or page rendering. TypeError: Cannot read properties of undefined (reading 'context')
    at Module.w (https://esm.sh/v86/preact@10.9.0/X-YS9yZWFjdC9qc3gtcnVudGltZTpwcmVhY3QvY29tcGF0L2pzeC1ydW50aW1lLHJlYWN0OnByZWFjdC9jb21wYXQ/deno/hooks.js:2:1132)
gbahamondezc commented 1 year ago

@marsidev I had the same issue, updating the preact deps version in the @mui/material import line to the same than fresh is using 10.11.0 fixed the issue for me, example.

{
  "imports": {
    "$fresh/": "https://deno.land/x/fresh@1.1.2/",
    "preact": "https://esm.sh/preact@10.11.0",
    "preact/": "https://esm.sh/preact@10.11.0/",
    "preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4",
    "@preact/signals": "https://esm.sh/*@preact/signals@1.0.3",
    "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1",
    "twind": "https://esm.sh/twind@0.16.17",
    "twind/": "https://esm.sh/twind@0.16.17/",
    "@mui/material": "https://esm.sh/@mui/material@^5.10.17?alias=react:preact/compat,react/jsx-runtime:preact/compat/jsx-runtime&deps=preact@10.11.0"
  }
}
reosablo commented 1 year ago

see also: #363