From 7d78429693476976a0a7d4f136e57fad9cd19642 Mon Sep 17 00:00:00 2001 From: Aaron Carlino Date: Tue, 19 Nov 2019 13:55:33 +1300 Subject: [PATCH] Live markdown updates --- README.md | 46 +++++++++++++++++++++++++-------- gatsby-config.js | 8 +++--- gatsby-node.js | 29 +++++++++++++++++---- src/templates/docs-template.tsx | 12 +++++---- src/types/index.ts | 4 ++- src/utils/cleanApiTags.ts | 4 +-- src/utils/cleanCalloutTags.ts | 2 +- 7 files changed, 76 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 919c160..aae69d4 100644 --- a/README.md +++ b/README.md @@ -28,18 +28,17 @@ To set up a local instance of [doc.silverstripe.org](https://github.com/silverst ``` git clone https://github.com/silverstripe/doc.silverstripe.org path/to/ssdocs ``` -will clone this repository into `path/to/ssdocs`. -* From within `path/to/ssdocs`, run the command -``` -gatsby develop -``` -to instantiate a development server. This will consume all of the markdown files in both major release -branches and allow you to browse the documentation site on `http://localhost:8000` by default -(see the [Gatsby docs](https://www.gatsbyjs.org/docs/) for instructions on customising the port). ## Building -To test a static build of the site +To test a static build of the site, first create a production environment file. + +``` +cp .env.development .env.production +``` + +Then, run the build. + ``` gatsby build gatsby serve @@ -48,15 +47,40 @@ gatsby serve These commands will give you an exact representation of how the site will run on a production server, with statically generated html files and server-side rendering. -## Deploying +## Developing + +From within `path/to/ssdocs`, run the command + +``` +gatsby develop +``` +to instantiate a development server. This will consume all of the markdown files in both major release +branches and allow you to browse the documentation site on `http://localhost:8000` by default +(see the [Gatsby docs](https://www.gatsbyjs.org/docs/) for instructions on customising the port). + +## Authoring + +You can make changes directly to the source markdown files and get live updates in the development +server without having to rebuild the app or even refresh the browser. The clones of the `silverstripe/framework` +repositories are in the `.cache/gatsby-source-git` folder in the root of this project. There are subfolders +for `3/` and `4/`, respective to their branch names. You can edit the files in `docs/en` from there. + +Just don't forget to merge your changes upstream once you're done. Building the gatsby app will not preserve +your content changes, since the remote repositories are the source of truth. + +## Deploying content changes Once your contribution has been merged into the master branch, you can run a build hook to trigger a new build in Netlify. ``` -(build hook coming soon) +curl -X POST -d {} https://api.netlify.com/build_hooks/5dd225fffdc558cbf6a23490 ``` +## Deploying app changes + +Once your change is merged in to the `master` branch of this repository, it will be deployed live within minutes. + ## Contribution To contribute an improvement to the https://docs.silverstripe.org functionality or diff --git a/gatsby-config.js b/gatsby-config.js index 8c8c4ac..932dbf6 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -33,15 +33,15 @@ module.exports = { { resolve: `gatsby-source-filesystem`, options: { - name: `ss3-files`, - path: `${__dirname}/.cache/gatsby-source-git/3` + name: `watcher--ss3`, + path: `${__dirname}/.cache/gatsby-source-git/3/docs/en` } }, { resolve: `gatsby-source-filesystem`, options: { - name: `ss4-files`, - path: `${__dirname}/.cache/gatsby-source-git/4` + name: `watcher--ss4`, + path: `${__dirname}/.cache/gatsby-source-git/4/docs/en` } }, { diff --git a/gatsby-node.js b/gatsby-node.js index 9b1083f..af61f75 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -12,18 +12,37 @@ const createSlug = (filePath, version) => { .toLowerCase() }; -exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) => { +exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNodeId, createContentDigest }) => { if (node.internal.type !== 'MarkdownRemark') { return; } const { createNode } = actions; const fileNode = getNode(node.parent); const version = fileNode.sourceInstanceName; + + // The gatsby-source-filesystem plugins are registered to collect from the same path + // that the git source writes to, so we get the watch task (hot reload on content changes) + // But we don't want duplicate document pages for each source plugin, so + // we bail out if we already have the file. However, we need to ensure + // the file is injected into the template as a dependency, so when the content changes, + // the pages get refreshed on the fly. + if (version.match(/^watcher--/)) { + const existing = getNodesByType('SilverstripeDocument') + .find(n => n.fileAbsolutePath === node.fileAbsolutePath); + + if (existing) { + // Pair the document with its watched file so we can inject it into the template + // as a dependency. + existing.watchFile___NODE = node.id; + return; + } + } + const filePath = createFilePath({ node, getNode, basePath: `docs` - }); + }); let fileTitle = path.basename(node.fileAbsolutePath, '.md'); const isIndex = fileTitle === 'index'; if (isIndex) { @@ -32,7 +51,7 @@ exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) = const docTitle = fileToTitle(fileTitle); const slug = createSlug(filePath, version); const parentSlug = `${path.resolve(slug, '../')}/`; - + const docData = { isIndex, filePath, @@ -55,11 +74,11 @@ exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) = }; const nodeData = { ...node, - id: `ss-doc-${node.id}`, + id: createNodeId(`SilverstripeDocument${node.id}`), ...docData, parent: node.id, internal: docInternal, - } + } createNode(nodeData); }; diff --git a/src/templates/docs-template.tsx b/src/templates/docs-template.tsx index 54e97a6..bfe101a 100644 --- a/src/templates/docs-template.tsx +++ b/src/templates/docs-template.tsx @@ -7,7 +7,7 @@ import { setCurrentNode } from '../utils/nodes'; const Template: StatelessComponent = (result): ReactElement => { const currentNode = result.data.silverstripeDocument; - const { html } = currentNode.parent; + const { html } = currentNode.watchFile; const { title, slug } = currentNode; const { relativePath, gitRemote: { ref, webLink } } = currentNode.parent.parent; const editLink = `${webLink}/edit/${ref}/${relativePath}`; @@ -35,9 +35,14 @@ export default Template; export const pageQuery = graphql` query DocsBySlug($slug: String!) { silverstripeDocument(slug: { eq: $slug }) { + title + slug + id + watchFile { + html + } parent { ... on MarkdownRemark { - html parent { ... on File { relativePath @@ -51,9 +56,6 @@ export const pageQuery = graphql` } } - title - slug - } } ` diff --git a/src/types/index.ts b/src/types/index.ts index fddb05f..4ea1323 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -7,8 +7,10 @@ export interface SingleFileQuery { export interface SinglePage { title: string; slug: string; - parent: { + watchFile: { html: string; + } + parent: { parent: { relativePath: string; gitRemote: { diff --git a/src/utils/cleanApiTags.ts b/src/utils/cleanApiTags.ts index 253edc3..e2f2820 100644 --- a/src/utils/cleanApiTags.ts +++ b/src/utils/cleanApiTags.ts @@ -1,7 +1,7 @@ const cleanApiTags = (html: string): string => { return html.replace( - /\[api:(.*?)\][^(]/g, - (_, query) => `${query} ` + /\[api:(.*?)\]([^(])/g, + (_, query, next) => `${query}${next}` ) }; diff --git a/src/utils/cleanCalloutTags.ts b/src/utils/cleanCalloutTags.ts index d932dbf..60b6146 100644 --- a/src/utils/cleanCalloutTags.ts +++ b/src/utils/cleanCalloutTags.ts @@ -14,7 +14,7 @@ const getCalloutClass = (type: string): string => { }; const cleanCalloutTags = (html: string): string => { return html.replace( - /(?:

\s*)?(\[(hint|warning|info|alert|notice|note)\])(.*?)(\[\/(hint|warning|info|alert|notice|note)\])(?:<\/p>)?/gs, + /(?:

\s*)(\[(hint|warning|info|alert|notice|note)\])(.*?)(\[\/(hint|warning|info|alert|notice|note)\])(?:\s*<\/p>)/gs, (_, tag, type, content) => `