This repository holds the product documentation and everything needed to build it into a static website. The pages are written in Markdown, and the site is generated with Gatsby and a set of gulp tasks.
The repository is self-contained. The website template is in src/, and the gulp tasks are in build/. There is no separate helper package to install.
The site can be white-labeled: the product name, logo, and favicon are each set in one place. See White-label the site.
| Tool | Version | Notes |
|---|---|---|
| Node.js | 22 LTS (22.17.1 recommended) | Comes with npm. |
| npm | 10 or later | Node.js includes npm. |
| Git | Any recent version | Needed to clone the repository. The build also reads the last commit date of each page from Git. |
You also need internet access to registry.npmjs.org for the first install. All commands below are run from the repository root.
-
Install the dependencies.
npm install
-
Start the site locally with live reload.
npx gulp serve
Open
http://localhost:8000in a browser. Changes to the template insrc/and to the Markdown files indocs/show up in the browser within a few seconds of saving; no restart is needed. Restart the command only after you changedocs/summary.json,docs-structure.yaml, orconfig.json.The first start takes several minutes. Later starts reuse the Gatsby cache in
.cache/. To start from a clean state, runnpx gulp cleanfirst. -
Create the production build.
npm run build
The static site is written to the
public/folder. Host the contents ofpublic/on any static web server.
| Command | What it does |
|---|---|
npm install |
Installs the dependencies. |
npm run serve (or npx gulp serve) |
Builds the table of contents and starts the Gatsby development server. |
npm run build |
Runs gulp production-build and writes the static site to public/, including public/sitemap.xml. |
npm run preview |
Serves the existing public/ build at http://localhost:9000 with the URL prefix, so you can check the production build. Run npm run build first. |
npm run build-preview |
Runs the production build, then serves it for preview. |
npm test |
Runs all content checks. See Run the tests. |
npm run clean (or npx gulp clean) |
Deletes the Gatsby cache and the generated pages, for a completely fresh start. |
npm run prepare-content (or npx gulp build) |
Prepares the content only: clears the cache, copies docs/ to src/pages, and generates left-toc.json. |
npm run sitemap (or npx gulp sitemap) |
Generates sitemap.xml for the site link set in config.json. Run it after npm run prepare-content. |
npm testThe command runs these checks in order and stops at the first one that fails:
| Check | What it verifies |
|---|---|
| Page list | Every page in docs/summary.json has a Markdown file, and every Markdown file is listed. |
| Spelling | All Markdown files in docs/ and this README. |
| Images | Image width syntax and alt text. |
| File names | File and folder names under docs/ use lowercase dictionary words separated by hyphens. |
| Search engine optimization | Title and description length, one top-level heading per page, and no unused images in static/images/. |
| Links | Links between pages point to pages that exist. |
| Markdown lint | Markdown formatting rules in build/lint/.markdownlint.json. |
| Code blocks | No code block starts with an empty line. |
If the spelling or file name check reports a correct technical term, add the term on its own line to the .spelling file.
The URL prefix is the folder name that comes after the domain in the website address. For example, in https://docs.example.com/reports/designer-guide/ the prefix is /reports.
You set the prefix once, in siteLink in config.json. The production build then adds the prefix to every page link, image, and script. Because of this, you must upload the site to a folder with the same name as the prefix. If the folder name and the prefix are different, the pages open without styles or images.
-
Decide the final address of the documentation, for example
https://docs.example.com/reports. -
Open
config.jsonand setsiteLinkto that address."siteLink": "https://docs.example.com/reports"
-
Build the site.
npm run build
-
Upload everything inside the
public/folder to the folder on your web server that has the same name as the prefix. Do not upload thepublic/folder itself. -
Open the address in a browser and check that the pages, images, and search work.
siteLink is https://docs.example.com/reports, so the prefix is /reports.
On the web server, upload the contents of public/ into a folder named reports:
web server root
└── reports/ <- same name as the prefix
├── designer-guide/
│ └── index.html <- the designer guide page
├── page-data/
├── images/
└── (other files from public/)
What customers see:
| Address | Result |
|---|---|
https://docs.example.com/reports/ |
Opens the home page of the documentation. |
https://docs.example.com/reports/designer-guide/ |
Opens the designer guide page. |
siteLink is https://docs.example.com, so there is no prefix.
Upload the contents of public/ directly into the web server root, with no extra folder:
web server root
├── designer-guide/
│ └── index.html <- the designer guide page
├── page-data/
├── images/
└── (other files from public/)
What customers see:
| Address | Result |
|---|---|
https://docs.example.com/ |
Opens the home page of the documentation. |
https://docs.example.com/designer-guide/ |
Opens the designer guide page. |
Every page is built as a folder that contains an index.html file, for example designer-guide/index.html. Customers do not type index.html. The web server opens it automatically when the address ends with /.
| Address | Use it? |
|---|---|
https://docs.example.com/reports/designer-guide/ |
Yes. Share this address with customers. |
https://docs.example.com/reports/designer-guide/index.html |
It also works, but it is longer. Do not share it. |
Always end page addresses with / and do not include index.html. The addresses in sitemap.xml also end with /.
npm run serveignores the prefix. Pages open athttp://localhost:8000/designer-guide/.npm run build-previewbuilds the site and opens it with the prefix. Pages open athttp://localhost:9000/reports/designer-guide/. Use your own prefix in place of/reports.
To try another prefix without changing config.json, add --prefix to the build. The sitemap still uses siteLink, so change siteLink instead if the sitemap must match.
npm run build -- --prefix=/docs| Problem | Fix |
|---|---|
npm install stops with ERESOLVE could not resolve |
Make sure the .npmrc file in the repository root contains legacy-peer-deps=true. |
The build stops with Something went wrong installing the "sharp" module |
Run npm rebuild sharp, then build again. |
The development server stops with EBUSY: resource busy or locked |
Many files were moved or deleted while the server was running. Start npx gulp serve again. |
Page titles or icons disappear after you edit a file in src/ |
Stop the development server and start npx gulp serve again. |
| A new page does not appear in the left table of contents | Add the page to docs/summary.json, then restart npx gulp serve. |
.
├── docs/ Documentation pages
│ ├── summary.json Left table of contents: titles, slugs, and file names
│ └── designer-guide/ Markdown pages, in folders that match the page URLs
├── src/ Website template
│ ├── components/ Header, table of contents, search, feedback, page navigation
│ ├── templates/ Page layout
│ └── assets/
│ ├── css/ Style sheets
│ └── img/ Icons used by the template
├── static/ Files copied to the site as they are
│ ├── branding/ Logo, favicon, app icon, and social sharing image
│ ├── images/ Images used by the documentation pages
│ ├── 404.js 404 page
│ └── robots.txt
├── build/ gulp tasks
│ ├── *.js One file for each group of tasks
│ └── lint/ Markdown lint rules used by the test tasks
├── gatsby-config.js Gatsby plugins
├── gatsby-node.js Page creation and redirects
├── gatsby-browser.js Browser-side Gatsby hooks
├── config.json Site settings: product name, branding, site link, header label, analytics
├── docs-structure.yaml Top-level sections of the site
├── redirects.json Redirects from old URLs to new URLs
├── .spelling Word list for the spell check and the file-name check
├── .npmrc npm settings needed for the install
├── .htaccess Apache web server rules; copy it to the web root when you host the site
├── .github/ Pull request templates
├── Jenkinsfile Continuous integration pipeline (optional)
├── pipeline.cmd Git settings used by the pipeline (optional)
├── gulpfile.js Loads the gulp tasks from build/
└── package.json npm dependencies and scripts
The following items are generated. They are ignored by Git and must not be edited by hand:
| Path | Created by |
|---|---|
src/pages/, left-toc.json |
gulp serve and gulp build |
.cache/, public/ |
Gatsby |
node_modules/, package-lock.json |
npm install |
cireports/ |
npm test |
sitemap.xml, public/sitemap.xml |
gulp sitemap (the production build also copies it to public/) |
File in build/ |
Purpose |
|---|---|
build.js |
clean, copy, sync-pages, toc, build, and postinstall tasks. |
serve.js |
serve task: starts the development server and watches docs/. |
production.js |
production-build task. |
toc.js |
Generates left-toc.json from docs-structure.yaml and docs/summary.json. |
product-name.js, site-variables.js |
Replace the product name placeholders. |
content.js, tab.js, tile.js, release-note.js |
Prepare the page content for Gatsby. |
test.js |
test task, spell check, Markdown lint, and image checks. |
file-validation.js, seo.js, url-validation.js, prism-validation.js |
The other checks that npm test runs. |
sitemap.js |
sitemap task. |
config.js |
Reads config.json and package.json for the other tasks. |
- Add or edit the Markdown file under
docs/. Use lowercase words separated by hyphens for file and folder names. - For a new page, add its title and file name to
docs/summary.jsonso that it appears in the left table of contents. - Put images under
static/images/and reference them from the Markdown file with a path that starts with/static/images/. Give every image alt text. - Run
npx gulp serveto preview the change. - Run
npm testbefore you commit.
Every page starts with a header block like this:
---
layout: post
title: Manage Report Categories in Report Server | {{site.productName}}
description: Create, open, update, pin, and delete report categories in {{site.productName}} Report Server, and manage share permissions so the right users can access each one.
platform: report-platform
documentation: ug
---
| Field | Rule |
|---|---|
title |
Required. 46 to 60 characters, counted after the product name placeholder is replaced. |
description |
Required. At least 100 characters; keep it under 160. |
Use one top-level heading (#) per page, and do not repeat the title text in it.
Use the product name placeholders instead of typing the product name. See Change the product name.
All branding lives in config.json, the website template in src/, and the files in static/branding/.
| What to change | Where |
|---|---|
| Brand name, header logo, favicon, and social sharing image | See Replace the brand name, logo, and favicon. |
| Product name inside the pages | product.name in config.json. See Change the product name. |
Product label next to the logo (Enterprise) |
additionalInfo.header in config.json |
| Colors and fonts | CSS variables in the :root blocks of src/assets/css/style.css. Header-only styles are in header.css. |
| Header content | src/components/Header.js |
| Feedback form | src/components/Feedback.js |
| Focus menu (Open in ChatGPT, Open in Claude) | src/components/FocusButton.js |
| 404 page, including its links to demos and other documentation sites | static/404.js |
| Analytics and tracking | analytics.googleTagManagerId in config.json. Leave it empty to turn tracking off. |
Site domain used by the gulp sitemap task |
siteLink in config.json |
| URL path prefix | Path part of siteLink in config.json, or the --prefix build option |
Follow these three steps to rebrand the site. Keep the file names and image sizes shown below, so that no code needs to change.
Open config.json and change product.name. Set product.trademark to "" if your name has no trademark symbol.
"product": {
"name": "Contoso Reports",
"trademark": ""
}This one setting changes the name in every documentation page, the table of contents, the social sharing tags, and the 404 page title. See Change the product name for how it works.
The label shown next to the logo (Enterprise) is separate. Change it with additionalInfo.header in config.json.
Replace this file with your own logo. Keep the same file name, or change the branding.logo path in config.json.
| File | Used for | Size |
|---|---|---|
static/branding/logo.svg |
Header logo | SVG, 237 x 47 (about 5:1) |
The logo is displayed at 170 x 36 pixels and is scaled to fit, so a logo with a different shape still works but may look smaller. To change the displayed size, edit width and height of .header-logo in src/assets/css/style.css. Narrow screens use the smaller widths set for .header-logo at the end of src/assets/css/header.css.
Replace these files in static/branding/ with your own. Keep the same file names, or change the paths under branding in config.json.
| File | Config key | Used for |
|---|---|---|
static/branding/favicon.ico |
branding.favicon |
Browser tab icon |
static/branding/app-icon.png |
branding.appIcon |
Apple touch icon and high-resolution icon |
static/branding/social-image.png |
branding.socialImage |
Preview image shown when a page link is shared (1200 x 630 PNG recommended) |
- Restart
npx gulp serve. A restart is needed becauseconfig.jsonchanged. - Open
http://localhost:8000and check the logo, the browser tab icon, and the product name on a page. - If the old icon still shows, clear the browser cache or open the site in a private window. Browsers keep favicons for a long time.
The product name is not typed into the documentation pages. The Markdown files in docs/ and the titles in docs/summary.json use placeholders, and the build replaces them with the values from the product setting in config.json.
"product": {
"name": "Bold Reports",
"trademark": "<sup>®</sup>"
}| Placeholder | Replaced with | Use it for |
|---|---|---|
{{site.productName}} |
product.name |
Page titles, descriptions, keywords, image alt text, and table of contents titles. |
{{site.productNameTM}} |
product.name followed by product.trademark |
Headings and body text where the trademark symbol is shown. |
To white-label the content, change product.name. If your product name has no trademark symbol, set product.trademark to an empty string (""). Then restart npx gulp serve or run npm run build; no Markdown file needs to be edited.
When you write new pages, use the placeholders instead of typing the product name.
The setting does not change these items. Review them by hand when you rebrand:
- Links to other websites inside the pages.
- Names of other products that the pages mention.
- Text that appears inside the screenshots in
static/images/.
Note: Keep
"name": "enterprise-docs"inpackage.json. The build uses this name to find the matching entry underreposinconfig.json.
- Run
npx gulp serveand check the header, favicon, colors, and a few pages. - Run
npm test. - Run
npm run buildand host thepublic/folder.