{"id":17586956,"url":"https://github.com/antitoxic/prerender-spa-ultra","last_synced_at":"2025-04-28T20:03:52.149Z","repository":{"id":179706863,"uuid":"616058387","full_name":"antitoxic/prerender-spa-ultra","owner":"antitoxic","description":"Crawls \u0026 prerenders your SPA. Provides a GitHub Action, SEO-only mode, npm package \u0026 cli.","archived":false,"fork":false,"pushed_at":"2024-12-26T14:43:54.000Z","size":2428,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-28T20:03:34.584Z","etag":null,"topics":["cli","deployment","jamstack","npm-package","pinned","prerender","seo","social-network"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/antitoxic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"antitoxic"}},"created_at":"2023-03-19T13:52:24.000Z","updated_at":"2025-03-27T04:12:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"ed66a5ac-977d-4ac2-afc6-31891794c64b","html_url":"https://github.com/antitoxic/prerender-spa-ultra","commit_stats":null,"previous_names":["antitoxic/prerender-spa-ultra"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitoxic%2Fprerender-spa-ultra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitoxic%2Fprerender-spa-ultra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitoxic%2Fprerender-spa-ultra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitoxic%2Fprerender-spa-ultra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antitoxic","download_url":"https://codeload.github.com/antitoxic/prerender-spa-ultra/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251380914,"owners_count":21580338,"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":["cli","deployment","jamstack","npm-package","pinned","prerender","seo","social-network"],"created_at":"2024-10-22T03:25:14.942Z","updated_at":"2025-04-28T20:03:52.129Z","avatar_url":"https://github.com/antitoxic.png","language":"TypeScript","funding_links":["https://github.com/sponsors/antitoxic"],"categories":[],"sub_categories":[],"readme":"![prerender-spa-ultra: Generate static site from any application, whatever the tech stack. Get the benefits of Jamstack without binding yourself to specific framework or\nstatic generator](./docs/header.png)\n\n\u003cdiv align=\"center\"\u003e\n\nConverts your `JavaScript`-powered\n[SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA 'Single Page Application')\nweb application into individual `*.html` documents (_one for each unique `URL`\nyour app has_) filled with the content that your `JavaScript` generated for\nthem.\n\n[Usage](#prerender-spa-ultra-usage) — [Goals](#prerender-spa-ultra-goals) —\n[Limitations \u0026 Caveats](#prerender-spa-ultra-limitations)\n\n(available as _github `action`, `cli` command \u0026 `npm` package_)\n\n[![Open `prerender-spa-ultra` in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/antitoxic/prerender-spa-utlra)\n\n\u003c/div\u003e\n\n---\n\n### What is this for? (_purpose_)\n\n1. When your app uses `/deep/link/to/a/page` and you want to get a nice preview\n   of that page when its `URL` is shared.\n\n   Link sharing over most channels like messaging apps, social networks or other\n   websites will not run `JavaScript`, so they will preview your `URL` based on\n   your static `*.html` (_which is likely empty_). So if you want to preview\n   meaningful things that are shown with `JavaScript` like the page main image,\n   or the correct page title you want to `prerender`.\n\n2. When you expect slow connection to your\n   [SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA 'Single Page Application')\n   or huge size of your `JavaScript`. Instead of making your users wait staring\n   at a blank page you can `prerender` that page, so that the html that gets\n   loaded includes the corresponding content and only make the users wait for\n   `JavaScript` in order to interact with it\n\n\u003ca name=\"prerender-spa-ultra-usage\"\u003e\u003c/a\u003e\n\n## Usage\n\n1. As a `github action`\n   ([_» see all GitHub action settings_](#prerender-spa-ultra-github-action)):\n   ```yaml\n   uses: antitoxic/prerender-spa-ultra@v1\n   with:\n     website_root: 'path/to/your/spa/dist'\n   ```\n2. As `CLI` ([_» see all cli arguments_](#prerender-spa-ultra-cli)):\n\n   ```shell\n   # will automatically start http server\n   npx prerender-spa-ultra \u003cpath/to/your/output/dir\u003e\n   ```\n\n   You can prevent the http server from running or customize further\n   [via cli args](#prerender-spa-ultra-cli).\n\n3. As a `npm` package ([_» see full config_](#prerender-spa-ultra-npm-package)):\n   \u003e _In contrast to the other approaches, when using `prerender-spa-ultra`\n   \u003e programmatically you are responsible for starting the http server for your\n   \u003e static files. [» See examples](#http-server-with-fallback) how you can do\n   \u003e this._\n   ```typescript\n   import { preRenderSite } from 'prerender-spa-ultra';\n   //...\n   await preRenderSite({\n     outputDir: 'path/to/output',\n     // This is the url at which you started the static http server\n     startingUrl: 'http://localhost:8000',\n   });\n   ```\n\n\u003ca name=\"prerender-spa-ultra-github-action\"\u003e\u003c/a\u003e\n\n### `github action` usage\n\nBelow you can find an example of a job definition for prerendering your\nrepository via a GitHub workflow. Keep in mind that you can skip/remove\n`actions/setup-node@v3`, if you don't utilize `npm` caching.\n\nWhenever a GitHub workflow runs, `nodejs` is already available and is the exact\nversion needed, since `prerender-spa-ultra` is written considering this.\n\n```yaml\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          cache: npm\n      - name: Install\n        run: |\n          npm install\n      - name: Build\n        run: |\n          npm run build\n      - name: Prereder the freshly built app\n        uses: @antitoxic/prerender-spa-ultra@v1\n        id: prerender\n        with:\n          website_root: 'path/to/your/app/dist'\n          # the options below are optional:\n          max_concurrent_pages: 10\n          meta_prerender_only: \"1\"\n          selector_to_wait_for: \"[data-scraper=ready]\"\n```\n\nIf you are looking to deploy the final prerendered files to Cloudflare you can\nadd the following action in the end of your job:\n\n```yaml\n- name: Deploy to cloudflare\n  env:\n    CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n  run:\n    npx wrangler pages publish path/to/your/app/dist --project-name\n    REPLACE_WITH_YOUR_PROJECT_NAME\n```\n\n\u003ca name=\"prerender-spa-ultra-cli\"\u003e\u003c/a\u003e\n\n### `CLI` usage\n\nCheck the help output of `npx prerender-spa-ultra` or the self-explanatory\nsource code of the cli:\nhttps://github.com/antitoxic/prerender-spa-ultra/blob/main/src/prerenderer/cli.ts#L9-L83\n\n\u003ca name=\"prerender-spa-ultra-npm-package\"\u003e\u003c/a\u003e\n\n### `npm` package usage\n\n`preRenderSite(...)` config type definitions:\nhttps://github.com/antitoxic/prerender-spa-ultra/blob/main/src/prerenderer/prerender.ts#L59-L71\n\nIf you are not using the peer dependency `serve-handler` to\n[run http server for your static files](#http-server-with-fallback) you can skip\n\n## Debugging problems\n\nYou can enable logging:\n\n```shell\nPRERENDER_SPA_ULTRA_DEBUG=1 npx prerender-spa-ultra ....\n# or\nPRERENDER_SPA_ULTRA_DEBUG=1 \u003cyour command that uses this package programatically\u003e\n```\n\nor as GitHub job step:\n\n```yaml\n- name: Pre-render\n  uses: antitoxic/prerender-spa-ultra@v1\n  env:\n    PRERENDER_SPA_ULTRA_DEBUG: 1\n  with:\n    website_root: dist\n```\n\n\u003ca name=\"http-server-with-fallback\"\u003e\u003c/a\u003e\n\n## Serving your [SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA 'Single Page Application') static files with local http server\n\nThe `prerender-spa-ultra`'s cli \u0026 GitHub action internally use the\n`serve-handler` npm package to start a http server but there are multiple\nalternatives:\n\n```shell\ncd \u003cpath/to/static/files/root/dir/\u003e\n# and then one of:\nnpx serve --single\nnpx node-static --spa\nnpx http-server --proxy \"http://localhost:8080?\"\n```\n\nIf you are trying to minimize dependencies and don't want to use those, you can\nrely on the included `http-server.py` (_python 3_):\n\n```shell\ncd \u003cpath/to/static/files/root/dir/\u003e\npython \u003cpath/to/node_modules\u003e/prerender-spa-ultra/src/http-server.py\n```\n\n\u003ca name=\"prerender-spa-ultra-limitations\"\u003e\u003c/a\u003e\n\n## Limitations \u0026 Caveats\n\n1. This library shares 2 limitations that any other pre-rendering lib has:\n   1. It doesn't work with hash-based routing of SPAs (i.e.\n      `example.com/#route`). This is because the server never sees the `#...`\n      part of the url, so it can't find a file based on it. If you are in this\n      scenario you can try migrating to html5 push history.\n   2. Your assets (_media files, `*.js`, `*.css`_) should not be linked as\n      relative paths since pre-rendering creates a nested folder structure to\n      match the urls you have. Instead, those should be linked from your URL\n      root (`/...`).\n2. The library will ignore query params and consider all urls having matching\n   `pathname` to be one and the same url. You can override this by providing a\n   custom `cleanUrl` and `getFilename` functions to `preRenderSite`. It will be\n   up to you to configure your http server to route such urls with query params\n   to their respective static file (created by `getFilename`).\n3. The default `cleanUrl` trims any slashes, which means `some/url/path/` and\n   `some/url/path` will be considered the same\n\n\u003ca name=\"prerender-spa-ultra-goals\"\u003e\u003c/a\u003e\n\n## Goals of `prerender-spa-ultra`\n\n- **Simplest prerender out there**\n  - Single programmatic dependency (`puppeteer-core`), nothing else besides the\n    peer dependency for the automatic http server in CLI (which _you can opt\n    out_). This also means saving build-time otherwise spend downloading\n    packages \u0026 binaries on every build\n  - Pre-renderer with the lowest bug surface (including dependencies) - written\n    in the most concise way possible while keeping readability-first design\n  - Know what you are executing — One of the goals for `prerender-spa-ultra` is\n    to be easy to understand from just reading the code.\n  - Uses already available packages \u0026 binaries on the OS it's running on (_see\n    [Built with CI/CD \u0026 JAMSTACK in mind](#serverless)_)\n- **Crawls your site**. It will find all you URLs that need prerendering as long\n  as they are linked from another page. You don't need to provide explicit list\n  of urls to prerender, just pass the URL you want to start with.\n- **Optimized for speed of pre-rendering**\n  - Stops crawling as soon as possible\n  - Blocks unnecessary for the pre-rendering resources from loading (_blocking\n    is configurable_). By default, it blocks the following:\n    - fonts\n    - images \u0026 media\n    - some known third party scripts (_your site shouldn't fail without them_)\n  - Concurrent crawling \u0026 concurrent pre-rendering (_concurrency is\n    configurable_)\n    - Creates a pool of browser pages for pre-rendering in parallel\n    - Reuses the pages instead of destroying and recreating them\n  - All IO operations are async, no filesystem or network calls that are\n    blocking\n- \u003ca name=\"serverless\"\u003e\u003c/a\u003e**Built with CI/CD \u0026 JAMSTACK in mind**\n  - Provides configurations for Github Action \u0026 Cloudflare pages deployment\n  - Targets and uses already available packages on those build images\n\n## Non-goals of `prerender-spa-ultra`\n\n`prerender-spa-ultra` has a narrow goal. Let's keep expectation clear:\n\n- `prerender-spa-ultra` is not going to **optimize the output html files**. It's\n  far more efficient to do that beforehand in your main SPA assets-build step.\n- `prerender-spa-ultra` is not going to **prerender any site you provide**. This\n  is specifically made to work together with the local http static file server\n  included in it. The purpose of this is making sure you get the maximum\n  performance + taking care of some edge case scenarios in headless chrome\n- `prerender-spa-ultra` is not going to **provide 100% of the options as CLI\n  arguments**. Only the basic customizations are possible by passing CLI\n  arguments. If you want to do something more advanced, import\n  `prerender-spa-ultra` as a nodejs module and call it with all the options you\n  need.\n- `prerender-spa-ultra` is not going to **install chrome or chromium**. If you\n  are using GitHub workflows or similar, it's likely to have it already\n  installed. Otherwise, you can use the OS package manager to install or use\n  `node-chromium` (`npm install chromium`)\n\n## Funding\n\nWill be opened very soon, waiting for GitHub sponsorship approval :)\n\n## Prior art\n\n- https://github.com/egoist/presite\n- https://github.com/stereobooster/react-snap\n- https://github.com/dattran92/site-prerender\n- https://github.com/JoshTheDerf/prerenderer\n- https://github.com/sPavl0v/react-spa-prenderer\n- https://github.com/chrisvfritz/prerender-spa-plugin\n\n## External Pre-render Services available\n\n- https://webprerender.io/pricing/\n- https://prerender.io/\n\n## Marketing locations\n\n- https://github.com/automata/awesome-jamstack\n- (old) https://www.tnd.dev/tool/\n\n# Background \u0026 References\n\n- Not ideal to use `JSDOM` since it can't safely execute `\u003cscript/\u003e`s\n- Good Jamstack intro video: https://vimeo.com/163522126 and the rest:\n  https://jamstack.org/resources/videos/\n- Available binary packages in various CI/CD pre-build images:\n  - https://github.com/cloudflare/pages-build-image/discussions/1 \u0026\n    https://developers.cloudflare.com/pages/platform/build-configuration/\n  - https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md\n  - https://github.com/netlify/build-image/blob/focal/included_software.md\n- Reserved tlds for local work https://news.ycombinator.com/item?id=12578908\n- GitHub actions running locally:\n  - https://stackoverflow.com/questions/59241249/how-to-run-prerender-spa-ultra-github-actions-workflows-locally\n  - https://github.com/nektos/act\n\n## Cloudflare integration\n\nhttps://developers.cloudflare.com/workers/wrangler/ci-cd/\n\nTo use cloudflare cli (`wrangler`) from CI like GitHub actions you need to\ncreate `CLOUDFLARE_API_TOKEN` and add it as a secret in that CI environment\n\nMaybe you will need to set `CLOUDFLARE_ACCOUNT_ID` if you have more than 1\naccount associated with this API token.\n\nMust expose GitHub secret as ENV variable (not done by default)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantitoxic%2Fprerender-spa-ultra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantitoxic%2Fprerender-spa-ultra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantitoxic%2Fprerender-spa-ultra/lists"}