Skip to content

Commit 9054fe6

Browse files
Create new React + Node example with Vite (#122)
* Rename legacy react-nodejs example to create-react-app * Set up basic client and server * Ignore package-lock.json * Transfer example files from the create-react-app example * Tweak imports * Add README * Remove package-lock.json * Remove unnecessary info * Tweak README verbiage * Update examples/react-nodejs/package.json Co-authored-by: maxblank-stripe <[email protected]> * Update examples/react-nodejs/vite.config.js Co-authored-by: maxblank-stripe <[email protected]> * Update examples/react-nodejs/server.js Co-authored-by: maxblank-stripe <[email protected]> * Add package-lock.json file * Set up basic production build * Update README to reflect new scripts --------- Co-authored-by: maxblank-stripe <[email protected]>
1 parent 5c3cb88 commit 9054fe6

28 files changed

+6017
-82
lines changed

examples/create-react-app/.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*

examples/create-react-app/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# React example
2+
3+
This example builds a client-side rendered React app that fetches Markdoc ASTs from an [Express.js](https://expressjs.com/) server.
4+
This project was built with `create-react-app`.
5+
6+
## Setup
7+
8+
To get started, run:
9+
10+
`npm run start`
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
route: '/'
3+
---
4+
5+
# Home
6+
7+
{% callout type="warning" %}
8+
This is a warning callout!
9+
{% /callout %}
10+
11+
{% callout type="caution" %}
12+
This is a caution callout!
13+
{% /callout %}
14+
15+
```js
16+
const x = 'test';
17+
```
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
route: '/variables'
3+
---
4+
5+
There a message under this line. Can you figure out how to get it to show up?
6+
7+
{% if $flags.show_secret_feature %}
8+
This is special hidden text!
9+
{% /if %}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const fs = require('fs');
2+
const yaml = require('js-yaml');
3+
const glob = require('glob');
4+
const Markdoc = require('@markdoc/markdoc');
5+
6+
const parseMarkdocFrontmatter = (ast) => {
7+
return ast.attributes.frontmatter
8+
? yaml.load(ast.attributes.frontmatter)
9+
: {};
10+
};
11+
12+
// This creates a mapping between route and parsed Markdoc content.
13+
exports.createContentManifest = (ROOT_DIR) => {
14+
const files = glob.sync(`${ROOT_DIR}/**/*.md`);
15+
16+
const contentManifest = {};
17+
18+
files.forEach((file) => {
19+
const rawText = fs.readFileSync(file, 'utf-8');
20+
const ast = Markdoc.parse(rawText);
21+
const frontmatter = parseMarkdocFrontmatter(ast);
22+
23+
contentManifest[frontmatter.route] = {
24+
ast,
25+
frontmatter
26+
};
27+
});
28+
29+
return contentManifest;
30+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"private": true,
3+
"dependencies": {
4+
"@markdoc/markdoc": "latest",
5+
"@testing-library/jest-dom": "^5.16.4",
6+
"@testing-library/react": "^13.1.1",
7+
"@testing-library/user-event": "^13.5.0",
8+
"glob": "^8.0.1",
9+
"js-yaml": "^4.1.0",
10+
"react": "^18.0.0",
11+
"react-dom": "^18.0.0",
12+
"react-scripts": "5.0.1",
13+
"web-vitals": "^2.1.4"
14+
},
15+
"scripts": {
16+
"start:client": "react-scripts start",
17+
"start:server": "node server.js",
18+
"start": "concurrently \"yarn start:client\" \"yarn start:server\"",
19+
"build": "react-scripts build",
20+
"test": "react-scripts test",
21+
"eject": "react-scripts eject"
22+
},
23+
"eslintConfig": {
24+
"extends": [
25+
"react-app",
26+
"react-app/jest"
27+
]
28+
},
29+
"proxy": "http://localhost:4242",
30+
"browserslist": {
31+
"production": [
32+
">0.2%",
33+
"not dead",
34+
"not op_mini all"
35+
],
36+
"development": [
37+
"last 1 chrome version",
38+
"last 1 firefox version",
39+
"last 1 safari version"
40+
]
41+
},
42+
"devDependencies": {
43+
"concurrently": "^7.2.0"
44+
}
45+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = {
2+
render: 'Callout',
3+
children: ['paragraph', 'tag', 'list'],
4+
attributes: {
5+
type: {
6+
type: String,
7+
default: 'note',
8+
matches: ['check', 'error', 'note', 'warning']
9+
},
10+
title: {
11+
type: String
12+
}
13+
}
14+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const { nodes } = require('@markdoc/markdoc');
2+
3+
function generateID(children, attributes) {
4+
if (attributes.id && typeof attributes.id === 'string') {
5+
return attributes.id;
6+
}
7+
return children
8+
.filter((child) => typeof child === 'string')
9+
.join(' ')
10+
.replace(/[?]/g, '')
11+
.replace(/\s+/g, '-')
12+
.toLowerCase();
13+
}
14+
15+
module.exports = {
16+
...nodes.heading,
17+
transform(node, config) {
18+
const base = nodes.heading.transform(node, config);
19+
base.attributes.id = generateID(base.children, base.attributes);
20+
return base;
21+
}
22+
};

examples/create-react-app/server.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const express = require('express');
2+
const app = express();
3+
const path = require('path');
4+
5+
const Markdoc = require('@markdoc/markdoc');
6+
const callout = require('./schema/callout.markdoc');
7+
const heading = require('./schema/heading.markdoc');
8+
const { createContentManifest } = require('./createContentManifest');
9+
10+
const PORT = 4242;
11+
const CONTENT_DIR = path.join(__dirname, 'content');
12+
13+
// The content manifest maps routes to Markdoc documents.
14+
const contentManifest = createContentManifest(CONTENT_DIR);
15+
16+
app.get('/markdoc-api', (req, res) => {
17+
// Here we can dynamically fetch variables, like user preferences or feature flags
18+
const variables = {
19+
flags: {
20+
show_secret_feature: false
21+
}
22+
};
23+
24+
const document = contentManifest[req.query.path];
25+
26+
if (!document) {
27+
return res.sendStatus(404);
28+
}
29+
30+
const { ast } = document;
31+
const config = {
32+
tags: {
33+
callout
34+
},
35+
nodes: {
36+
heading
37+
},
38+
variables: variables
39+
};
40+
const content = Markdoc.transform(ast, config);
41+
42+
return res.json(content);
43+
});
44+
45+
app.listen(PORT, () => {
46+
console.log(`Example app listening on port ${PORT}`);
47+
});

examples/react-nodejs/.gitignore

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
1-
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2-
3-
# dependencies
4-
/node_modules
5-
/.pnp
6-
.pnp.js
7-
8-
# testing
9-
/coverage
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
109

11-
# production
12-
/build
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
1314

14-
# misc
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
1519
.DS_Store
16-
.env.local
17-
.env.development.local
18-
.env.test.local
19-
.env.production.local
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
2025

21-
npm-debug.log*
22-
yarn-debug.log*
23-
yarn-error.log*
26+
# Static files (generated by the Vite build)
27+
static

examples/react-nodejs/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# React example
1+
# React + Node Markdoc Example
22

3-
This example builds a client-side rendered React app that fetches Markdoc ASTs from an [Express.js](https://expressjs.com/) server.
4-
This project was built with `create-react-app`.
3+
This example includes two applications:
54

6-
## Setup
5+
- A client app created with [Vite](https://vite.dev/)'s `react` template
6+
- A basic Node backend that provides a simple API
77

8-
To get started, run:
8+
To start both applications, run `npm run start`, then view the client app in your browser at `http://localhost:5173/`.
99

10-
`npm run start`
10+
To build the production version, run `npm run build` to bundle the static files, then start the Node server with `node server.js`.
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
const fs = require('fs');
2-
const yaml = require('js-yaml');
3-
const glob = require('glob');
4-
const Markdoc = require('@markdoc/markdoc');
1+
import { readFileSync } from 'fs';
2+
import { load } from 'js-yaml';
3+
import globPkg from 'glob';
4+
const { sync } = globPkg;
5+
6+
import Markdoc from '@markdoc/markdoc';
57

68
const parseMarkdocFrontmatter = (ast) => {
7-
return ast.attributes.frontmatter
8-
? yaml.load(ast.attributes.frontmatter)
9-
: {};
9+
return ast.attributes.frontmatter ? load(ast.attributes.frontmatter) : {};
1010
};
1111

1212
// This creates a mapping between route and parsed Markdoc content.
13-
exports.createContentManifest = (ROOT_DIR) => {
14-
const files = glob.sync(`${ROOT_DIR}/**/*.md`);
13+
export function createContentManifest(ROOT_DIR) {
14+
const files = sync(`${ROOT_DIR}/**/*.md`);
1515

1616
const contentManifest = {};
1717

1818
files.forEach((file) => {
19-
const rawText = fs.readFileSync(file, 'utf-8');
19+
const rawText = readFileSync(file, 'utf-8');
2020
const ast = Markdoc.parse(rawText);
2121
const frontmatter = parseMarkdocFrontmatter(ast);
2222

@@ -27,4 +27,4 @@ exports.createContentManifest = (ROOT_DIR) => {
2727
});
2828

2929
return contentManifest;
30-
};
30+
}

examples/react-nodejs/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>React + Node Markdoc Example</title>
5+
</head>
6+
<body>
7+
<div id="root"></div>
8+
<script type="module" src="/src/main.jsx"></script>
9+
</body>
10+
</html>

0 commit comments

Comments
 (0)