Sorry @paulishca , I have been swamped and kids had a long weekend so I just started working today.
This should get the conversation started. I’m not sure I’m executing the mediaQuery part correctly.
On the App side I have issues using hydrate so I use render. Not sure how to use hydrate instead, any feedback is appreciated.
Server
import React from "react"
import { renderToString } from "react-dom/server"
import App from "../../ui/both/App"
import { LoadableCaptureProvider, preloadAllLoadables } from 'meteor/npdev:react-loadable'
import { FastRender } from "meteor/communitypackages:fast-render"
import { CacheProvider } from '@emotion/react';
import createEmotionServer from '@emotion/server/create-instance';
import creatEmotionCache from '../../ui/both/createEmotionCache'
import parser from 'ua-parser-js';
import mediaQuery from 'css-mediaquery';
preloadAllLoadables().then(() => {
FastRender.onPageLoad( (sink) => {
const deviceType = parser(sink.request.headers['user-agent']).device.type || 'desktop';
console.log(deviceType)
const ssrMatchMedia = (query) =>{ ({
matches: mediaQuery.match(query, {
// The estimated CSS width of the browser.
width: deviceType === 'mobile' ? '0px' : '1024px',
}),
})};
const cache = creatEmotionCache();
const { extractCriticalToChunks, constructStyleTagsFromChunks } = createEmotionServer(cache);
const loadableHandle = {};
const helmetContext = {};
const html = renderToString(
<LoadableCaptureProvider handle={loadableHandle}>
<CacheProvider value={cache}>
<App location={sink.request.url} context={helmetContext} ssrMatchMedia={ssrMatchMedia} />
</CacheProvider>
</LoadableCaptureProvider>
);
// Grab the CSS from emotion
const emotionChunks = extractCriticalToChunks(html);
const emotionCss = constructStyleTagsFromChunks(emotionChunks);
sink.appendToHead(emotionCss)
sink.appendToHead(loadableHandle.toScriptTag());
sink.renderIntoElementById("react-target", html);
});
});
CLIENT MAIN
import "../imports/startup/client/index"
import React from 'react'
import { render } from "react-dom"
import App from '../imports/ui/both/App'
import { preloadLoadables } from 'meteor/npdev:react-loadable'
import { FastRender } from "meteor/communitypackages:fast-render"
import { CacheProvider } from '@emotion/react';
import createEmotionCache from '../imports/ui/both/createEmotionCache'
const cache = createEmotionCache()
function Main() {
return (
<CacheProvider value={cache}>
<App/>
</CacheProvider>
);
}
FastRender.onPageLoad( () => {
indexedDB.open("dummy")
preloadLoadables().then(() =>{
render(<Main/>, document.getElementById("react-target")
)
})
})
APP
import React, { useState , useEffect} from "react"
import Layout from "../layouts/Layout"
import Router from "./Router"
import NotFound from "../pages/NotFound"
import { Route , Switch } from "react-router-dom"
import { Helmet, HelmetProvider } from "react-helmet-async"
import useOneSignal from "../../api/oneSignal/hooks/useOneSignal"
import useUser from "../hooks/useUser"
import useRoutes from "../hooks/useRoutes"
import { ThemeProvider } from '@mui/material'
import { createTheme } from '@mui/material/styles';
import theme from '../both/theme'
import { modeState } from '../../api/states/ThemeState';
export default App = ({ location, context = {} , ssrMatchMedia }) => {
const oneSignalResponse = useOneSignal({debug:false})
const user = useUser()
const yourRoutes = useRoutes({ user,isNav:false })
const [activeTheme, setActiveTheme] = useState(createTheme(theme))
// theme.props.MuiUseMediaQuery = ssrMatchMedia
useEffect(() => {
theme.palette.mode = modeState.get()
setActiveTheme(createTheme(theme))
}, [modeState.use()])
return (
<HelmetProvider context={context}>
<Helmet>
<title lang="en">APP</title>
</Helmet>
<Router location={location}>
<ThemeProvider theme={activeTheme}>
<Layout>
<Switch>
{yourRoutes.map(route =>
<Route key={route.path} exact={route.exact} path={route.path} component={route.component}/>
)}
<Route component={NotFound}/>
</Switch>
</Layout>
</ThemeProvider>
</Router>
</HelmetProvider>
);
}
theme
import React from 'react'
import { Link as RouterLink } from 'react-router-dom'
import { modeState } from '../../api/states/ThemeState';
// https://bareynol.github.io/mui-theme-creator/
const LinkBehavior = React.forwardRef((props, ref) => {
const { href, ...other } = props;
// Map href (MUI) -> to (react-router)
return <RouterLink ref={ref} to={href} {...other} />;
});
// Create a theme instance.
const theme = {
palette: {
mode: modeState.get(),
primary: {
main: '#000000',
},
secondary: {
main: '#0ebe96',
},
},
components: {
MuiLink: {
defaultProps: {
component: LinkBehavior,
},
}
},
}
if (Meteor.isClient){
console.log(theme)
}
export default theme;
createEmotionCache.js
import createCache from '@emotion/cache';
export default function createEmotionCache() {
return createCache({ key: 'css' });
}