Skip to content

Instantly share code, notes, and snippets.

@gbozee
Created December 29, 2017 19:20
Show Gist options
  • Save gbozee/51704f3c0a74016f473742da267721e1 to your computer and use it in GitHub Desktop.
Save gbozee/51704f3c0a74016f473742da267721e1 to your computer and use it in GitHub Desktop.
Server side implementation files with graphql support
// To use preact, we would have
/***
import { getComponent, cdn, afterScripts } from "./preact-server"; // should be the first line because of how module-alias works
***/
import { getComponent, cdn, afterScripts } from "./react-server";
const { graphqlExpress, graphiqlExpress } = require("apollo-server-express");
import Loadable from "react-loadable";
import express from "express";
import path from "path";
const bodyParser = require("body-parser");
import getRouter from "./router";
const app = express();
// Serve client.js and vendor.js
app.use("/static", express.static(__dirname + "/static"));
app.use("/graphql", bodyParser.json(), graphqlExpress({ schema }));
// // GraphiQL, a visual editor for queries
app.use("/graphiql", graphiqlExpress({ endpointURL: "/graphql" }));
const { router, schema } = getRouter(getComponent, cdn, afterScripts);
app.use("/", router);
export default app;
var path = require("path");
var moduleAlias = require("module-alias");
moduleAlias.addAliases({
react: "preact-compat/dist/preact-compat.min",
"react-dom": "preact-compat/dist/preact-compat.min",
"create-react-class": path.resolve(__dirname, "./create-preact-class")
});
import "./patchPreact";
import { getComponents as GC } from "../utils";
import renderToString from "preact-render-to-string";
export const cdn = `
<script type="text/javascript" src="https://unpkg.com/@umds/[email protected]/object-assign.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/dist/preact.min.js"></script>
<script src="https://unpkg.com/[email protected]/prop-types.js"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/dist/preact-compat.min.js"></script>
`;
export const afterScripts = `
<script>
window.React = preactCompat;
window.ReactDOM = preactCompat;</script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/umd/react-router-dom.min.js"></script>
`
export const getComponent = (path, context) => {
return GC(renderToString, path, context);
};
import React from "react";
import { getComponents as GC } from "./utils";
import ReactDOMServer from "react-dom/server";
import { ServerStyleSheet } from "styled-components";
import Loadable from "react-loadable";
import { StaticRouter } from "react-router-dom";
import Routes from "../routes";
export const cdn = `
<script type="text/javascript" src="https://unpkg.com/@umds/[email protected]/object-assign.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/umd/react-router-dom.min.js"></script>
`;
export const afterScripts = ` `;
export const getComponent = (path, context) => {
const sheet = new ServerStyleSheet();
const modules = [];
const html = ReactDOMServer.renderToString(
sheet.collectStyles(
<Loadable.Capture
report={moduleName => {
modules.push(moduleName);
}}
>
<StaticRouter location={path} context={context}>
<Routes />
</StaticRouter>
</Loadable.Capture>
)
);
return GC(ReactDOMServer.renderToString,path, context);
};
© 2017 GitHub, Inc.
//@ts-check
import path from "path";
import express from "express";
const { makeExecutableSchema } = require("graphql-tools");
const books = [
{ title: "Harry Potter and the Sorcerer's stone", author: "J.K. Rowling" },
{ title: "Jurassic Park", author: "Michael Crichton" }
];
// The GraphQL schema in string form
const typeDefs = `
type Query { books: [Book], route(path: String): Route }
type Book { title: String, author: String }
type Route { html: String, css: String, scripts:[String],styles:[String]}
`;
function renderer(getComponent, cdn, afterScripts) {
const render = (html, css, bundles, styles) => `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" href="/favicon.ico">
<title>React App</title>
${css}
${styles.map(style => `<link href="${style}" rel="stylesheet"/>`).join("\n")}
${bundles
.map(bundle => `<link rel="prefetch" href="${bundle}">`)
.join("\n")}
</head>
<body>
<div id="root">${html}</div>
${cdn}
${afterScripts}
${bundles.map(bundle => `<script src="${bundle}"></script>`).join("\n")}
<script>window.main()</script>
</body>
</html>
`;
// The resolvers
const resolvers = {
Query: {
books: () => books,
route: (_, { path }) => {
const context = {};
let newPath = path.replace("$", "");
console.log(newPath);
console.log(context);
return getComponent(newPath, context);
}
}
};
// Put together a schema
const schema = makeExecutableSchema({
typeDefs,
resolvers
});
const router = express.Router();
router.get("/manifest.json", (req, res) => {
res.status(200).sendFile(path.resolve(__dirname, "manifest.json"));
});
router.get("/service-worker.js", (req, res) => {
res.status(200).sendFile(path.resolve(__dirname, "service-worker.js"));
});
router.get("*", (req, res) => {
const context = {};
if (context.url) {
res.redirect(context.url);
return;
}
const { html, css, scripts, styles } = getComponent(req.url, context);
res.status(200).send(render(html, css, scripts, styles));
});
return { router, schema };
}
export default renderer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment