Skip to content

Instantly share code, notes, and snippets.

@caub
Last active May 27, 2022 04:38
Show Gist options
  • Save caub/4ddbe7ed7642fcaca91553360c37ee91 to your computer and use it in GitHub Desktop.
Save caub/4ddbe7ed7642fcaca91553360c37ee91 to your computer and use it in GitHub Desktop.
Next static
import React from 'react';
import Html from '../components/html'; // wraps pages into <html> and some common layout
// you might want a webpack.config.js at least for styles
// typically we use a sass loader, and also @emotion/react in our components
// Html will take care to add <link> for built ./build/**/*.css
// and <script> for built ./build/**/*.js if any, you might even inline it <script>{content}</script> if short
// It's also possible to build css/js assets per page, we didn't do that
export async function getServerSideProps({ req }) {
// do stuff
return { req };
}
export default function NotFound(props) {
return (
<Html {...props}>
<h2 className="text-center">Not found</h2>
</Html>
)
}
const express = require('express');
const { renderToStaticMarkup } = require('react-dom/server');
const { createElement } = require('react');
const fs = require('fs');
require('@babel/register')({ only: ['pages', 'components'].map(n => __dirname + '/' + n) }); // uses .babelrc as well
const app = express().disable('x-powered-by');
// ... production stuff like https redirect, compression
app.use(express.static(__dirname + '/build', process.env.NODE_ENV === 'production' && {
redirect: false,
index: false,
maxAge: '30d',
}));
// ... production security headers
async function renderPage(page, params) {
const component = require(`./pages/${page}`);
const componentProps = await component.getServerSideProps?.(params);
if (componentProps === null) return null; // used for 404's
const app = createElement(component.default, { ...params, ...componentProps });
return `<!DOCTYPE html>${renderToStaticMarkup(app)}`;
}
// custom dynamic pages
app.get('/blog/:id', async function (req, res, next) {
try {
const content = await renderPage('blog/:id.js', { req, id: req.params.id });
if (!content) return next();
res.send(content);
} catch (err) {
if (!process.env.NODE_ENV) console.error(err);
res.sendStatus(500);
}
});
// regular pages
app.get('*', async function (req, res) {
const path = new URL(req.url, 'file:').pathname.slice(1).replace(/\/$/, ''); // trim leading / and trailing /
const found = fs.existsSync(`./pages/${path}.js`)
|| fs.existsSync(`./pages${path ? '/' + path : ''}/index.js`);
try {
res.status(found ? 200 : 404).send(await renderPage(found ? path : '404', { req }));
} catch (err) {
if (!process.env.NODE_ENV) console.error(err);
res.sendStatus(500);
}
});
// ... express error middleware
app.listen(process.env.PORT || 3000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment