{"id":18541459,"url":"https://github.com/kentor/tiny-ssg","last_synced_at":"2025-04-09T18:31:07.569Z","repository":{"id":65516597,"uuid":"91277242","full_name":"kentor/tiny-ssg","owner":"kentor","description":"An unopinionated static site generator with a tiny api. Friendly with a watched hot reloaded environment.","archived":false,"fork":false,"pushed_at":"2017-06-01T05:03:00.000Z","size":42,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-03T06:03:10.973Z","etag":null,"topics":["nodejs","server-side-react","server-side-rendering","static-site-generator"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kentor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-14T23:18:17.000Z","updated_at":"2021-11-08T12:44:50.000Z","dependencies_parsed_at":"2023-01-26T22:25:12.028Z","dependency_job_id":null,"html_url":"https://github.com/kentor/tiny-ssg","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kentor%2Ftiny-ssg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kentor%2Ftiny-ssg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kentor%2Ftiny-ssg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kentor%2Ftiny-ssg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kentor","download_url":"https://codeload.github.com/kentor/tiny-ssg/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248087684,"owners_count":21045564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nodejs","server-side-react","server-side-rendering","static-site-generator"],"created_at":"2024-11-06T20:05:09.603Z","updated_at":"2025-04-09T18:31:07.194Z","avatar_url":"https://github.com/kentor.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tiny-ssg\n\n[![Build Status](https://travis-ci.org/kentor/tiny-ssg.svg)](https://travis-ci.org/kentor/tiny-ssg) [![npm](https://img.shields.io/npm/v/tiny-ssg.svg)](https://www.npmjs.com/package/tiny-ssg)\n\nAn unopinionated static site generator with a tiny api, that is friendly with a\nwatched hot reloaded environment.\n\n# api\n\n## ``new SSG(opts = { dest: `${process.cwd()}/public` })``\n\nCreates a new `SSG` instance. `opts.dest` specifies the destination of the\ngenerated html files. `opts.dest` defaults to the `public` dir under the current\nworking directory. It's probably easier to just use the next api instead.\n\n## `ssg = require('tiny-ssg/instance')`\n\nReturns a new `SSG` instance with defaults args. Possible to set the destination\nby setting `ssg.dest`. This is more friendly with watch mode and\n[invalidate-module][i].\n\n## `ssg.manifest(cb: () =\u003e Promise\u003cPage[]\u003e | Page[]): void`\n\nSpecifies the pages to be built.\n\n`Page` has the type:\n\n```js\ntype Page = {\n  url: string,\n  view: (meta: any, page: Page) =\u003e Promise\u003cstring\u003e | string,\n  meta?: any,\n}\n```\n\n`url` specifies the destination where you would ultimately access the page when\nserved on your host. e.g. `/`, `/posts/title-slug/`, `/posts/feed.xml`.\n\n`view` is a function whose return value will be written to disk at the\nappropriate file for the url. The return value may be a Promise that resolves\ninto a string. It is passed the `meta` object and the `Page` object itself.\n\n`meta` will be passed as the first argument to view. This could be anything that\nthe view would find useful.\n\nThe `cb` arg to `manifest` should return a list or a Promise that resolves to a\nlist of `Page` objects.\n\n## `ssg.build(): Promise\u003cvoid\u003e`\n\nExecutes the callback given in `manifest()` and builds the site according to the\nreturned `Page` objects.\n\nThere is no guaranteed order of executing the `view` functions or the\norder of the writes. Views may be executed in parallel. For this reason, if your\nviews depend on the same resource, you need to write code that is friendly with\nparallel access of resources. See the Recommended Utilities section.\n\nIf `build()` is ran again in the same process, it will rebuild the site with\nthese differences:\n\n- if the view of a Page returns the same string, it will not write out\n- if a url is no longer returned since the previous manifest, the page will be\n  deleted from the destination directory\n\n# trivial example\n\nHere's a trivial example to demonstrate the API:\n\n```js\nconst ssg = require('tiny-ssg/instance');\n\nssg.manifest(() =\u003e {\n  return [\n    { url: '/', view: () =\u003e 'Hello World!' },\n  ];\n});\n\nssg.build();\n```\n\nThis will write to `Hello World!` to `public/index.html`.\n\n# watch mode example\n\n`tiny-ssg` is great with watchers like [chokidar][c] and tools like\n[invalidate-module][i]:\n\n```js\n// watch.js\nconst chokidar = require('chokidar');\nconst invalidate = require('invalidate-module');\nconst path = require('path');\n\nconst watcher = chokidar.watch('*.js').on('all', (event, filename) =\u003e {\n  invalidate(path.resolve(filename));\n  require('./build')();\n});\n```\n\n```js\n// build.js\nconst ssg = require('tiny-ssg/instance');\n\nssg.manifest(() =\u003e {\n  return [\n    { url: '/', view: () =\u003e 'Hello World!' },\n  ];\n});\n\nmodule.exports = () =\u003e ssg.build();\n```\n\nNow you if you execute `node watch.js`, you may freely update the view function\nin `build.js` and it will rebuild the site.\n\n# markdown file example\n\nUsing [marky-markdown][m], [fs-extra][f], and [async/await][a]:\n\n```js\nconst fs = require('fs-extra');\nconst md = require('marky-markdown');\nconst ssg = require('tiny-ssg/instance');\n\nssg.manifest(() =\u003e {\n  return [\n    { url: '/', view: markdownView, meta: { file: 'test.md' } },\n  ];\n});\n\nasync function markdownView(meta) {\n  const raw = await fs.readFile(meta.file);\n  return md(raw);\n}\n\nssg.build();\n```\n\n# react example\n\nUse `ReactDOMServer.renderToStaticMarkup`:\n\n```js\nconst React = require('react');\nconst ssg = require('tiny-ssg/instance');\nconst { renderToStaticMarkup } = require('react-dom/server');\n\nssg.manifest(() =\u003e {\n  return [\n    { url: '/', view: reactView },\n  ];\n});\n\nfunction reactView() {\n  const element = (\n    \u003chtml\u003e\n      \u003chead\u003e\u003ctitle\u003eHello World!\u003c/title\u003e\u003c/head\u003e\n      \u003cbody\u003e\u003ch1\u003eHello World!\u003c/h1\u003e\u003c/body\u003e\n    \u003c/html\u003e\n  );\n  return `\u003c!doctype html\u003e${renderToStaticMarkup(element)}`\n}\n\nssg.build();\n```\n\nIt's up to you on how you compose your React components. Stateless functional\ncomponents work well here.\n\n# how to make rebuilds fast\n\nIn watch mode, since the build process is ran all over again on `build()`, you\nwould need to prevent excessive calls to expensive operations for fast rebuilds.\nFor example, if your view reads from a file, then the read should be cached and\ncould be invalidated by the file's `mtime`.\n\nViews that perform async I/O will be executed concurrently. If multiple views\nread from the same resource, you can use something like [reuse-promise][r] to\nprevent parallel reads of the same resource.\n\n[a]: https://babeljs.io/docs/plugins/transform-async-to-generator/\n[c]: https://github.com/paulmillr/chokidar\n[f]: https://github.com/jprichardson/node-fs-extra\n[i]: https://github.com/kentor/invalidate-module\n[m]: https://github.com/npm/marky-markdown\n[r]: https://github.com/elado/reuse-promise\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkentor%2Ftiny-ssg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkentor%2Ftiny-ssg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkentor%2Ftiny-ssg/lists"}