logo elektroda
logo elektroda
X
logo elektroda

Procedural creation of project pages on Github - free GH Pages hosting and node.js script

p.kaczmarek2  11 1164 Cool? (+7)
📢 Listen (AI):

TL;DR

  • GitHub Pages project generates separate static HTML pages for programmable IoT devices from a devices.json source file.
  • A Node.js script loads the JSON, sanitizes filenames, creates per-device pages, and writes them to the gh-pages branch.
  • GitHub Actions runs .github/workflows/gh-pages.yml on each push to main, installs Node.js, executes node generate-devices.js, and publishes the result.
  • The workflow successfully generated a devices folder and linked pages such as /devices/Tuya_ATLO_SW1_TUYA.html, updating documentation automatically.
  • The approach works around GitHub Pages' lack of server-side scripts, but it still only produces static pages.
Generated by the language model.
GitHub Pages deployments panel showing recent commits and deployed link .
GitHub Pages is a free hosting service that allows you to publish static HTML pages. However, it does not support running server-side scripts, which means no support for backend languages such as PHP, Python or Ruby. In this tutorial, I will show a potential way around this limitation - procedural HTML generation using Node.js via GitHub Actions.

Node.js is a server-side JavaScript runtime environment that allows us to create web applications, generate files and automate various processes. With Node.js, for example, we can write a script that dynamically creates static HTML files, which can then be published on GitHub Pages. In this way, we can, to a certain extent, 'simulate' a backend on a static host and, more precisely, generate all the expected pages 'for the future'.

GitHub Actions is a tool for automating processes in the GitHub repository. It allows the creation of so-called workflows that can run automatically, e.g. with each push to the repository.

The aim of the project is to automatically create device pages for my list of programmable IoT hardware . I already have one aggregate page-search engine that takes data from a JSON file and runs in the browser, but in addition I want each device to have a separate link with its own page.

This is where the first doubt arises - but how can Node.js if you can't run server-side scripts? Indeed, you can't run server-side scripts, but during changes to the repository you can run a one-time GitHub Workflow which will generate static HTML and save it to the gh-pages branch.

So the organisation of the repository will look as follows:
- branch main contains the main information we provide, the source data, in my example it will be a JSON file with device information
- branch gh-pages will be empty by default
- in addition, in branch main there will be a GitHub workflow which, at the time of each change in main, parses the JSON file and generates static HTML files and writes them to gh pages, which then publishes them on GitHub

Generate HTML locally (on your own computer) .
Let's consider the contents of the main branch. The most important file there is devices.json, here is an example of the contents:
Code: JSON
Log in, to see the code
.
It describes the devices for which we want to generate pages.
Now you can add the JS script that will do this.
We need in turn:
- clear the old GH Pages content
- load the devices.json file
- spell out each device object and generate HTML for it into a separate file to the gh-pages branch
Minimal example, deletion section:
Screenshot of JavaScript code clearing and recreating the gh-pages directory .
Loading JSON, creating a folder for the devices and iterating:

Node.js code snippet loading devices.json and processing devices
Device processing function:
JavaScript code snippet generating HTML files for IoT devices
pageNameForDevice converts the name of the manufacturer and model of the device into a page name, and sanitizeFilename makes sure it is file system friendly. Not all characters can be in file names. We are left with createDeviceHTML. Here is an example implementation:
Code: Javascript
Log in, to see the code
.
. For clarity I have removed the HTML file - the latest version of the script can be seen here: https://github.com/OpenBekenIOT/webapp/blob/main/generate-devices.js .
The code above has a few features added from me, such as displaying the GPIO of the device, but this is not relevant to this example.

Now it's time to test how the system works - we run the script via node.js:

node generate-devices.js
.
The whole thing should execute correctly and generate files for our JSON database:
Screenshot of devices folder with HTML files generated for individual devices .


Generate HTML on GitHub (automatically with each change to the main branch) .
We have already developed the generation of HTML files for each device from a JSON file and tested this locally with Node.js. Now it's time to go one step further. GitHub allows us to automatically perform operations with every change on a branch, we can use this to automatically run our script and save the results to gh pages. This way every, even the smallest, change to the data in devices.json will update our documentation.
We create a file .github/workflows/gh-pages.yml :
Code: text
Log in, to see the code
.
Let's consider the operation of this script. The script is called after a push to the main branch. Then, on a machine with the latest version of ubuntu, first Node.js is installed and then the script developed earlier is executed. The results are then saved to gh-pages, i.e. published on GitHub.

