The pico static side generator, the simplest one I ever wanted and hopefully "found".
  • JavaScript 42%
  • Nunjucks 31.4%
  • CSS 20.3%
  • HTML 5.2%
  • Shell 1.1%
Find a file
2026-02-12 10:56:32 +01:00
docs/adr Basically just add ADR3 and some tests to verify the markdown features we expect. 2025-05-12 19:04:07 +02:00
examples/1-basic Move the package to pic0 namespace (pico was not available :( ). 2025-08-05 22:25:25 +02:00
picossg.dev More CSS nesting 2026-02-12 10:56:32 +01:00
src PicoSPA is the new SPAish, also a much easier to read name. 2025-08-16 11:09:31 +02:00
templates A first prototype using the docs-kit to create a docs page, now i will try it on SPAish and then picossg.dev and the kit is ready to go. 2025-06-05 17:59:51 +02:00
test Make the 13th njk error test pass too. 2025-08-04 19:09:03 +02:00
.gitignore Add smoke to test the njk errors that we are throwing now. 2025-07-02 12:42:09 +02:00
CHANGELOG.md PLanning and noting 2025-08-16 11:09:00 +02:00
CLAUDE.md Describe the tests and how to use them useful, I hope. 2025-08-16 11:50:55 +02:00
docker-compose.yml Add build_docs ... might just be a hack, but simple enough for now. 2025-05-15 19:57:30 +02:00
LICENSE.md Update a bit 2025-04-29 20:43:04 +02:00
package-lock.json Describe the tests and how to use them useful, I hope. 2025-08-16 11:50:55 +02:00
package.json Fix OS check control flow logic in dev:install script. 2026-02-02 15:59:21 -07:00
prod.sh Remove the npm-i again, it freaks out later :). I am postponing fixing this until it occurs again. 2025-08-04 19:27:51 +02:00
README.md Describe the tests and how to use them useful, I hope. 2025-08-16 11:50:55 +02:00

picossg

The pico static site generator – the simplest one I ever wanted and hopefully "found". See the picossg.dev for more information.

What it does

picossg processes:

  • files from the content directory into the output directory, processing the files if needed
  • Markdown files (.md) using markdown-it
  • Nunjucks templates (.njk) using nunjucks
  • Combined Nunjucks + Markdown files (.md.njk)
  • Static assets (copied as-is)

It transforms these files into a static website with a 1:1 mapping from source director+file structure to output.

How to use it

  • Make sure to have nodejs installed see here
  • open a terminal
  • run npx @pic0/ssg -c content -o output, this builds all files in the content directory into the output directory
  • to serve, open another terminal, run npx http-server output -p 0 (-p 0 searches for an available port, staring with 8080), open http://localhost:8080 (or the right port) in your browser and the files in content are processed and served from output

Getting Started

  • create your new site's directory: mkdir my-site; cd my-site
  • create the content directory: mkdir content
  • put the package.json in the root of the project
{
  "name": "my-ssg-site",
  "version": "1.0.0",
  "scripts": {
    "build": "npx @pic0/ssg -c content -o output",
    "start": "npx http-server output -p 0",
    "build:watch": "npx nodemon --quiet --legacy-watch --watch content --ext '*' --exec \"bash -c 'npm run build'\""
  }
}
  • put some *.html.md or *.html.njk file into the content directory, e.g. start with index.html.md (you can start with just putting "Hello World!" in there, for more see "Create a Site" in the docs)
  • run npm run build:watch in one terminal to start building the site
  • run npm start in another terminal to start the server
  • open http://localhost:8080 in your browser to see the site (the port may be different, see the output of the npm start command)

The npm run build script above (the code npx @pic0/ssg -c content -o output) will run the remote picossg package (which is published on npmjs.org) and look for files in the content directory, process them and put them to the output directory.
The npm run start (or can also be called as npm start) script (the script npx http-server output -p 0) will run the remote package http-server (also published on npmjs.org) and serve the files from the output directory on an available port (mostly 8080) on your local computer, which you can then see in your browser at http://localhost:8080.
The npm run build:watch script uses yet another remote package nodemon to watch the content directory for changes and re-run the build command whenever a file changes, so you don't have to call npm run build every time you change a file.

