{"id":16328799,"url":"https://github.com/marko-js/writable-dom","last_synced_at":"2025-04-04T09:10:09.914Z","repository":{"id":57399812,"uuid":"419491214","full_name":"marko-js/writable-dom","owner":"marko-js","description":"Utility to stream HTML content into a live document.","archived":false,"fork":false,"pushed_at":"2025-02-20T20:08:51.000Z","size":421,"stargazers_count":111,"open_issues_count":1,"forks_count":7,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-28T08:09:41.392Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/marko-js.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","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}},"created_at":"2021-10-20T21:13:04.000Z","updated_at":"2025-02-24T02:08:12.000Z","dependencies_parsed_at":"2025-02-27T21:22:00.659Z","dependency_job_id":"b96786fa-77e9-4647-b03b-682ccf0f6527","html_url":"https://github.com/marko-js/writable-dom","commit_stats":{"total_commits":8,"total_committers":2,"mean_commits":4.0,"dds":0.375,"last_synced_commit":"020d50b97d197334c8e6609eb949a0e6a361706e"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fwritable-dom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fwritable-dom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fwritable-dom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fwritable-dom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marko-js","download_url":"https://codeload.github.com/marko-js/writable-dom/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247149505,"owners_count":20891954,"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":[],"created_at":"2024-10-10T23:14:32.233Z","updated_at":"2025-04-04T09:10:09.886Z","avatar_url":"https://github.com/marko-js.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003c!-- Logo --\u003e\n  \u003cbr/\u003e\n  writable-dom\n\t\u003cbr/\u003e\n\n  \u003c!-- Format --\u003e\n  \u003ca href=\"https://github.com/prettier/prettier\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/styled_with-prettier-ff69b4.svg\" alt=\"Styled with prettier\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- CI --\u003e\n  \u003ca href=\"https://github.com/marko-js/writable-dom/actions/workflows/ci.yml\"\u003e\n    \u003cimg src=\"https://github.com/marko-js/writable-dom/actions/workflows/ci.yml/badge.svg\" alt=\"Build status\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Coverage --\u003e\n  \u003ca href=\"https://codecov.io/gh/marko-js/writable-dom\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/marko-js/writable-dom/branch/main/graph/badge.svg?token=06lKJj8my3\" alt=\"Code coverage\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- NPM Version --\u003e\n  \u003ca href=\"https://npmjs.org/package/writable-dom\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/writable-dom.svg\" alt=\"NPM version\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Downloads --\u003e\n  \u003ca href=\"https://npmjs.org/package/writable-dom\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dm/writable-dom.svg\" alt=\"Downloads\"/\u003e\n  \u003c/a\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Utility to stream HTML content into a live document.\n\u003c/p\u003e\n\n# Installation\n\n```console\nnpm install writable-dom\n```\n\n# How it works\n\nThis module allows you to write a stream of raw HTML chunks into an existing element in the DOM.\nEach chunk of HTML is handled in a way that is similar to how browsers process and display it.\n\nSpecifically blocking assets, including stylesheets and scripts, prevent adding newly parsed nodes to the target element.\nThis means that there are no flashes of unstyled content, and that scripts execution order follows the same rules as normal.\n\nOn top of that this module will look ahead for additional assets to preload while it is blocked.\n\n# Examples\n\nThe following examples fetch an HTML stream and place the content into a `#root` container element.\n\n```js\nimport WritableDOMStream from \"writable-dom\";\n\nconst res = await fetch(\"http://ebay.com\");\nconst myEl = document.getElementById(\"root\");\n\nawait res.body\n  .pipeThrough(new TextDecoderStream())\n  .pipeTo(new WritableDOMStream(myEl));\n```\n\nThe presented example relies on the [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)s API.\n\nAn alternative API is also available to use in case legacy browsers not implementing `WritableStream`s need to be supported.\n\nThe following is a version of the previous example implemented using the alternative API.\n\n```js\nimport writableDOM from \"writable-dom\";\n\nconst res = await fetch(\"https://ebay.com\");\nconst decoder = new TextDecoder();\nconst reader = res.body.getReader();\nconst myEl = document.getElementById(\"root\");\n\n// create a writable object to stream data into.\nconst writable = writableDOM(myEl);\n\ntry {\n  while (true) {\n    const { value, done } = await reader.read();\n    if (done) {\n      // wait for blocking assets to finish.\n      await writable.close();\n      break;\n    }\n\n    // write partial chunks of html.\n    writable.write(decoder.decode(value));\n  }\n} catch (err) {\n  // ensure the writable dom stops if there is an error.\n  writable.abort(err);\n}\n```\n\n# API\n\nThe module exposes a single default constructor function, once imported it can be used via one of the two following APIs.\n\n## `WritableStream` API\n\n```ts\nimport writableDOMStream from \"writable-dom\";\n\nnew WritableDOMStream(\n  target: ParentNode,\n  previousSibling?: ChildNode | null\n): WritableStream\n```\n\nBy instantiating a new object via the `new` keyword on the constructor function, the generated object will be of type [WritableStream\\\u003cstring\\\u003e](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream), which you can for example combine with your original stream via the [`pipeTo`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/pipeTo) method.\n\nYou can also provide `previousSibling` to have all written HTML be placed _after_ that node.\n\n## `Writable` API\n\n```ts\nimport writableDOM from \"writable-dom\";\n\nwritableDOM(\n  target: ParentNode,\n  previousSibling?: ChildNode | null\n): Writable\n```\n\nCalling the function directly creates a new `Writable` object which you can use to manually write HTML into the `target` element.\n\nAgain, you can also provide `previousSibling` to have all written HTML be placed _after_ that node.\n\nA `Writable` object provides the following methods:\n\n- `write(html: string): void`\\\n  Writes a partial chunk of HTML content into the `target` element.\n\n- `close(): Promise\u003cvoid\u003e`\\\n  Indicates that no additional HTML is going to be written.\n  Returns a promise that will resolve when all blocking assets have loaded and the content is being displayed in the document.\n  You should not call `write` after calling `close`.\n\n- `abort(err: Error): void`\n  Prevents any additional HTML from being written into the document and aborts any blocking assets.\n  You should not call `write` after calling `abort`.\n\n# Code of Conduct\n\nThis project adheres to the [eBay Code of Conduct](./.github/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarko-js%2Fwritable-dom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarko-js%2Fwritable-dom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarko-js%2Fwritable-dom/lists"}