Verified working on GitHub .
Let's see how this works in practice. I've added some changes via the GitHub GUI:
GitHub editor view showing changes in generate-devices.js file .
A commit with a "bird" appears on GitHub:
Screenshot of GitHub repository “webapp” with active “main” branch shown .
In the preview we have information about the success of the deploy operation:
GitHub Actions notification: Deploy Device Pages completed successfully .
In the details we have the entire log of the operation:
View of completed GitHub Actions job showing step list and execution times .
Now we can look at the gh-pages branch:
Dropdown menu showing main and gh-pages branches in a GitHub repository .
There is a devices folder generated on it:
GitHub repo view showing “devices” folder in the gh-pages branch .
Our HTML files are also in it:
List of device HTML files in the devices folder on the gh-pages branch on GitHub .


Final result .
The HTML itself is beyond the scope of this presentation, so I'll just write that I also modified the search engine to link to the generated device pages. The result is available here:
https://openbekeniot.github.io/webapp/devicesList.html
Example device page:
https://openbekeniot.github.io/webapp/devices/Tuya_ATLO_SW1_TUYA.html
From now on, each device has its own page where I can additionally display configuration tips and links to related topics on Elektroda.

Direct link to the repository (for reference):
https://github.com/OpenBekenIOT/webapp

Summary .
GitHub only offers hosting of static HTML code, but clever use of GitHub Actions allows you to automatically pregenerate any kind of page which then mimics a site with a dynamic backend.. For finer work, on the other hand, you can harness JavaScript, on which my main search engine is based - fully client-side. I think this is a convenient and practical solution and will probably use it more than once.
PS: In a separate topic I will show how the same mechanism can be used to automatically generate project documentation.
PS2: Anticipating the question - I put the code snippets as images due to the limitations of our forum. Javascript was turning on spam protection and I couldn't save the topic....

About Author
p.kaczmarek2
p.kaczmarek2 wrote 14416 posts with rating 12374 , helped 650 times. Been with us since 2014 year.

Comments

gulson 04 Sep 2025 15:42