Examples

Philosophy

The core philosophy of picossg is simplicity and predictability:

  1. 1:1 file mapping – Each source file maps directly to an output file with the same path (except for extension changes)
  2. Minimal magic – The only "magic" is:
    • Files starting with underscore (_*) are excluded from the output
    • Template files (.njk, .md) are processed, a file.html.md.njk processes nunjucks and markdown and outputs file.html, just by working off the extensions from the last one backward. Allows also for style.css.njk to be processed and output as style.css if desired.
    • All other files are copied as-is
  3. Asset handling – Any assets (CSS, images, etc.) in the source directory are copied to the output, as mentioned in 2. already
  4. _config.js – An optional _config.js file in the content directory can provide preprocess() and postprocess() functions, they both receive a map of all files and can be used to preprocess the content before rendering or postprocess the output after rendering.

There are no complex configuration options, no plugins, no middleware – just a simple, predictable build process.

How to develop PicoSSG

PicoSSG is developed in JavaScript, using Node.js. It uses Nunjucks for templating and Markdown-it for Markdown processing. To ensure that PicoSSG really still works as with the last commit, there are tests. The tests are on various levels:

  1. the most essential ones are those you find in test/content and test/golden-ref, they compare the output of the build with the expected output, these tests are run npm test and npm run test:watch (in watch mode), with npm run testdiffs you can see the differences between the output and the expected output in case the tests failed
  2. the second layer is testing the preprocessor, which finds all the files to be processed, see the file [test/content/_config_preprocess_assertions.js] the function const preprocess() at the bottom, the test names should explain what is tested. These tests are separate because they run during the build step, see the npm run test:preprocess command it just runs the build step with using the config file _config_preprocess_assertions.js, which contains our tests. You can run these in watch mode too, which is npm run test:preprocess:watch.
  3. the third layer is the smoke tests, which are run with npm run test:smoke (there is no watch mode). These I introduced when I started testing the better error messages that are given during the build process, and for that smoke is just THE TOOL. Each test runs a build and the test is about comparing the console output of the build with some expected output. See the [test/smoke.yaml] file, which contains the tests, and the [test/njk-errors] directory, which contains the "broken" templates that are used to test the error messages.

Set up

To develop picossg, clone the repository and install the dependencies:

  • git clone https://codeberg.org/wolframkriesing/picossg.git
  • cd picossg
  • npm i
  • npm run dev:install which will install tools needed in development, like smoke, which need to be installed once

Does it all work?

You might hate tests, but the least these do here is: tell you if all the things work as expected, on your machine ;) and if it makes sense to even start changing any code. Because if tests fail already the setup might need some love first. (Might also be that the provided setup has a flaw, then report it please.) So I encourage you to run the tests first.

  • npm run test:ci runs all the tests, just not in watch mode
  • npm run test:watch runs the golden-ref tests in watch mode, and re-runs on any content change
  • test:preprocess:watch runs the preprocess tests in watch mode, they can NOT run in parallel with the npm run test:watch tests, since they are using the same _output directory and would overwrite each other, therefore the final nom run test:ci command does the "final" test before a release
  • npm run test:smoke runs the tests that tests the njk error messages

The npm test runs a simple diff command, it compares the generated _output directory with the expected output in test/golden-ref.

Since the default npm run build:watch runs multiple times when you change the source code, e.g. build.js there is also build:watch:dev which only watches the code to be run and NOT the content to be generated.

Run it via docker

  • you can use docker-compose run --rm --remove-orphans picossg_node node src/build-cli.js -c content -o _output to run the build
  • to build the content from the directory picossg.dev into _picossg.dev directory you can use docker-compose run --rm --remove-orphans picossg_node npm run build:site

(To be) Listed at