{"id":38678192,"url":"https://github.com/coxmi/toast","last_synced_at":"2026-01-17T10:05:59.544Z","repository":{"id":57377459,"uuid":"382301625","full_name":"coxmi/toast","owner":"coxmi","description":"A tiny static site generator that doesn't specify a framework. Bring your own compilation.","archived":false,"fork":false,"pushed_at":"2022-05-22T10:41:49.000Z","size":3513,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-06T03:16:40.366Z","etag":null,"topics":["ssg","static-site-generator","webpack"],"latest_commit_sha":null,"homepage":"https://npmjs.com/toast-static","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coxmi.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":"2021-07-02T09:48:42.000Z","updated_at":"2022-01-17T16:30:34.000Z","dependencies_parsed_at":"2022-09-26T16:50:11.500Z","dependency_job_id":null,"html_url":"https://github.com/coxmi/toast","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/coxmi/toast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coxmi%2Ftoast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coxmi%2Ftoast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coxmi%2Ftoast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coxmi%2Ftoast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coxmi","download_url":"https://codeload.github.com/coxmi/toast/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coxmi%2Ftoast/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28505597,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T06:57:29.758Z","status":"ssl_error","status_checked_at":"2026-01-17T06:56:03.931Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["ssg","static-site-generator","webpack"],"created_at":"2026-01-17T10:05:58.897Z","updated_at":"2026-01-17T10:05:59.539Z","avatar_url":"https://github.com/coxmi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n\u003cpre\u003ePlease note: This library is a work in progress!\u003c/pre\u003e\n\n# toast\n\n### A really tiny static site generator plugin for webpack\n\nTurn external data sources into a static site without specifying your development environment. Transpile, generate, or concatenate your templates however you want, toast is just a step in your build process. You’re not tied to using today’s framework of choice, so you can use es6 template literals for your `sitemap.xml`, `jsx` for your `\u003chead\u003e`, or `ejs` for your `\u003cbody\u003e`.\n\n- bring your own transpilation (using [webpack](https://webpack.js.org/))\n- just return a `string` in your template render function\n- no magic filenames or frontmatter: set urls in your template files\n- fetch data from anywhere: just export a `Promise` or `async` function\n\n\n## Usage\n\n```js\n// use javascript to get your content from anywhere you like\nexport const content = { title: 'Hello, World!' }\n\n// set the url of your page\nexport const url = '/'\n\n// render your template\nexport const html = (content, meta) =\u003e \n  `\u003c!DOCTYPE html\u003e\n   \u003chtml\u003e\n        \u003cbody\u003e\n            \u003ch1\u003e${content.title}\u003c/h1\u003e\n        \u003c/body\u003e\n    \u003c/html\u003e`\n```\n\n## Setup\n\n### Install\n\n```bash\nnpm install toast-static --save-dev\n```\n\n### Configure webpack\n\nAdd the plugin to your `webpack.config.js`:\n\n\n```js\nconst { WebpackToastPlugin } = require('toast-static/webpack')\n\nmodule.exports = {\n    output: {\n        path: outputDir,\n        filename: '[name].js',\n    },\n    plugins: [\n        new WebpackToastPlugin({ \n            templates: './templates/**.js' // glob, path, or array\n        })\n    ]\n}\n```\n\n\n\n## Templates\n\nA template is just a simple js file with some exports. \n\n`pages/latest.js`:\n\n```js\n// grab your data (optional)\nexport const content = fetch('https://xkcd.com/info.0.json').then((res) =\u003e res.json())\n\n// set your output url (starting with a forward-slash)\nexport const url = (content, meta) =\u003e '/latest/'\n\n// render your html (or css, json, xml, rss, svg, or any other string-based format)\nexport const html = (content, meta) =\u003e \n   `\u003c!DOCTYPE html\u003e\n    \u003chtml\u003e\n        \u003cbody\u003e\n            \u003ch1\u003e${content.title}\u003c/h1\u003e\n            \u003cimg src=\"${content.img}\"\u003e\n        \u003c/body\u003e\n    \u003c/html\u003e`\n```\n\n### Collections\n\nExport an iterable to `collection`, and a page will be generated for each item. \n\n`pages/drinks.js`:\n\n```js\nexport const collection = fetch('https://thecocktaildb.com/api/json/v1/1/filter.php?i=Mango').then((res) =\u003e res.json())\n\nexport const url = (content, meta) =\u003e `/drinks/${content.idDrink}/`\n\nexport const html = (content, meta) =\u003e \n    `\u003c!DOCTYPE html\u003e\n    \u003chtml\u003e\n        \u003cbody\u003e\n            \u003ch1\u003e${content.strDrink}\u003c/h1\u003e\n            \u003cimg src=\"${content.strDrinkThumb}\"\u003e\n        \u003c/body\u003e\n    \u003c/html\u003e`\n\n```\n\n### Pagination\n\nTo split up a collection into pages, just export a number to `perPage`.\n\n`pages/blog.js`:\n\n```js\nexport const collection = [\n    { url: 'hello-world' },\n    { url: 'how-i-only-used-1-million-dependencies-to-build-my-new-blog' },\n    { url: 'who-needs-reactjs-anyway' },\n    { url: 'framework-fatigue-in-2041' },\n    { url: 'ai-generated-webpack-config' },\n    { url: 'the-singularity-came-from-css-houdini' }\n]\n\n// split posts into groups of five\nexport const perPage = 5 \n\n// set url to \"/posts\" for first page, and \"/posts/2\" for others\nexport const url = (content, meta) =\u003e {\n    return (meta.currentPage === 1)\n        ? `/posts/`\n        : `/posts/${meta.currentPage}/`\n}\n\nexport const html = (content, meta) =\u003e \n    `\u003c!DOCTYPE html\u003e\n    \u003chtml\u003e\n        \u003cbody\u003e\n            \u003ch1\u003ePage ${meta.currentPage} of ${meta.lastPage}\u003c/h1\u003e\n            \u003cul\u003e\n                ${content.map(post =\u003e \n                    `\u003cli\u003e\u003ca href=\"${post.url}\"\u003e${post.url}\u003c/a\u003e\u003c/li\u003e`\n                ).join('')}\n            \u003c/ul\u003e\n        \u003c/body\u003e\n    \u003c/html\u003e`\n```\n\n\n# Template exports\n\n\n| Name | Purpose | Valid signatures\n| :--- | :--- | :--- |\n| `html` | Outputs the page content\u003cbr\u003eFunction is passed `content` and `meta` arguments to help render the page | `async (content, meta) =\u003e string`\u003cbr\u003e`string` |\n| `url` | Sets the page url\u003cbr\u003eMust begin with a `/`. | `async (content, meta) =\u003e string`\u003cbr\u003e`string` |\n| `content` | (optional) Use to fetch the data from anywhere\u003cbr\u003e(result is passed to `html` function) |  `async () =\u003e any`\u003cbr\u003e`any` |\n| `collection` | (optional) Fetch a set of items\u003cbr\u003eEach item generates a page | `async () =\u003e []`\u003cbr\u003e`[]` |\n| `perPage` | (optional) split a `collection` into chunks for pagination | `number` |\n\n\n### `html` and `url` function arguments\n\n#### `content`\n\n`content` is the value exported by your `content` or `collection` function in the template, whichever takes precedence.\n\n#### `meta`\n\n`meta` is an object with the following properties:\n\n- `url`: the pretty url returned from your `url` function (e.g. `/`)\n- `output`: the path to the file created (e.g. `/index.html`)\n- `outputDir`: absolute path to the output directory\n- `root`: relative path from the current page to the document root\n- `relative(pathFromRoot)`: returns the relative path to an asset from the current page\n- `currentPage`: the current page in a collection\n- `firstPage`: the first page in a collection\n- `lastPage`: the last page in a collection \n- `previousPage`: the previous page in a collection \n- `nextPage`: the next page in a collection \n- `firstIndexOnPage`: the first item on the current page (counting from 0) \n- `lastIndexOnPage`: the last item on the current page (counting from 0)\n- `firstItemOnPage`: the first item on the current page (counting from 1)\n- `lastItemOnPage`: the first item on the current page (counting from 1)\n\n\n### Page context (accessing `content` and `meta`)\n\nCalling `context()` within your template functions gives you access to the `content` and `meta` variables, without having to pass them through each function call (including within async components, or deep within the render tree)\n\n```js\nimport { context } from 'toast-static'\n\nconst { content, meta } = context()\n```\n\n\n# Contributing\n\nContributions welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoxmi%2Ftoast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoxmi%2Ftoast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoxmi%2Ftoast/lists"}