{"id":16328396,"url":"https://github.com/marko-js/micro-frame","last_synced_at":"2026-02-21T04:31:30.815Z","repository":{"id":37894248,"uuid":"413958045","full_name":"marko-js/micro-frame","owner":"marko-js","description":"A Marko tag for building SSR friendly micro frontends.","archived":false,"fork":false,"pushed_at":"2025-03-07T22:35:07.000Z","size":1023,"stargazers_count":57,"open_issues_count":2,"forks_count":9,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-10-21T14:41:07.205Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Marko","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":null,"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,"zenodo":null}},"created_at":"2021-10-05T19:46:59.000Z","updated_at":"2025-09-28T16:00:40.000Z","dependencies_parsed_at":"2024-02-26T20:34:35.580Z","dependency_job_id":"413c01a2-75e4-411d-8c9b-5e763e75225d","html_url":"https://github.com/marko-js/micro-frame","commit_stats":{"total_commits":20,"total_committers":5,"mean_commits":4.0,"dds":0.4,"last_synced_commit":"fc36c57a3522c5a9a766220f2668f91aec7dd328"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/marko-js/micro-frame","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fmicro-frame","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fmicro-frame/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fmicro-frame/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fmicro-frame/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marko-js","download_url":"https://codeload.github.com/marko-js/micro-frame/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Fmicro-frame/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29673785,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T03:11:15.450Z","status":"ssl_error","status_checked_at":"2026-02-21T03:10:34.920Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":[],"created_at":"2024-10-10T23:14:18.018Z","updated_at":"2026-02-21T04:31:30.760Z","avatar_url":"https://github.com/marko-js.png","language":"Marko","funding_links":[],"categories":["Marko"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003c!-- Logo --\u003e\n  \u003cbr/\u003e\n  @micro-frame/marko\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!-- Coverage --\u003e\n  \u003ca href=\"https://codecov.io/gh/marko-js/micro-frame\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/marko-js/micro-frame/branch/main/graph/badge.svg?token=cSvMDikbE4\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- NPM Version --\u003e\n  \u003ca href=\"https://npmjs.org/package/@micro-frame/marko\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/@micro-frame/marko.svg\" alt=\"NPM Version\"/\u003e\n  \u003c/a\u003e\n  \u003c!-- Downloads --\u003e\n  \u003ca href=\"https://npmjs.org/package/@micro-frame/marko\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dm/@micro-frame/marko.svg\" alt=\"Downloads\"/\u003e\n  \u003c/a\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  A Marko tag for building SSR friendly micro frontends.\n\u003c/p\u003e\n\n# Installation\n\n```console\nnpm install @micro-frame/marko\n```\n\n# How it works\n\nThis package exposes a `\u003cmicro-frame\u003e` Marko component that in many ways is similar to a traditional `\u003ciframe\u003e`.\nHowever, unlike an `iframe`, the content from the `src` is loaded, with streaming support, _directly_ into the existing document.\n\n## On the server\n\nWhen this component is rendered server side, it will make a request to load the embedded html resource. The response is then streamed along side the content for the host page.\n\nInternally [make-fetch-happen](https://github.com/zkat/make-fetch-happen) is used to perform the requests from the server. These means you can also leverage [HTTP Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).\n\n## In the browser\n\nWhen rendered client side a normal fetch request is made to load the embedded html resource. The content of the response will be rendered within the page _as if_ it was a server side render. This includes full streaming support.\n\nAny time the `src` attribute is changed, a new request will be made to load updated html content.\n\n## Why\n\nThis module allows for embedded micro frontends with the following benefits:\n\n1. Can take full advantage of streaming, if loaded server side _or_ in the browser.\n2. Both the host, and embedded applications simply respond with HTML.\n3. Framework agnostic, the child can respond with HTML generated by any tool/framework.\n\nSpecifically in comparison to iframes it offers the following advantages:\n\n- Usability\n  - Control over loading \u0026 error state rendering.\n  - Does not break navigation / back button.\n  - Does not appear differently to screen readers.\n  - Does not cause issues using native browser API’s that are sometimes restricted in iframes.\n  - Content can rendered with the rest of the page\n    - No resizing issues.\n    - Flows with page content / layout.\n    - Can escape it’s container, eg for modals\n- Performance\n  - Shares single connection with host (no round trip once iframe makes it to the browser).\n  - Does not impact SEO (sometimes iframes are not indexed by search engines).\n  - iframes receive lower priority than other assets on the page, this does not.\n  - Avoids additional window / browser context (less memory used).\n  - Avoids boilerplate html, just send fragments (no `\u003chtml\u003e`, `\u003chead\u003e`, etc).\n  - Caches in both the client and host server.\n\n## Why not\n\nThis module works best when you have applications that are independently developed, potentially with different technology stacks, that you want to glue together.\n\n- Applications broken up this way in general are harder to optimize, deploy, etc.\n- Embedded apps _should_ be served from the same origin/TLD to prevent CORS issues. You should not embed _untrusted_ applications, you should consider the embedded application a part of the host page.\n- There will always be overhead in this approach, or really any naive micro-frontend setup. This module does not dictate how assets are loaded or shared across applications. If necessary that must be orchestrated between the applications separately. Solutions like [Module federation](https://webpack.js.org/concepts/module-federation/), native ES modules \u0026 globally available modules should work fine with `micro-frame`.\n\n# Example\n\n```marko\n\u003cmicro-frame src=\"my-nested-app\"\u003e\n  \u003c@loading\u003e\n    We're still loading...\n  \u003c/@loading\u003e\n  \u003c@catch|err|\u003e\n    Uh-oh! ${err.message}\n  \u003c/@catch\u003e\n\u003c/micro-frame\u003e\n```\n\n# API\n\n## `src`\n\nA (required) path to the embedded html application. This is resolved from the [`origin`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin) of the of the host application.\n\n```marko\n\u003cmicro-frame src=\"my-nested-app\"/\u003e\n```\n\nWith the above, assuming the host application is rendered at `https://ebay.com/n/all-categories`, the embedded application will resolve to `https://ebay.com/my-nested-app`.\n\n## `headers`\n\nOptionally provide additional http headers to send. Only the object form shown below is supported.\n\n```marko\n\u003cmicro-frame src=\"...\" headers={\n  \"X-My-Header\": \"Hello\",\n  \"X-Another-Header\": \"World\"\n}/\u003e\n```\n\n\u003e Note that be default on the server side headers are copied from the current incoming request, the `headers` option will be merged with existing headers.\n\n## `cache`\n\nMirrors the [`Request.cache` options](https://developer.mozilla.org/en-US/docs/Web/API/Request/cache) (works on both server and client renders).\n\n```marko\n\u003c!--\nThis example will always show cached content if available\nand fallback to the network otherwise\n--\u003e\n\u003cmicro-frame src=\"...\" cache=\"force-cache\"/\u003e\n```\n\n## `fetch`\n\nOptionally provide function to override default `fetch` logic.\n\n```marko\n\u003cmicro-frame src=\"...\" name=\"...\" fetch(url, options, fetch) {\n  // The 3rd parameter allows us to continue to use micro-frames fetch implementation (which is different server/browser).\n  // We can use this override to do things like a POST request, eg:\n  return fetch(url, {\n    ...options,\n    method: \"POST\",\n    headers: {\n      ...headers,\n      \"Content-Type\": \"application/json\"\n    },\n    body: JSON.stringify({ \"some\": \"json\" })\n  });\n}  /\u003e\n```\n\n## `timeout`\n\nA timeout in `ms` (defaults to 30s) that will prematurely abort the request. This will trigger the `\u003c@catch\u003e` if provided.\nIf set to `0` the request will not time out.\n\n```marko\n\u003c!--\nThis example will disable the default 30s timeout.\n--\u003e\n\u003cmicro-frame src=\"...\" timeout=0/\u003e\n```\n\n## `\u003c@catch|err|\u003e`\n\nAn [attribute tag](https://markojs.com/docs/syntax/#attribute-tag) rendered when there is a network error or timeout.\nIf there is no `@catch` handler the error will be emitted to the stream, similar to the [`\u003cawait\u003e`](https://markojs.com/docs/core-tags/#await) tag.\n\n```marko\n\u003cmicro-frame src=\"...\"\u003e\n  \u003c@catch|err|\u003e\n    \u003c!-- Displays if request to service fails or times out --\u003e\n    error: ${err.message}\n  \u003c/@catch\u003e\n\u003c/micro-frame\u003e\n```\n\n## `\u003c@loading\u003e`\n\nAn [attribute tag](https://markojs.com/docs/syntax/#attribute-tag) rendered when while the request is still being streamed.\nIt is removed after the request has either errored, or successfully loaded.\n\n```marko\n\u003cmicro-frame src=\"...\"\u003e\n  \u003c@loading\u003e\n    We are loading the nested app...\n    \u003cmy-spinner/\u003e\n  \u003c/@loading\u003e\n\u003c/micro-frame\u003e\n```\n\n## `class`\n\nOptional `class` attribute which works the same way as [Marko class attribute](https://markojs.com/docs/syntax/#class-attribute).\n\n```marko\n\u003cmicro-frame src=\"...\" class=\"a c\"/\u003e\n\u003cmicro-frame src=\"...\" class={ a:true, b:false, c:true }/\u003e\n\u003cmicro-frame src=\"...\" class=[\"a\", null, { c:true }]/\u003e\n```\n\n## `style`\n\nOptional `style` attribute which works the same way as [Marko style attribute](https://markojs.com/docs/syntax/#style-attribute).\n\n```marko\n\u003cmicro-frame src=\"...\" style=\"display:block;margin-right:16px\"/\u003e\n\u003cmicro-frame src=\"...\" style={ display: \"block\", color: false, marginRight: 16 }/\u003e\n\u003cmicro-frame src=\"...\" style=[\"display:block\", null, { marginRight: 16 }]/\u003e\n```\n\n## `client-reorder`\n\nSimilar to the [`\u003cawait\u003e` tag client-reorder attribute](https://markojs.com/docs/core-tags/#await), this tells the micro-frame to avoid blocking content later in the document.\n\n\u003e Note when this is used the micro-frame will be buffered instead of streamed and inserted once it's ready.\n\n# Communicating between host and child\n\nCommunicating with the embedded application happens primarily in one of two ways, either you want to do a full reload of and get new HTML, or you want to orchestrate a client side rendered update.\n\n### Full reload\n\nTo perform a full reload of the embedded application it works best to pass a query string in the `src` attribute. Whenever `src` updates, a full reload will happen automatically.\n\n```marko\nclass {\n  onCreate() {\n    this.state = { page: 0 };\n  }\n\n  nextPage() {\n    this.state.page++;\n  }\n}\n\n\u003cmicro-frame src=`my-nested-app?page=${state.page}`/\u003e\n\n\u003cbutton onClick(\"nextPage\")\u003eNext Page\u003c/button\u003e\n```\n\nWith the above, any time `state.page` changes the `my-nested-app` content will be re-loaded.\n\n### Client side update\n\nClient side communication between the host and child application can be done through a number of mechanisms.\nYou can use a global store, store data on the dom (perhaps even use web components) or other creative options.\n\nYou can do this relatively simply by having a contract between the host and child application.\nBelow is an example using a global exposed by the nested application.\n\n```marko\nclass {\n  onCreate() {\n    this.state = { page: 0 };\n  }\n\n  openModal() {\n    if (window.nestedApp) {\n      window.nestedApp.openModal();\n    }\n  }\n}\n\n\u003cmicro-frame src=\"my-nested-app\"/\u003e\n\n\u003cbutton onClick(\"openModal\")\u003eOpen nested app modal\u003c/button\u003e\n```\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%2Fmicro-frame","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarko-js%2Fmicro-frame","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarko-js%2Fmicro-frame/lists"}