{"id":13727671,"url":"https://github.com/brillout/goldpage","last_synced_at":"2025-03-21T08:30:58.736Z","repository":{"id":48251441,"uuid":"186423241","full_name":"brillout/goldpage","owner":"brillout","description":"Page Builder.","archived":false,"fork":false,"pushed_at":"2021-08-04T09:39:11.000Z","size":22542,"stargazers_count":57,"open_issues_count":15,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-30T00:27:13.310Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brillout.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-13T13:17:36.000Z","updated_at":"2022-11-21T06:25:42.000Z","dependencies_parsed_at":"2022-09-15T16:20:21.382Z","dependency_job_id":null,"html_url":"https://github.com/brillout/goldpage","commit_stats":null,"previous_names":["reframejs/ssr-coin","reframejs/goldpage"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brillout%2Fgoldpage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brillout%2Fgoldpage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brillout%2Fgoldpage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brillout%2Fgoldpage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brillout","download_url":"https://codeload.github.com/brillout/goldpage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244236080,"owners_count":20420759,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T02:00:29.472Z","updated_at":"2025-03-21T08:30:56.017Z","avatar_url":"https://github.com/brillout.png","language":"JavaScript","funding_links":[],"categories":["Tools","📦 Legacy \u0026 Inactive Projects"],"sub_categories":["Vue"],"readme":"\u003c!---\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n--\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"/../../#readme\"\u003e\n    \u003cimg align=\"center\" src=\"/docs/assets/logo-with-text.svg\" height=96 style=\"max-width:100%;\" alt=\"Goldpage\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\n\n\n\n\n\n\n\n\n\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#what-is-goldpage\u003eWhat is Goldpage\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#how-it-works\u003eHow it Works\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#learn-more\u003eLearn More\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; Usage\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#getting-started\u003eGetting Started\u003c/a\u003e\n\u003cbr/\u003e\n\u003csub\u003e\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nBasics\n\u003c/sub\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#css--static-assets\u003eCSS \u0026 Static Assets\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#async-data-addinitialprops\u003eAsync Data: `addInitialProps`\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#html-indexhtml-head-meta-link-\u003eHTML: `index.html`, `\u003chead\u003e`, `\u003cmeta\u003e`, `\u003clink\u003e`, ...\u003c/a\u003e\n\u003cbr/\u003e\n\u003csub\u003e\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nRender Control\n\u003c/sub\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#where--when-rendertodom-rendertohtml--renderhtmlatbuildtime\u003eWhere \u0026 when: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#how-htmlrender--domrender\u003eHow: `htmlRender` \u0026 `domRender`\u003c/a\u003e\n\u003cbr/\u003e\n\u003csub\u003e\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nApp Types\n\u003c/sub\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#spa--mpa\u003eSPA \u0026 MPA\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#ssr\u003eSSR\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#static-website\u003eStatic Website\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#mixed-apps--bfa\u003eMixed Apps \u0026 BFA\u003c/a\u003e\n\u003cbr/\u003e\n\u003csub\u003e\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nAPI Reference\n\u003c/sub\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#page-config-pagejs\u003ePage Config `*.page.js`\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#goldpage-config-goldpageconfigjs\u003eGoldpage Config `goldpage.config.js`\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#cli\u003eCLI\u003c/a\u003e\n\u003cbr/\u003e\n\u003csub\u003e\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\nRecipes\n\u003c/sub\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#providers-redux--react-router--vuex--vue-router--graphql-apollo--relay--\u003eProviders: Redux / React Router / Vuex / Vue Router / GraphQL Apollo / Relay / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#transpilation-babel--typescript---es6--\u003eTranspilation: Babel / TypeScript /  ES6 / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#css-in-js-emotion--styled-components--\u003eCSS-in-JS: Emotion / styled-components / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#css-pre-processors-postcss--sass--less--\u003eCSS pre-processors: PostCSS / Sass / Less / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#routing-server-side-routing--browser-side-routing--react-router--vue-router--\u003eRouting: Server-side Routing / Browser-side Routing / React Router / Vue Router / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#frontend-libraries-google-analytics--jquery--bootstrap--semantic-ui--\u003eFrontend Libraries: Google Analytics / jQuery / Bootstrap / Semantic UI / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#server-express--koa--hapi--fastify--\u003eServer: Express / Koa / Hapi / Fastify / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#view-libraries-react--vue--preact--\u003eView Libraries: React / Vue / Preact / ...\u003c/a\u003e\n\u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp; \u003ca href=#process-managers-docker--systemd--pm2--\u003eProcess Managers: Docker / systemd / PM2 / ...\u003c/a\u003e\n\n\u003cbr/\u003e\n\n\n\n## What is Goldpage\n\nGoldpage makes it easy to create a modern frontend.\n\nYou define pages:\n\n~~~jsx\n// A page config\nexport default {\n  route: '/hello/:name',\n  view: ({name}) =\u003e (\n    \u003cdiv\u003e\n      Hello {name}, welcome to Goldpage.\n    \u003c/div\u003e\n  ),\n};\n~~~\n\nThe Goldpage CLI takes care of the rest:\n\n~~~shell\n$ goldpage build\n~~~\n\nYour pages are built at `.build/browser/`.\nIf your pages are static, deploy `.build/browser/` to a static host such as Netlify and you are done.\n\nFor server-side rendering, use a Node.js server and add the Goldpage middleware:\n\n~~~js\n// Goldpage can be used with any Node.js server framework (Express, Koa, Hapi, ...)\nconst express = require('express');\nconst goldpage = require('goldpage');\n\nconst app = express();\n\n// Our Goldpage middleware serves your pages.\napp.use(goldpage.express);\n~~~\n\nGoldpage is a tiny do-one-thing-do-it-well library (~4K LOCs) with a simple interface. Yet it is powerful:\n- **Render Control** -\n  You can choose when and where your pages are rendered:\n  one page can be rendered to both HTML and the DOM (classic SSR),\n  another page can be rendered to HTML only (good old plain HTML like in the 90s!),\n  and a third page can be rendered to the DOM only (classic SPA).\n- **Any view tool** -\n  Goldpage can be used with\n  any view framework (React, Vue, RNW, Svelte, ...) and\n  any view library (Redux, Vuex, GraphQL, ...).\n- **HTML-only for mobile** -\n  You can choose to render a page to HTML only with\n  no browser-side JavaScript.\n  Removing browser-side JavaScript is an effective\n  way to achieve high performance on mobile.\n- **Any app type** -\n  Goldpage supports all app types\n  (SPA, SSR, Static Website, ...)\n  and switching from one app type to another is easy;\n  you can start writing a prototype and decide later which app type is right for you.\n  No more endless research whether you should go for a static website or SSR!\n- **Backend First Apps** -\n  Goldpage introduces a new app type \u0026mdash; the [Backend First App (BFA)](/docs/bfa.md#readme).\n  A BFA uses the view framework (React, Vue, ...) primarly as an HTML template engine\n  and only secondarily to implement interactive views.\n\n\n## How it Works\n\nGoldpage uses Webpack to transpile and bundle your pages. Its Webpack config is minimal allowing you to easily modify and extend it.\n\nGoldpage is designed to give you full control over how and where your pages are rendered.\n\nYou control where a page is rendered with two page configs:\n- `renderToDom` - If set to true, your page is rendered to the DOM (browser).\n- `renderToHtml` - If set to true, your page is rendered to HTML (Node.js).\n\nIf you want to add SSR to a page you set `renderToHtml: true` and `renderToDom: true`.\nIf you want a page to be an SPA, you set `renderToDom: true` and `renderToHtml: false`.\nYou can also set `renderToHtml: true` and `renderToDom: false` for a page\nto be rendered only to HTML with zero browser-side JavaScript.\n(Good old plain HTML like in the 90s!)\n\nYou can control how your pages are rendered by defining the render functions `htmlRender` and `domRender`:\n\n~~~js\n// We can use any view framework here (React, Vue, RNW, ...)\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\n\nexport default domRender;\n\nasync function domRender({page, initialProps, CONTAINER_ID}) {\n  const element = React.createElement(page.view, initialProps);\n  const container = document.getElementById(CONTAINER_ID);\n  if( page.renderToHtml ){\n    ReactDOM.hydrate(element, container);\n  } else {\n    ReactDOM.render(element, container);\n  }\n}\n~~~\n\n~~~js\nconst React = require('react');\nconst ReactDOMServer = require('react-dom/server');\n\nmodule.exports = htmlRender;\n\nasync function htmlRender({page, initialProps, CONTAINER_ID}) {\n  const el = React.createElement(page.view, initialProps);\n  const html = ReactDOMServer.renderToStaticMarkup(el);\n  return html;\n}\n~~~\n\nGoldpage's render control enables you to:\n- Build any app type. (SPA, SSR, static website, ...)\n- Build new kinds of apps, such as [Backend First Apps](/docs/bfa.md#readme).\n- Use any view framework. (React, Vue, RNW, ...)\n- Use any view library. (React Router, Vuex, GraphQL, ...)\n\nFor server-side rendering, we provide a server middleware that can be used with any server framework. (Express, Koa, Hapi, ...)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Learn More\n\nLearning material.\n\n- [Backend First App (BFA)](/docs/bfa.md#readme)\n  \u003cbr/\u003e\n  Introduction to BFAs.\n  A BFA uses the view framework (React, Vue, ...) primarly as an HTML template engine\n  and only secondarily to implement interactive views.\n  Increasing productivity and performance.\n- [Goldpage VS Others (CRA, Next.js, Nuxt.js, Gatsby, Vue CLI, etc.)](/docs/goldpage-vs-others.md#readme)\n  \u003cbr/\u003e\n  Explains what makes Goldpage different from other tools (CRA, Next.js, Nuxt.js, Gatsby, Vue CLI, etc.)\n- [CSR \u0026 SSR Explained](/docs/csr-and-ssr-explained.md#readme)\n  \u003cbr/\u003e\n  Explains what CSR and SSR are.\n- [Client-side Rendering (CSR) VS Server-side Rendering (SSR)](/docs/csr-vs-ssr.md#readme)\n  \u003cbr/\u003e\n  Helps you choose between CSR and SSR.\n- [Plugins](/plugins#readme)\n  \u003cbr/\u003e\n  List of Goldpage plugins.\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Getting Started\n\nThis getting started adds Goldpage to an exisiting app.\nIf you don't have an app yet or if you just want to try out Goldpage,\nthen use a [Goldpage starter](https://github.com/topics/goldpage-starter).\n\n0. Install Goldpage.\n\n   ~~~shell\n   npm install goldpage\n   ~~~\n\n   Install a [render plugin](/plugins#render-plugins), such as `@goldpage/react`:\n   ~~~shell\n   npm install @goldpage/react\n   ~~~\n\n   Install a [server plugin](/plugins#server-plugins), such as `@goldpage/express`:\n   ~~~shell\n   npm install @goldpage/express\n   ~~~\n\n1. Add Goldpage to your Node.js server.\n\n   With Express:\n   ~~~js\n   const express = require('express');\n   const ssr = require('goldpage');\n\n   const app = express();\n   app.use(ssr.express);\n   ~~~\n\n   \u003cdetails\u003e\n   \u003csummary\u003e\n   With Hapi\n   \u003c/summary\u003e\n\n   ~~~js\n   const Hapi = require('hapi');\n   const ssr = require('goldpage');\n\n   (async ()=\u003e{\n     const server = Hapi.Server();\n     await server.register(ssr.hapi);\n   })();\n   ~~~\n   \u003c/details\u003e\n\n   \u003cdetails\u003e\n   \u003csummary\u003e\n   With Koa\n   \u003c/summary\u003e\n\n   ~~~js\n   const Koa = require('koa');\n   const ssr = require('goldpage');\n\n   const app = new Koa();\n   app.use(ssr.koa);\n   ~~~\n   \u003c/details\u003e\n\n   \u003cdetails\u003e\n   \u003csummary\u003e\n   With other server frameworks\n   \u003c/summary\u003e\n\n   Goldpage can be used with any server framework.\n   But there is no documentation for this (yet).\n   Open a GitHub issue\n   if you want to use Goldpage with a server framework other than\n   Express, Koa, or Hapi.\n   \u003c/details\u003e\n\n2. Create your first page.\n\n   Create a `pages/` directory.\n   ~~~shell\n   cd path/to/your/project/ \u0026\u0026 mkdir pages/\n   ~~~\n\n   Create a file\n   at `pages/hello.page.js`.\n\n   With React:\n   ~~~js\n   // pages/hello.page.js\n\n   import React, {useState} from 'react';\n\n   export default {\n     route: '/hello/:name',\n     addInitialProps,\n     view: Hello,\n     title,\n     renderToHtml: true,\n   };\n\n   async function addInitialProps({name}) {\n     // We simulate a network request delay\n     await sleep(0.5);\n\n     const nameReversed = name.split('').reverse().join('');\n     return {nameReversed};\n   }\n\n   function Hello({name, nameReversed}) {\n     const [isReversed, setReverse] = useState(false);\n\n     return (\n       \u003cdiv\u003e\n         Hello \u003cspan\u003e{isReversed ? nameReversed : name}\u003c/span\u003e, welcome to Goldpage.\n         \u003cbr/\u003e\n         \u003cbutton onClick={() =\u003e setReverse(!isReversed)}\u003eReverse name\u003c/button\u003e\n       \u003c/div\u003e\n     );\n   }\n\n   function title({name}) {\n     return 'Hi '+name;\n   }\n\n   function sleep(seconds) {\n     let resolve;\n     const promise = new Promise(r =\u003e resolve=r);\n     setTimeout(resolve, seconds*1000);\n     return promise;\n   }\n   ~~~\n\n   \u003cdetails\u003e\n   \u003csummary\u003e\n   With Vue\n   \u003c/summary\u003e\n\n   ~~~js\n   // pages/hello.page.js\n\n   import Hello from './Hello.vue';\n\n   export default {\n     route: '/hello/:name',\n     addInitialProps,\n     view: Hello,\n     title,\n     renderToHtml: true,\n   };\n\n   async function addInitialProps({name}) {\n     // We simulate a network request delay\n     await sleep(0.5);\n\n     const nameReversed = name.split('').reverse().join('');\n     return {nameReversed};\n   }\n\n   function title({name}) {\n     return 'Hi '+name;\n   }\n\n   function sleep(seconds) {\n     let resolve;\n     const promise = new Promise(r =\u003e resolve=r);\n     setTimeout(resolve, seconds*1000);\n     return promise;\n   }\n   ~~~\n   ~~~js\n   // pages/Hello.vue\n\n   \u003ctemplate\u003e\n     \u003cdiv\u003e\n       Hello {{isReversed?nameReversed:name}}, welcome to \u003ccode\u003eGoldpage\u003c/code\u003e.\n       \u003cbr/\u003e\n       \u003cbutton v-on:click=\"toggleReverse\"\u003eReverse name\u003c/button\u003e\n     \u003c/div\u003e\n   \u003c/template\u003e\n\n   \u003cscript\u003e\n   import Vue from \"vue\";\n\n   export default {\n     props: ['name', 'nameReversed'],\n     data() {\n       return {\n         isReversed: false,\n         bundler: \"Parcel\"\n       };\n     },\n     methods: {\n       toggleReverse: function() {\n         this.isReversed = !this.isReversed;\n       },\n     },\n   };\n   \u003c/script\u003e\n\n   \u003cstyle scoped\u003e\n   code {\n     color: gold;\n   }\n   \u003c/style\u003e\n   ~~~\n   \u003c/details\u003e\n\n3. Add the Goldpage scripts to your `package.json`:\n   ~~~json\n   {\n     \"scripts\": {\n       \"dev\": \"goldpage dev ./path/to/your/server.js\",\n       \"prod\": \"npm run build \u0026\u0026 npm run start\",\n       \"build\": \"goldpage build ./path/to/your/server.js\",\n       \"start\": \"export NODE_ENV='production' \u0026\u0026 node ./.build/nodejs/server\"\n     }\n   }\n   ~~~\n\n   \u003e :information_source:\n   \u003e Goldpage also builds your server's source code\n   \u003e so that you can use the same language,\n   \u003e for example TypeScript,\n   \u003e for browser-side code as well as for server-side code.\n\nThat's it: you can now run `npm run dev` (`yarn dev`) and go to [http://localhost:3000/hello/jon](http://localhost:3000/hello/jon).\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## CSS \u0026 Static Assets\n\nTo load a CSS file, simply import it:\n\n~~~js\nimport './path/to/style.css';\n~~~\n\nImporting static assets such as images, fonts, or videos\nreturns an URL:\n\n~~~js\nimport imageUrl from './path/to/image.png';\n// `imageUrl` is the URL that serves `./path/to/image.png`.\n// Do something with imageUrl, e.g. `await fetch(imageUrl)` or `\u003cimg src={imageUrl}/\u003e`.\n~~~\n\nYou can also reference static assets in CSS:\n\n~~~css\n.logo {\n    /* Your file's path on your disk `./path/to/image.png`\n       will automatically be replaced with the URL that serves `./path/to/image.png` */\n    background-image: url('./path/to/image.png');\n}\n@font-face {\n    font-family: 'MyAwesomeFont';\n    /* Your file's path on your disk `./path/to/my-awesome-font.ttf`\n       will automatically be replaced with the URL that serves `./path/to/my-awesome-font.ttf` */\n    src: url('./path/to/my-awesome-font.ttf') format('truetype');\n}\n~~~\n\nExample of a page that uses all kinds of static assets:\n - [/examples/static-assets/](/examples/static-assets/)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Async Data: `addInitialProps`\n\nYou can load and render data by adding an `addInitialProps` function to your page config:\n\n~~~js\nimport React from 'react';\nimport fetchProduct from './fetchProduct';\nimport Product from './Product';\n\nexport default {\n  route: '/product/:productId',\n\n  // Goldpage calls `addInitialProps()` before rendering `view` to HTML or to the DOM.\n  // Alls props returned in `addInitialProps()` are passed to the `view`'s props.\n  addInitialProps: async ({productId}) =\u003e {\n    const product = await fetchProduct(productId);\n    return {product};\n  },\n\n  // The `product` returned by `addInitialProps` is available to `view`.\n  view: initialProps =\u003e {\n    const {product} = initialProps;\n    return (\n      \u003cProduct product={product}/\u003e\n    );\n  },\n\n  // The initial props are also available for generating HTML code.\n  title: initialProps =\u003e {\n    const {product, productId} = initialProps;\n    return (\n      product.name+' ('+productId+')'\n    );\n  },\n\n  renderToHtml: true,\n};\n~~~\n\nAlternatively, you can fetch data in a stateful component.\nBut the page's content is then rendered to the DOM only (and not to HTML).\n\nWe further explain the difference between using a stateful component and `addInitialProps` at:\n - [/examples/async-data/](/examples/async-data/)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## HTML: `index.html`, `\u003chead\u003e`, `\u003cmeta\u003e`, `\u003clink\u003e`, ...\n\nTo set the HTML meta tags of all your pages,\ncreate an `index.html` file somewhere in your project's directory.\nYour `index.html` needs to contain  `!HEAD` and `!BODY`:\n~~~html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    !HEAD\n  \u003c/head\u003e\n  \u003cbody\u003e\n    !BODY\n    \u003cscript src=\"https://example.org/some-lib.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n~~~\n\nTo set the HTML meta tags of only one page, use the page config:\n~~~js\n// /examples/html/pages/products.page.js\n\nimport React from 'react';\nimport logoUrl from './logo.png';\nimport manifestUrl from './manifest.webmanifest';\nimport fetchProduct from './fetchProduct';\nimport Product from './Product';\n\nexport default {\n  view: Product,\n\n  // Goldpage uses the package @brillout/html (https://github.com/brillout/html) to generate HTML.\n  // All @brillout/html's options are available over the page config.\n\n  // Adds \u003ctitle\u003eWelcome\u003c/title\u003e\n  title: 'Product Page',\n\n  // Adds \u003clink rel=\"shortcut icon\" href=\"/logo.hash_85dcecf7a6ad1f1ae4d590bb3078e4b1.png\"\u003e\n  favicon: logoUrl,\n\n  // Adds \u003cmeta name=\"description\" content=\"A welcome page.\"\u003e\n  description: 'Describes a product',\n\n  // Adds \u003cscript src=\"https://example.org/awesome-lib.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n  scripts: [\n    'https://example.org/awesome-lib.js',\n  ],\n\n  // Adds \u003clink href=\"https://example.org/awesome-lib.css\" rel=\"stylesheet\"\u003e\n  styles: [\n    'https://example.org/awesome-lib.css',\n  ],\n\n  // Adds \u003clink rel=\"manifest\" href=\"/manifest.hash_bb5e0038d1d480b7e022aaa0bdce25a5.webmanifest\"\u003e\n  head: [\n    '\u003clink rel=\"manifest\" href=\"'+manifestUrl+'\"/\u003e',\n    // All HTML in this array are added to `\u003chead\u003e`.\n    // Make sure that the HTML you inject here is safe and escape all user generated content.\n  ],\n\n  body: [\n    '\u003cscript\u003econsole.log(\"hello from injected script\")\u003c/script\u003e',\n    // All HTML in this array are added to `\u003cbody\u003e`.\n    // Make sure that the HTML you inject here is safe and escape all user generated content.\n  ],\n\n  // You can also generate HTML dynamically:\n  route: '/products/:productId',\n  addInitialProps: async ({productId}) =\u003e {\n    const product = await fetchProduct(productId);\n    return {product};\n  },\n  title: ({product, productId}) =\u003e product.name+' ('+productId+')',\n  description: ({product}) =\u003e product.description,\n  head: ({product}) =\u003e [\n    // Open Graph tags\n    '\u003cmeta property=\"og:title\" content=\"'+product.name+'\"\u003e',\n    '\u003cmeta property=\"og:description\" name=\"description\" content=\"'+product.description+'\"\u003e',\n  ],\n\n  renderToHtml: true,\n};\n~~~\n~~~js\n// /examples/html/pages/about.page.js\n\nimport React from 'react';\n\nexport default {\n  // `html` allows you to override the `index.html` file for a specific page:\n  html: (\n`\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eTitle set over \\`html\\` option.\u003c/title\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"\u003e\n    !HEAD\n  \u003c/head\u003e\n  \u003cbody\u003e\n    !BODY\n  \u003c/body\u003e\n\u003c/html\u003e\n`\n  ),\n\n  route: '/about',\n  view: () =\u003e \u003ch1\u003eAbout Page\u003c/h1\u003e,\n  renderToHtml: true,\n};\n~~~\n\nSee [`@brillout/html`'s documentation](https://github.com/brillout/html) for the list of all options.\n\nExample:\n - [/examples/html](/examples/html)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## SPA \u0026 MPA\n\n\u003e :information_source: You can use Goldpage without reading this section.\n\n\u003e :warning: This section is meant for readers that know what SPAs and MPAs are.\n\nIf what you want is an MPA\nthen you don't have to do anything:\nGoldpage's default app type is an MPA.\n- By default, your pages are rendered only in the browser. (That is: `renderToDom: true` and `renderToHtml: false`. We explain `renderToHtml` and `renderToDom` at \u003ca href=#where--when-rendertodom-rendertohtml--renderhtmlatbuildtime\u003eWhere \u0026 when: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\u003c/a\u003e.)\n- By default, your pages are routed on the server-side. (We explain what \"server-side routing\" means at \u003ca href=#routing-server-side-routing--browser-side-routing--react-router--vue-router--\u003eRouting: Server-side Routing / Browser-side Routing / React Router / Vue Router / ...\u003c/a\u003e.)\n\nIf what you want is an SPA\nthen:\n- Create a single page with a catch-all route. (That is, create only one page config with `route: '/:param*` to have all URLs routed to this single page.)\n- Use a browser-side routing library such as React Router. (We elaborate more at \u003ca href=#routing-server-side-routing--browser-side-routing--react-router--vue-router--\u003eRouting: Server-side Routing / Browser-side Routing / React Router / Vue Router / ...\u003c/a\u003e.)\n\nNote that an MPA is usually better than an SPA.\nYou most likely want an MPA instead of an SPA.\n(An MPA is basically the same as an SPA but with server-side routing and code-splitting.)\n\nFYI, an SPA is what you get when you use create-react-app, vue-cli, Webpack, or Parcel.\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## SSR\n\n\u003e :information_source: You can use Goldpage without reading this section.\n\n\u003e :warning: This section is meant for readers that know what an SSR app is.\n\nIf you want an SSR app,\nthen:\n- Set `renderToHtml: true` and `renderToDom: true` to all your page configs. (We explain `renderToHtml` and `renderToDom` at \u003ca href=#where--when-rendertodom-rendertohtml--renderhtmlatbuildtime\u003eWhere \u0026 when: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\u003c/a\u003e.)\n\n(FYI, an SSR app is what you get when you use Next.js or Nuxt.js.)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Static Website\n\n\u003e :information_source: You can use Goldpage without reading this section.\n\n\u003e :warning: This section is meant for readers that know what a static website is.\n\nIf you want a static website,\nthen:\n- Set `renderHtmlAtBuildTime: true` to all your page configs. (We explain `renderHtmlAtBuildTime` at \u003ca href=#where--when-rendertodom-rendertohtml--renderhtmlatbuildtime\u003eWhere \u0026 when: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\u003c/a\u003e.)\n\nBy setting `renderHtmlAtBuildTime: true` to all your page configs,\nall browser-side code and assets are generated at built-time.\n\nThis means that no Node.js server is required to serve your frontend and\nyou can deploy your frontend using a static host such as\n[Netlify](https://www.netlify.com/),\n[Amazon S3](https://aws.amazon.com/s3/), or\n[GitHub Pages](https://pages.github.com/).\n\nTo deploy,\nsimply run `$ goldpage build`\n(or better: `npm run build` while `require('./package.json').scripts.build === 'goldpage build'`)\nand deploy the directory `.build/browser/`\n(this is the directory that contains all browser assets)\nto your static host.\n\n(FYI, a static website is what you get when you use Gastby.)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Mixed Apps \u0026 BFA\n\n\u003e :information_source: You can use Goldpage without reading this section.\n\n\u003e :warning: **Prerequisite Knowledge**\n\u003e \u003cbr/\u003e\n\u003e For this section you need to know:\n\u003e \u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp;\n\u003e CSR \u0026 SSR\n\u003e \u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp;\n\u003e `renderToDom` \u0026 `renderToHtml`\n\u003e \u003cbr/\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026#8226;\u0026nbsp;\n\u003e Interactive VS non-interactive\n\u003e \u003cbr/\u003e\n\u003e You can learn all this\n\u003e at [CSR \u0026 SSR Explained](/docs/csr-and-ssr-explained.md#readme).\n\nTools usually implement CSR and SSR in an all-or-nothing way:\neither all your pages are CSR'd or all your pages are SSR'd.\n\nOur `renderToHtml`/`renderToDom` interface gives you a fine grain control \u0026mdash;\nyou can mix CSR and SSR:\none page can be CSR'd (`renderToDom: true` \u0026 `renderToHtml: false`) while another page can be SSR'd (`renderToDom: false` \u0026 `renderToHtml: true`).\n\nFor example,\nif your app is non-interactive with the exception of one interactive page, then\nyou can set CSR for that interactive page (`renderToDom: true` and `renderToHtml: false`) and set SSR for all your other pages (`renderToDom: false` and `renderToHtml: true`).\n\nThis mixing enables a whole new range of app types that where previously not possible to achieve.\n\nFor example,\nwhat we call a *BFA (Backend First App)*.\nThe idea of a BFA is to\nuse React (or Vue)\nprimarily as an HTML template engine and\nonly secondarily to implement interactive views.\nTo achieve:\n- Fast mobile pages\n- High development speed\n- Reliable SEO\nMore at [BFA](/docs/bfa.md#readme).\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Where \u0026 when: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\n\n\u003e :information_source: You can use Goldpage without reading this section.\n\n\u003e :warning: **Prerequisite Knowledge**\n\u003e \u003cbr/\u003e\n\u003e This section requires you to know what CSR and SSR are (which we explain at\n\u003e [CSR \u0026 SSR Explained](/docs/csr-and-ssr-explained.md#readme)).\n\nThere are three page configs that allow you to control when your page is rendered:\n- `renderToDom` - If set to true, your page is rendered in the browser (to the DOM).\n- `renderToHtml` - If set to true, your page is rendered to HTML (in Node.js).\n- `renderHtmlAtBuildTime` - Whether your page is rendered to HTML at request-time or at build-time.\n\nThe default values are `renderToDom: true` and `renderToHtml: false`,\nwhich means that by default your page is rendered only in the browser.\n\nConfiguring these three page configs are about achieving improvements in:\n\n- Search Engines\n  \u003cbr/\u003e\n  All search engines other than Google (Bing, Baidu, Yandex, DuckDuckGo, ...) cannot crawl content rendered to the DOM.\n  If you want your pages to appear in these search engines,\n  then you need to render them to HTML.\n- Google Search\n  \u003cbr/\u003e\n  Google is capable of crawling content rendered to the DOM but with limitations.\n  Rendering your pages to HTML can still be beneficial.\n- Social Sharing Previews\n  \u003cbr/\u003e\n  When your page is shared on a social site (Facebook, Twitter, ...) then a little preview (title, description, and image) of your page is shown.\n  To have a correct preview the meta data of your page needs to be rendered to HTML.\n  (No social site can crawl meta data rendered dynamically to the DOM.)\n- Performance\n  \u003cbr/\u003e\n  Your page's performance can vastly differ depending on whether your page is rendered to the DOM and/or to HTML.\n- Mobile Performance\n  \u003cbr/\u003e\n  Browser-side JavaScript is a performance killer for low-end devices such as mobile phones.\n  On mobile,\n  rendering your page to HTML is drastically faster then rendering it to the DOM.\n\nAt\n[Client-side Rendering (CSR) VS Server-side Rendering (SSR)](/docs/csr-vs-ssr.md#readme),\nwe elaborate how to set `renderToHtml`, `renderToDom` and `renderHtmlAtBuildTime`\nin order to achieve improvements in the above points.\nBut before you learn more about these page configs and what you can achieve with them,\nwe recommend that you first implement a prototype and learn more only after you need improvements in the above mentioned points.\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## How: `htmlRender` \u0026 `domRender`\n\nYou can control how your pages are rendered\nto HTML and the DOM.\n\nFor that,\nsave a `goldpage.config.js` file at your project's root directory\n(the directory that contains your `package.json`)\nand add the `htmlRender` and `domRender` configs:\n~~~js\n// goldpage.config.js\n\nmodule.exports = {\n  htmlRender: './render/htmlRender.js',\n  domRender: './render/domRender.js',\n};\n~~~\n\nThen create the `domRender` and `htmlRender` files.\n\nWith React:\n\n~~~js\n// render/domRender.js\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\n\nexport default domRender;\n\nasync function domRender({page, initialProps, CONTAINER_ID}) {\n  const element = React.createElement(page.view, initialProps);\n  const container = document.getElementById(CONTAINER_ID);\n  if( page.renderToHtml ){\n    ReactDOM.hydrate(element, container);\n  } else {\n    ReactDOM.render(element, container);\n  }\n}\n~~~\n\n~~~js\n// render/htmlRender.js\n\nconst React = require('react');\nconst ReactDOMServer = require('react-dom/server');\n\nmodule.exports = htmlRender;\n\nasync function htmlRender({page, initialProps, CONTAINER_ID}) {\n  const html = (\n    ReactDOMServer.renderToStaticMarkup(\n      React.createElement(page.view, initialProps)\n    )\n  );\n\n  // Altnertively, you can return a `@brillout/html` options object\n  // in order to have more control over the generated HTML. See all\n  // html options at https://github.com/brillout/html\n  // return {\n  //   head: [\n  //     '\u003cstyle\u003ebody{background: blue;}\u003c/style\u003e',\n  //   ],\n  //   body: [\n  //     '\u003cdiv\u003eSome additional HTML\u003c/div\u003e',\n  //     '\u003cdiv id=\"'+CONTAINER_ID+'\"\u003e'+html+'\u003c/div\u003e',\n  //   ]\n  // };\n\n  return html;\n}\n~~~\n\nThis allows you to add providers such as Redux's `\u003cProvider store={store} /\u003e` or React Router's `\u003cBrowserRouter /\u003e`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\nWith Vue\n\u003c/summary\u003e\n\n~~~js\n// render/domRender.js\n\nimport Vue from 'vue';\nimport getVueInstance from './getVueInstance';\n\nexport default domRender;\n\nasync function domRender({page, initialProps, CONTAINER_ID}) {\n  const vm = getVueInstance(page.view, initialProps);\n\n  vm.$mount('#'+CONTAINER_ID);\n}\n~~~\n\n~~~js\n// render/htmlRender.js\n\nconst VueServerRenderer = require('vue-server-renderer');\nconst getVueInstance = require('./getVueInstance');\n\nmodule.exports = htmlRender;\n\nasync function htmlRender({page, initialProps}) {\n  const renderer = VueServerRenderer.createRenderer();\n\n  const vm = getVueInstance(page.view, initialProps);\n\n  const html = await renderer.renderToString(vm);\n\n  return html;\n}\n~~~\n\n~~~js\n// render/getVueInstance.js\n\nlet Vue = require('vue');\nVue = Vue.default || Vue;\n\nmodule.exports = getViewInstance;\n\nfunction getViewInstance(view, initialProps) {\n  if( view instanceof Function ){\n    return view(initialProps);\n  } else {\n    return (\n      new Vue({\n        render: createElement =\u003e createElement(view, {props: initialProps}),\n      })\n    );\n  }\n}\n~~~\n\nThis allows you to add providers such as for Vuex or Vue Router.\n\u003c/details\u003e\n\nExamples:\n- [/examples/react-router](/examples/react-router)\n- [/examples/redux](/examples/redux)\n- [/examples/styled-components](/examples/styled-components)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Page Config `*.page.js`\n\nThe following page config showcases an overview of the available page configs.\n\n~~~js\n// pages/*.page.js\n\nimport React from 'react';\nimport fetchProduct from './fetchProduct';\nimport getHtmlOptions from './getHtmlOptions';\nimport assert_initialProps from './assert_initialProps';\nimport Product from './Product';\n\nexport default getPageConfig();\n\nfunction getPageConfig() {\n  return {\n    // The url of the page.\n    // The routing is done by `path-to-regexp` (https://github.com/pillarjs/path-to-regexp).\n    route: '/product-details/:productId',\n\n    // Add additional inital props, for example data loaded from an API.\n    // `addInitialProps` can be async and Goldpage awaits `addInitialProps` before\n    // rendering `view` to the DOM / HTML.\n    addInitialProps,\n\n    // The content of your page.\n    // `view` is rendered by the render plugin you installed.\n    view: Product,\n\n    // Control when the page is rendered.\n    // More in a section below.\n    renderToDom: true, // (default value)\n    renderToHtml: false, // (default value)\n    renderHtmlAtBuildTime: false, // default value\n\n    // The definition of `getHtmlOptions` is shown in a section below\n    // and shows all HTML configs.\n    ...getHtmlOptions()\n  };\n}\n\nasync function addInitialProps(initialProps) {\n  // The definition of `assert_initialProps` is shown in a section below\n  // and shows all `initialProps`.\n  assert_initialProps(initialProps);\n\n  const {productId} = initialProps;\n\n  const product = await fetchProduct(productId);\n\n  return {product};\n}\n~~~\nWe now list all configs.\n\n\n- \u003ca href=#all-initial-props-initialprops\u003eAll initial props `initialProps`\u003c/a\u003e\n- \u003ca href=#all-page-configs-for-the-pages-html-document\u003eAll page configs for the page's HTML document\u003c/a\u003e\n- \u003ca href=#all-render-page-configs-rendertodom-rendertohtml--renderhtmlatbuildtime\u003eAll render page configs: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\u003c/a\u003e\n\n##### All initial props `initialProps`\n\nThis `initialProps` assertion showcases all `initialProps`.\n\n~~~js\nimport assert from '@brillout/reassert';\n\nexport default assert_initialProps;\n\nfunction assert_initialProps(initialProps){\n  const {\n    // Route arguments\n    productId,\n\n    // Query paramaters\n    productColor,\n\n    // Whether the code is being run in Node.js or in the browser\n    isNodejs,\n\n    // URL props\n    url,\n    origin,\n    protocol,\n    hostname,\n    port,\n    pathname,\n    query,\n    queryString,\n    hash,\n\n    // The request object is available here.\n    // The page config as well.\n    // See below.\n    ...initialProps__rest\n  } = initialProps;\n\n  assert.internal(url.startsWith('http'));\n  if( url==='http://localhost:3000/products/123?productColor=blue#reviews' ){\n    // Url params\n    assert(productId==='123');\n    assert(productColor==='blue');\n\n    // Url props\n    assert(origin==='http://localhost:3000');\n    assert(protocol==='http:');\n    assert(hostname==='localhost');\n    assert(port==='3000');\n    assert(pathname==='/products/123');\n    assert(query.productColor==='blue');\n    assert(queryString==='?productColor=blue');\n    assert(hash==='#reviews');\n  }\n\n  assert([true, false].includes(isNodejs));\n\n  // The server framework's request object is also available.\n  // For example, to get the HTTP request headers `req.headers`:\n  const {headers} = initialProps__rest;\n\n  // The page config is available at `initialProps`\n  assert(initialProps__rest.route);\n  assert(initialProps__rest.view);\n\n  // Since all props are flat-merged into one object, there can be conflicts.\n  // In case of a prop name conflict, you can access all props over `__sources`.\n  const {__sources} = initialProps;\n  // Props returned by `addInitialProps`\n  assert(__sources.addInitialProps__result===null || __sources.addInitialProps__result.product);\n\n  // The request object returned by your server framework (Express / Koa / Hapi / ...)\n  assert(isNodejs===false || __sources.requestObject);\n  assert(isNodejs===false || __sources.requestObject.headers);\n\n  // The url props returned by `@brillout/parse-url` (https://github.com/brillout/parse-url)\n  assert(__sources.urlProps);\n\n  // The route params\n  assert(__sources.routeArguments);\n  assert(__sources.routeArguments.productId);\n\n  // The page config\n  assert(__sources.pageConfig);\n  assert(__sources.pageConfig.route);\n  assert(__sources.pageConfig.view);\n\n  // Whether the code is running on the server or in the browser.\n  assert(__sources.isNodejs===isNodejs);\n}\n~~~\n\n##### !VAR HTML_CONFIGS\n\nList of all HTML configs:\n\n~~~js\nimport manifestUrl from './manifest.webmanifest';\n\nexport default getHtmlOptions;\n\nfunction getHtmlOptions() {\n  // Goldpage uses `@brillout/html` (https://github.com/brillout/html) to generate HTML.\n  // All `@brillout/html` options are available over the page config.\n\n  return {\n    // Adds \u003ctitle\u003eTitle shown in browser tab.\u003c/title\u003e\n    title: 'Title shown in browser tab.',\n    /* Altneratively:\n    title: initialProps =\u003e {\n      assert_initialProps(initialProps);\n      // Props returned by `addInitialProps` are also available to the `@brillout/html` options\n      return initialProps.product.product.name;\n    },\n    */\n\n    // \u003cmeta name=\"description\" content=\"Description of page shown in search engines.\"\u003e\n    description: 'Description of page shown in search engines.',\n    /*\n    // Not only `title` but all options can be dynmically generated with a function\n    description: initialProps =\u003e initialProps.product.product.name,\n    */\n\n    // \u003clink rel=\"shortcut icon\" href=\"/logo.hash_85dcecf7a6ad1f1ae4d590bb3078e4b1.png\"\u003e\n    favicon: require('./logo.png'),\n\n    head: [\n      '\u003clink rel=\"manifest\" href=\"'+manifestUrl+'\"\u003e',\n    ],\n    body: [\n      '\u003cscript\u003econsole.log(\"hello from injected script\")\u003c/script\u003e',\n    ],\n    /* Again, we can use a function to dynammically generate HTML.\n    body: initialProps =\u003e {\n      return [\n        '\u003cscript\u003econsole.log(\"hello from '+initialProps.product.productname+' page.\")\u003c/script\u003e',\n      ];\n    },\n    */\n\n    // You can fully control the HTML:\n    html: (\n`\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"\u003e\n    !HEAD\n  \u003c/head\u003e\n  \u003cbody\u003e\n    !BODY\n  \u003c/body\u003e\n\u003c/html\u003e\n`\n    ),\n    /* Dynammically as well:\n    html: initialProps =\u003e '...',\n    */\n\n    // See https://github.com/brillout/html for the list of all options\n  };\n}\n~~~\n\n##### All render page configs: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\n\nA page has three render configs:\n - `renderToDom`\n - `renderToHtml`\n - `renderHtmlAtBuildTime`\n\nIn this section we only explain what each config does.\nAt \u003ca href=#where--when-rendertodom-rendertohtml--renderhtmlatbuildtime\u003eWhere \u0026 when: `renderToDom`, `renderToHtml` \u0026 `renderHtmlAtBuildTime`\u003c/a\u003e we explain how to set these three render configs.\n\n###### `renderToDom`\n\nWith `renderToDom` you control whether your page is rendered in the browser (to the DOM).\n\n- `renderToDom: true` (default value)\n  - Slower Performance.\n    \u003cbr/\u003e\n    The page's views (e.g. React components) and view libraries (e.g. React) are loaded, executed, and rendered in the browser.\n    This can be very slow on mobile devices.\n  - Interactive.\n    \u003cbr/\u003e\n    Because your page is rendered to the browser's DOM, your page's views (e.g. React components) can be stateful and interactive.\n- `renderToDom: false`\n  - Increased performance.\n    \u003cbr/\u003e\n    The page's views and view libraries are not loaded nor executed in the browser.\n    Considerably less JavaScript is loaded/executed in the browser.\n    A page that has (or very little) browser-side JavaScript is blazing fast on mobile.\n  - Non-interactive.\n    \u003cbr/\u003e\n    Because your page is not rendered to the browser's DOM, your page connot have stateful views / interactive views.\n\nIn a nutshell:\nIf your page is interactive then you have to render it in the browser and set `renderToDom` to `true`.\nBut if your page isn't interactive then you can set `renderToDom` to `false` for increased performance and a blazing fast page on mobile devices.\n\n###### `renderToHtml`\n\nWith `renderToDom` you control whether your page is rendered to HTML (in Node.js).\n\n- `renderToHtml: false` (default value)\n  \u003cbr/\u003e\n  Your page's `view` component is not rendered to HTML.\n- `renderToHtml: true`\n  \u003cbr/\u003e\n  Your page's `view` component is rendered to HTML.\n\n###### `renderHtmlAtBuildTime`\n\nWith `renderHtmlAtBuildTime` you can control whether the page's HTML is\nrendered statically at build-time or\ndynamically at request-time.\n\n- `renderHtmlAtBuildTime: false` (default value)\n  \u003cbr/\u003e\n  The page is rendered to HTML at request-time.\n  \u003cbr/\u003e\n  The page is (re-)rendered to HTML every time the user requests the page.\n- `renderHtmlAtBuildTime: true`\n  \u003cbr/\u003e\n  The page is rendered to HTML at build-time.\n  \u003cbr/\u003e\n  The page is rendered to HTML only once, when Goldpage transpiles and builds your pages.\n\nBy default,\na page is rendered to HTML at request-time.\nBut if the page's content is static\n(a landing page, an about page, a blog post, a personal homepage, etc.)\nit is wasteful to re-render its HTML on every page request.\n\nBy setting `renderHtmlAtBuildTime: true` to all your pages,\nyou can remove the need for a Node.js server\nand have your frontend be a static website.\nYou can then deploy your frontend to a static host such as Netlify or GitHub Pages.\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Goldpage Config `goldpage.config.js`\n\nWe try to keep Goldpage as zero-config as possible\nand `ssr.config.js` has only few options.\n\n~~~js\n// ssr.config.js\n\nmodule.exports = {\n  // Control how pages are rendered. (See section \"How: `htmlRender` \u0026 `domRender`\").\n  htmlRender: require.resolve('./path/to/your/htmlRender'),\n  domRender: require.resolve('./path/to/your/domRender'),\n\n  // Make Goldpage silent in the terminal (but it will still prints errors).\n  silent: true,\n};\n~~~\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## CLI\n\nGoldpage has two commands:\n\n- ~~~shell\n  $ goldpage dev ./path/to/your/server.js\n  ~~~\n  The `dev` command starts your server with auto-reload:\n  whenever you make a change to your code,\n  your code is rebuilt and the pages open in your browser are reloaded.\n  The `dev` command is meant to be used while you develop your app.\n\n- ~~~shell\n  $ goldpage build ./path/to/your/server.js\n  ~~~\n  The `build` command builds your code for production.\n  (E.g. it minifies your browser-side code whereas the `dev` command doesn't.)\n  Once `build` is finished you can repeatedly start and shut down your server.\n  If your server-side code is written in JavaScript then you can call your server entry directly: `$ node ./path/to/your/server.js`.\n  If not, then run the transpiled version which is located in the `.build` directory: `$ node ./build/nodejs/server.js`.\n\nDo not install Goldpage globally and do not call the Goldpage CLI directly.\nUse your `package.json`'s `scripts` instead:\n\n~~~json\n{\n  \"dependencies\": {\n    \"goldpage\": \"^0.3.3\",\n  },\n  \"scripts\": {\n    \"dev\": \"goldpage dev ./path/to/your/server.js\",\n    \"prod\": \"npm run build \u0026\u0026 npm run start\",\n    \"build\": \"goldpage build ./path/to/your/server.js\",\n    \"start\": \"export NODE_ENV='production' \u0026\u0026 node ./.build/nodejs/server\"\n  }\n}\n~~~\n\nYou can then install a local Goldpage copy (`$ npm install` / `$ yarn`) and\nthen call `$ npm run dev` (/ `$ yarn dev`).\n\nA local install has couple of advantages over a global install:\n - Many projects can have many different Goldpage versions.\n - Removing your project's directory also removes Goldpage.\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Providers: Redux / React Router / Vuex / Vue Router / GraphQL Apollo / Relay / ...\n\nBy controlling the rendering of your pages you can add providers for Redux, GraphQL, etc.\n\nSee \u003ca href=#how-htmlrender--domrender\u003eHow: `htmlRender` \u0026 `domRender`\u003c/a\u003e for how to take over control of the rendering of your pages.\n\nExamples:\n- [/examples/react-router](/examples/react-router)\n- [/examples/redux](/examples/redux)\n- [/examples/styled-components](/examples/styled-components)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n## Transpilation: Babel / TypeScript /  ES6 / ...\n\nYou can configure Babel and the JavaScript transpilation by creating a `.babelrc` file.\nSee [/examples/babel](/examples/babel) for an example of configuring babel.\n\nGoldpage currently uses Webpack.\nThis means that for custom transpilations beyond babel, modifications to Goldpage's webpack config are required.\nInstead of modifying Goldpage's webpack config yourself,\nsee if there is a [transpilation plugin](/plugins#transpilation-plugins)\nthat modifies Goldpage's webpack config for you.\nFor exampe, for TypeScript, you can use the [TypeScript plugin](/plugins/typescript).\nIf there is no plugin for what you need, then open a GitHub issue and we'll create one together.\n\nOnce Parcel v2 is released,\nGoldpage will use Parcel instead of Webpack.\nSince Parcel is zero-config, most of your transpilation needs will then just work.\n(Transpilation plugins will not be required anymore.)\n\nExamples:\n- [/examples/typescript](/examples/typescript)\n- [/examples/babel](/examples/babel)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## CSS-in-JS: Emotion / styled-components / ...\n\nSome CSS-in-JS libraries,\nsuch as [emotion](https://github.com/emotion-js/emotion),\nwork with SSR out of the box and no additional setup is required.\n\nFor some others,\nsuch as [styled-components](https://github.com/styled-components/styled-components),\nyou make need to\n[take control over rendering](#how-htmlrender--domrender).\n\nExamples:\n- [/examples/emotion](/examples/emotion)\n- [/examples/styled-components](/examples/styled-components)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## CSS pre-processors: PostCSS / Sass / Less / ...\n\nIf there is a [transpilation plugin](/plugins#transpilation-plugins) for the CSS pre-processor you want to use,\nthen simply use it.\n\nIf there isn't one,\nthen see [controlling transpilation](#transpilation-babel--typescript---es6--).\n\nExample:\n - [/examples/postcss](/examples/postcss)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Routing: Server-side Routing / Browser-side Routing / React Router / Vue Router / ...\n\nOn the web, there are two ways to do routing:\n*server-side routing*\nand\n*browser-side routing*.\n\n###### Server-side Routing\n\nRoutes defined in your page configs\n\n~~~jsx\nimport React from 'react';\n\nexport default {\n  route: '/hello/:name',\n  view: ({name}) =\u003e (\n    \u003cdiv\u003e\n      Welcome {name}.\n    \u003c/div\u003e\n  ),\n};\n~~~\n\nare server-side routes:\nwhen navigating from `/hello/jon` to `/hello/alice`\nthe browser terminates the current `/hello/jon` page and starts a new page `/hello/alice`.\nIt is the same as if you would close your `/hello/jon` tab and open a new tab at `/hello/alice`.\n\nIt is the server that does the job of mapping URLs to pages and the browser is not involved in the routing process.\n\n###### Browser-side Routing\n\nHTML5 introduced a new browser API `window.history` that allows you to manipulate the browser URL history.\nThis enables browser-side routing:\nwhen navigating from `/previous-page` to `/next-page`, instead of terminating the current page `/previous-page` and starting a new page `/next-page`, the current page `/previous-page` is preserved, its URL changed to `/next-page` (with `window.history.pushState()`), and the content of `/next-page` is rendered to the DOM replacing the DOM of `/previous-page`.\n\nServer-side routing is simpler than browser-side routing;\nwhenever possible, server-side routing should be used instead of browser-side rendering.\n\nBut if server-side routing is not an option,\nyou can opt to do browser-side routing\nby [taking control over rendering](#how-htmlrender--domrender).\n\nFor example,\nif you use React,\nyou can take control over rendering in order to use React Router which does browser-side routing:\n\n~~~js\n// /examples/react-router/render/domRender.js\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\n\nexport default domRender;\n\nasync function domRender({page, initialProps, CONTAINER_ID}) {\n  ReactDOM.hydrate(\n    \u003cBrowserRouter\u003e\n      \u003cpage.view {...initialProps}/\u003e\n    \u003c/BrowserRouter\u003e,\n    document.getElementById(CONTAINER_ID)\n  );\n}\n~~~\n\n~~~js\n// /examples/react-router/render/htmlRender.js\n\nconst React = require('react');\nconst ReactDOMServer = require('react-dom/server');\nconst {StaticRouter} = require('react-router');\n\nmodule.exports = htmlRender;\n\nasync function htmlRender({page, initialProps}) {\n  const {pathname, search, hash} = initialProps;\n  return (\n    ReactDOMServer.renderToStaticMarkup(\n      React.createElement(\n        StaticRouter,\n        {location: {pathname, search, hash, state: undefined}, context: {}},\n        React.createElement(\n          page.view,\n          initialProps\n        )\n      )\n    )\n  );\n}\n~~~\n\n~~~js\n// /examples/react-router/goldpage.config.js\n\nmodule.exports = {\n  htmlRender: './render/htmlRender.js',\n  domRender: './render/domRender.js',\n};\n~~~\n\nThe example's entire source code is at:\n- [/examples/react-router](/examples/react-router)\n\nMore Resources:\n- [Understanding client side routing by implementing a router in Vanilla JS](http://willtaylor.blog/client-side-routing-in-vanilla-js/)\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Frontend Libraries: Google Analytics / jQuery / Bootstrap / Semantic UI / ...\n\nTo load a frontend library that is hosted on a cdn, add `\u003cscript\u003e`/`\u003cstyle\u003e` tags to your HTML, see \u003ca href=#html-indexhtml-head-meta-link-\u003eHTML: `index.html`, `\u003chead\u003e`, `\u003cmeta\u003e`, `\u003clink\u003e`, ...\u003c/a\u003e.\n\nTo load a frontend library that is saved on disk, use a file that is loaded by all your pages:\n\n~~~js\n// /examples/frontend-libraries/pages/commons.js\n\nif(\n  // Do not load the frontend libraries on the server\n  isBrowser()\n){\n  require('../frontend/normalize.css');\n  require('../frontend/style.css');\n  require('../frontend/google-analytics.js');\n}\n\nfunction isBrowser() {\n  return typeof window !== \"undefined\";\n}\n~~~\n~~~js\n// /examples/frontend-libraries/pages/landing.page.js\n\nrequire('./commons.js');\n\nimport React from 'react';\n\nexport default {\n  route: '/',\n  view: () =\u003e \u003ch1\u003eLanding Page\u003c/h1\u003e,\n  renderToHtml: true,\n};\n~~~\n~~~js\n// /examples/frontend-libraries/pages/about.page.js\n\nrequire('./commons.js');\n\nimport React from 'react';\n\nexport default {\n  route: '/about',\n  view: () =\u003e \u003ch1\u003eAbout Page\u003c/h1\u003e,\n  renderToHtml: true,\n};\n~~~\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Server: Express / Koa / Hapi / Fastify / ...\n\nTo use Goldpage with `express`, `koa` or `hapi`, use the corresponding [server plugin](/plugins#server-plugins).\n\nTo use Goldpage with another server framework, open a GitHub issue.\nGoldpage can be used with any server framework\nbut there is no documentation for this (yet).\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## View Libraries: React / Vue / Preact / ...\n\nIf there is a [render plugin](/plugins#render-plugins) for the view library you want to use,\nthen simply use it.\n\nIf there is no render plugin,\nthen [take control over rendering](#how-htmlrender--domrender).\nThat way you are able to use any view library.\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n## Process Managers: Docker / systemd / PM2 / ...\n\nYou can start your server with any process manager.\n\nFor example with `pm2`:\n\n~~~bash\npm2 start ./.build/nodejs/server\n~~~\n\nIf you don't transpile your server code (see !VAR|LINK),\nthen use your server entry file:\n\n~~~bash\npm2 start ./path/to/your/server.js\n~~~\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003csup\u003e\n\u003ca href=\"https://github.com/reframejs/goldpage/issues/new\"\u003eOpen a ticket\u003c/a\u003e or\n\u003ca href=\"https://discord.gg/kqXf65G\"\u003echat with us\u003c/a\u003e\nif you have questions, feature requests, or if you just want to talk to us.\n\u003c/sup\u003e\n\n\u003csup\u003e\nWe enjoy talking with our users :-).\n\u003c/sup\u003e\n\n\u003cbr/\u003e\n\n\u003csup\u003e\n\u003ca href=\"#readme\"\u003e\u003cb\u003e\u0026#8679;\u003c/b\u003e \u003cb\u003eTOP\u003c/b\u003e \u003cb\u003e\u0026#8679;\u003c/b\u003e\u003c/a\u003e\n\u003c/sup\u003e\n\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n\n\n\u003c!---\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n\n\n\n\n\n\n    WARNING, READ THIS.\n    This is a computed file. Do not edit.\n    Instead, edit `/docs/readme.template.md` and run `npm run docs` (or `yarn docs`).\n\n\n\n\n\n\n--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrillout%2Fgoldpage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrillout%2Fgoldpage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrillout%2Fgoldpage/lists"}