Very interesting. Github Pages is often just used as free hosting for static pages. I would add that Cloudflare Pages is also often considered together with Cloudflare Workers (for executing simple JS... [Read more]

p.kaczmarek2 04 Sep 2025 16:28

And let's not forget GitHub Actions - it's an equally powerful tool. GitHub Actions essentially provides us with a clean virtual machine with a repository where we can perform any operation, including... [Read more]

divadiow 04 Sep 2025 18:50

cool. I notice though that the new pages do not contain the wiki links, relying on the user to check the link on the main device list to get to the topic for that device. On a related note, TuyaMCU... [Read more]

p.kaczmarek2 04 Sep 2025 19:07

What do you mean? The wiki links are at the end of new page: https://openbekeniot.github.io/webapp/devices/Generic_ZN268131.html I can also make device name clickable. Regarding TuyaMCU - you are... [Read more]

divadiow 04 Sep 2025 19:25

apologies, yes, that's quite obvious. Added after 15 [minutes]: I've been vibe coding with overrides. Here's a summary of changes seen in here https://github.com/divadiow/OpenBekenIOT-webapp/blob/main/devicesList.html ... [Read more]

p.kaczmarek2 05 Sep 2025 09:23

not bad... would it work if I type "BK7231" in search box? Show only BK7231 T and N devices? And U... if present. [Read more]

divadiow 05 Sep 2025 18:09

seems so https://obrazki.elektroda.pl/5612536500_1757088549_bigthumb.jpg [Read more]

p.kaczmarek2 05 Sep 2025 20:41

Ok, now, what happened to keywords? Why they look like JSON array? They are okay in currently live version. https://openbekeniot.github.io/webapp/devicesList.html [Read more]

divadiow 05 Sep 2025 22:53

oh yeh! didn't spot that. hmm ok Added after 2 [hours] 11 [minutes]: i've been playing a bit more. [Read more]

p.kaczmarek2 08 Sep 2025 23:23

Well, if there are no bugs, maybe I could take that in, not sure... we might want to ask others for opinion. I am also trying to improve it - next idea is to display similar devices: https://ob... [Read more]

divadiow 09 Sep 2025 07:54

yes sure. I'm just playing and I don't know if overrides are the best/correct way of doing things. [Read more]

FAQ

TL;DR: Use Node.js plus GitHub Actions to pre-generate static device pages for GitHub Pages; one workflow can fan out to 54 builds, and “GitHub Actions essentially provides us with a clean virtual machine.” [Elektroda, p.kaczmarek2, post #21653323]

Why it matters: You get dynamic-like docs on free static hosting without running any backend, ideal for IoT catalogs and firmware projects.

Quick Facts

How do I generate static device pages with Node.js and GitHub Actions?

Keep devices.json in main, write a Node script to emit HTML into ./gh-pages/devices, and add a workflow that runs on push. The workflow checks out code, sets up Node 20, runs node generate-devices.js, then publishes ./gh-pages to the gh-pages branch using peaceiris/actions-gh-pages. This simulates a backend by prebuilding pages on each change. [Elektroda, p.kaczmarek2, post #21653190]

Can GitHub Pages run server-side code like PHP or Python?

No. GitHub Pages serves static content only. The workaround is to pre-generate HTML with a CI job in GitHub Actions and publish the outputs to gh-pages so updates happen automatically when devices.json changes. [Elektroda, p.kaczmarek2, post #21653190]

What does the minimal Actions workflow look like for this setup?

It triggers on push to main, uses ubuntu-latest, sets up Node 20, runs node generate-devices.js, then deploys ./gh-pages to the gh-pages branch with peaceiris/actions-gh-pages. Keep source in main and publish-only artifacts in gh-pages for a clean split. [Elektroda, p.kaczmarek2, post #21653190]

Who is this approach for?

It suits makers, maintainers, and teams documenting many IoT devices. If you want per-device pages, search, and tips without managing servers, pre-generation on Actions gives a robust, free pipeline with repeatable builds and instant publishing. [Elektroda, p.kaczmarek2, post #21653190]

Is there a live example of the device list and per-device pages?

Yes. The project ships a devicesList search page and example per-device pages generated from devices.json, showing images, pins, and wiki links. These demonstrate the prebuilt-doc pattern and how links flow between list and details. [Elektroda, p.kaczmarek2, post #21653190]

Where do wiki links appear on the generated pages?

They appear near the end of each device page. You can also make the device name clickable if you prefer stronger affordance. This keeps the card clean while preserving access to deeper guides and topics. [Elektroda, p.kaczmarek2, post #21653446]

Why can’t I fetch files over HTTP from GitHub Pages during device setup?

GitHub Pages only supports HTTPS. Some platforms ship without HTTPS enabled, so plain HTTP pulls (e.g., autoexec.bat) will fail. Enable HTTPS on the device or host transitional assets where HTTPS is available. [Elektroda, p.kaczmarek2, post #21653446]

Does the search handle BK7231 variants if I type “BK7231”?

Yes. The updated UI shows BK7231T and BK7231N (and U, if present) when you enter “BK7231.” The filtering improvements also debounce input and refresh results automatically for a smoother experience. [Elektroda, divadiow, post #21654228]

What about TuyaMCU devices—do I need extra configuration?

Yes. TuyaMCU-matched devices typically require further configuration, and the wiki link remains the best source for final setup details. Plan for a follow-up pass on these pages with clear, device-specific instructions. [Elektroda, divadiow, post #21653438]

How many builds can GitHub Actions run for firmware targets?

One workflow can fan out to many jobs; the example project runs up to 54 operations for different chips and targets from a single change. This scales maintenance and speeds releases. [Elektroda, p.kaczmarek2, post #21653323]

What is OpenBeken in this context?

OpenBeken is the firmware and tooling suite referenced by the project. Its repository integrates with Actions to compile device binaries and connects docs to device pages and search. It showcases the end-to-end CI-to-docs approach. [Elektroda, p.kaczmarek2, post #21653323]

Could Cloudflare Pages + Workers replace part of this?

Yes. Cloudflare Pages offers static hosting, and Workers run JS at the edge. For simple scripts, this provides fast global coverage and a free tier, making it a practical complement or alternative to GitHub Pages. [Elektroda, gulson, post #21653281]

I see keywords rendering like a JSON array—what’s happening?

That’s a front-end rendering issue in an experimental branch. The live version displays keywords correctly. Ensure your template maps the keywords array to a formatted string before rendering. [Elektroda, p.kaczmarek2, post #21654379]

Any planned improvements to the generated pages?

Yes. One idea is to show similar devices to aid discovery and migration. This would appear near the top of a device page, informed by shared chips, pins, or tags. [Elektroda, p.kaczmarek2, post #21657248]

How do I set this up, step by step? (3 steps)

  1. Put devices.json and generate-devices.js in main; script writes HTML to ./gh-pages/devices. 2. Create .github/workflows/gh-pages.yml to install Node 20 and run node generate-devices.js on push. 3. Deploy ./gh-pages to gh-pages via peaceiris/actions-gh-pages with force_orphan. [Elektroda, p.kaczmarek2, post #21653190]

Edge case: what fails silently here?

Direct HTTP fetches to GitHub-hosted files will fail on devices lacking HTTPS. Also, if the workflow doesn’t clear the publish directory, stale pages may persist. “Only HTTPS is supported,” so plan accordingly. [Elektroda, p.kaczmarek2, post #21653446]
Generated by the language model.
%}