This example shows how to do a optimized website for mobile and a responsive website for desktop in the same stack.
>> Check the demo << and use Lighthouse to check the performance!
+ const device = require('device');
app.prepare().then(() => {
createServer((req, res) => {
+ const _device = device(req.headers['user-agent']);
+ req.device = _device.type;
handle(req, res, parsedUrl)
}).listen(3000, (err) => {
if (err) throw err
console.log('> Ready on https://localhost:3000')
})
})
import Document from 'next/document';
import { ServerStyleSheet } from 'styled-components';
+import { mediaStyles } from '../components/media';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
+ {ctx.req.device === 'desktop' && (
+ <style type="text/css" dangerouslySetInnerHTML={{ __html: mediaStyles }} />
+ )}
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
}
import App from 'next/app';
import { ThemeProvider } from 'styled-components';
+import { Context as MediaContext, MediaContextProvider, } from '../components/media';
export default class MyApp extends App {
+ static async getInitialProps(ctx) {
+ const appProps = await App.getInitialProps(ctx);
+
+ const device = ctx.ctx.req.device;
+
+ return { ...appProps, device };
+ }
render() {
const { Component, pageProps, device } = this.props;
return (
+ <MediaContext.Provider value={device}>
+ {device === 'desktop' ? (
+ <MediaContextProvider>
+ <ThemeProvider theme={theme}>
+ <Component {...pageProps} />
+ </ThemeProvider>
+ </MediaContextProvider>
+ ) : (
+ <ThemeProvider theme={theme}>
+ <Component {...pageProps} />
+ </ThemeProvider>
+ )}
+ </MediaContext.Provider>
);
}
}
import React, { useContext } from 'react';
import { createMedia } from '@artsy/fresnel';
export const Context = React.createContext();
/**
* Components
*/
export const Mobile = ({ children }) => {
const context = useContext(Context);
return context === 'phone' ? (
children
) : (
<Media lessThan="lg">{children}</Media>
);
};
export const Desktop = ({ children }) => {
const context = useContext(Context);
return context === 'desktop' ? (
<Media greaterThan="md">{children}</Media>
) : null;
};
export const NotDesktop = ({ children }) => {
const context = useContext(Context);
if (context === 'phone') {
return children;
}
return context !== 'desktop' ? (
children
) : (
<Media lessThan="lg">{children}</Media>
);
};
const Medias = createMedia({
breakpoints: {
xs: 0,
sm: 576,
md: 768,
lg: 1024,
xl: 1200,
},
});
export const mediaStyles = Medias.createMediaStyle();
export const { Media, MediaContextProvider } = Medias;