{"id":16259659,"url":"https://github.com/tahul/sfc-composer","last_synced_at":"2025-03-16T13:30:57.104Z","repository":{"id":143458751,"uuid":"611002965","full_name":"Tahul/sfc-composer","owner":"Tahul","description":"👨‍🔬 Pre-compiler helpers for Single File Components","archived":false,"fork":false,"pushed_at":"2023-10-19T00:26:18.000Z","size":4829,"stargazers_count":58,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-19T04:27:00.736Z","etag":null,"topics":["compiler","components","sfc","transformer"],"latest_commit_sha":null,"homepage":"https://sfc-composer.netlify.app","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/Tahul.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-07T22:55:32.000Z","updated_at":"2024-07-03T18:36:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"31680148-97b3-44d0-8ab5-60b4f7c3b245","html_url":"https://github.com/Tahul/sfc-composer","commit_stats":{"total_commits":69,"total_committers":2,"mean_commits":34.5,"dds":0.01449275362318836,"last_synced_commit":"731990e76e53e94132de58b903d181ffcb9b1dfc"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":"unjs/template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tahul%2Fsfc-composer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tahul%2Fsfc-composer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tahul%2Fsfc-composer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tahul%2Fsfc-composer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tahul","download_url":"https://codeload.github.com/Tahul/sfc-composer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243815576,"owners_count":20352194,"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":["compiler","components","sfc","transformer"],"created_at":"2024-10-10T16:04:07.568Z","updated_at":"2025-03-16T13:30:55.457Z","avatar_url":"https://github.com/Tahul.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sfc-composer\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![Github Actions][github-actions-src]][github-actions-href]\n\n\u003e 👨‍🔬 Pre-compiler helpers for Single File Components\n\n\u003e Currently supports: [.vue](https://vuejs.org), [.svelte](https://svelte.dev), [.astro](https://astro.build)\n\n\u003e [🕹️ Playground](https://sfc-composer.netlify.app)\n\n## Usage\n\nInstall package:\n\n```bash\npnpm install sfc-composer\n```\n\n```js\nimport { MagicSFC as MagicVueSFC } from 'sfc-composer/vue'\nimport { MagicSFC as MagicSvelteSFC } from 'sfc-composer/svelte'\nimport { MagicSFC as MagicAstroSFC } from 'sfc-composer/astro'\n```\n\n## Internals\n\n### ⚙️ MagicSFC class\n\n`MagicSFC\u003cT\u003e` is the root interface supplied to be extended by framework-specific child classes.\n\n- `scripts: MagicBlock\u003cT\u003e[]`\n\n  Referring to `\u003cscript\u003e` or any `JavaScript/TypeScript` contexts of SFCs.\n\n- `templates: MagicBlock\u003cT\u003e[]`\n\n  Referring to `\u003ctemplate\u003e` parts of SFCs.\n\n- `styles: MagicBlock\u003cT\u003e[]`\n\n  Referring to `\u003cstyle\u003e` parts of SFCs.\n\n- `customs: MagicBlock\u003cT\u003e[]`\n\n  Custom blocks from frameworks parsers supporting that feature.\n\n- `getSourcemap(options?: SourceMapOptions): SourceMap`\n\n  Generates a [version 3 sourcemap](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit) like [`MagicString`](https://www.npmjs.com/package/magic-string).\n\n- `getTransformResult(): TransformResult`\n\n  Compatible with [Vite](https://vitejs.dev) `transform()` hook result.\n\n- `parse(): Promise\u003cMagicSFC\u003e`\n\n  Uses the parser to update `MagicSFC` blocks.\n\nShould be implemented by child classes.\n\nLearn more about all the usages by looking at [the tests](/test/index.test.ts)!\n\n### ⚙️ How MagicSFC works\n\nWhen using the `parse` function, `MagicSFC` will split the supplied component using your framework native tooling.\n\nThe parsing result will be splitted into a standard format recognizing `templates`, `scripts` and `styles` blocks.\n\nEach of these `MagicBlock` will preserve the original shape from the parser, but will also expose all the relevant [MagicString](https://www.npmjs.com/package/magic-string) functions.\n\nEach of these function, when called, will both apply your changes on the local block.\n\nYou also get access to `_loc` and `_source` on every `MagicBlock`, which are standard copies of the block positioning and content.\n\nWhen calling `result`, you will get the `code` as a string, and an appropriate `SourceMap` object.\n\nLook at the [implementation](./src/proxy.ts).\n\n### ⚙️ createSFC functions\n\nFrameworks exports a `createSfc` function that makes generating SFCs programatically easier.\n\nThey all support the same input aguments:\n\n```ts\nimport { createSFC as createVueSFC } from 'sfc-composer/vue'\nimport { createSFC as createSvelteSFC } from 'sfc-composer/svelte'\nimport { createSFC as createAstroSFC } from 'sfc-composer/astro'\n\nconst writeableSFC = {\n  templates: [\n    {\n      content: '\u003cdiv\u003eHello World!\u003c/div\u003e'\n    }\n  ],\n  scripts: [\n    {\n      content: 'console.log(`Hello World!`)'\n    }\n  ],\n  styles: [\n    {\n      content: 'div { color: red; }'\n    }\n  ]\n}\n\n// Will output a valid Svelte SFC\ncreateSvelteSFC(writeableSFC)\n\n// Will output a valid Astro SFC\ncreateAstroSFC(writeableSFC)\n\n// Will output a valid Vue SFC\ncreateVueSFC({\n  ...writeableSFC,\n  // Vue also natively supports `customs` block in its parser.\n  customs: [\n    {\n      type: 'i18n',\n      content: '{ \"fr\": \"Bonjour!\", \"en\": \"Hello!\" }',\n    }\n  ]\n})\n```\n\n## \u003cimg src=\"https://vuejs.org/logo.svg\" width=\"24\" height=\"24\" /\u003e MagicVueSFC\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample code\u003c/summary\u003e\n\n  ```ts\n  import { MagicSFC as MagicVueSFC } from 'sfc-composer/vue'\n  import { parse } from 'vue/compiler-sfc'\n\n  async function transformVueSFC() {\n    const sfc = new MagicVueSFC(\n      '\u003ctemplate\u003e\u003cdiv\u003eHello World!\u003c/div\u003e\u003c/template\u003e'\n      + '\u003cscript setup\u003elet test: string\u003c/script\u003e'\n      + '\u003cstyle scoped\u003ediv { color: red; }\u003c/style\u003e',\n      {\n        parser: parse\n      }\n    )\n\n    // Process the SFC code through the parser\n    await sfc.parse()\n\n    // Append to the \u003cscript\u003e tag\n    sfc.scripts[0].append(' = `Hello World`')\n\n    return sfc.result()\n\n    // {\n    //    code: '\u003ctemplate\u003e\u003cdiv\u003eHello World!\u003c/div\u003e\u003c/template\u003e\\n\\n\u003cscript setup\u003elet test: string = `Hello World`\u003c/script\u003e\\n\\n\u003cstyle scoped\u003ediv { color: red; }\u003c/style\u003e'\n    //    map: SourceMap\n    // }\n  }\n  ```\n\n\u003c/details\u003e\n\n\u003e Learn more by looking at [the tests](/test/vue.test.ts).\n\n## \u003cimg src=\"https://vuejs.org/logo.svg\" width=\"24\" height=\"24\" /\u003e createVueSFC\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample code\u003c/summary\u003e\n\n  ```ts\n  import { createSFC as createVueSFC } from 'sfc-composer/vue'\n\n  const MagicVueSFC = createVueSFC({\n    templates: [\n      {\n        content: '\u003cdiv\u003e{{ msg }}\u003c/div\u003e',\n      }\n    ],\n    script: [\n      {\n        content: 'export default { data() { return { msg: \"Hello, world!\" } } }'\n      },\n      {\n        content: 'const setupMsg = \"Hello from setup!\"',\n      }\n    ],\n    styles: [\n      {\n        lang: 'scss',\n        scoped: true,\n        content: '.text { color: red; }',\n      },\n    ],\n})\n```\n\n  #### 🖨️ Will output\n\n  ```\n  \u003cscript\u003e\n  export default { data() { return { msg: \"Hello, world!\" } }\n  \u003c/script\u003e\n\n  \u003cscript setup\u003e\n  const setupMsg = \"Hello from setup!\"\n  \u003c/script\u003e\n\n  \u003ctemplate\u003e\n  \u003cdiv\u003e{{ msg }}\u003c/div\u003e\n  \u003c/template\u003e\n\n  \u003cstyle scoped lang=\"scss\"\u003e\n  .text { color: red; }\n  \u003c/style\u003e\n  ```\n\n\u003c/details\u003e\n\n\u003e Learn more by looking at [the tests](/test/vue.create.test.ts)!\n\n## \u003cimg src=\"https://svelte.dev/favicon.png\" width=\"24\" height=\"24\" /\u003e  MagicSvelteSFC\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample code\u003c/summary\u003e\n\n  ```ts\n  import { MagicSFC as MagicSvelteSFC } from 'sfc-composer/svelte'\n  import { preprocess } from 'svelte/compiler'\n\n  async function transformSvelteSFC() {\n    const sfc = new MagicSvelteSFC(\n      '\u003cscript\u003elet test: string\u003c/script\u003e\\n\\n'\n      + '\u003cdiv\u003eHello World!\u003c/div\u003e\\n\\n'\n      + '\u003cstyle\u003ediv { color: red; }\u003c/style\u003e',\n      {\n        parser: preprocess\n      }\n    )\n\n    // Process the SFC code through the parser\n    await sfc.parse()\n\n    // Append to the \u003cscript\u003e tag\n    sfc.scripts[0].append(' = `Hello World`')\n\n    return sfc.result()\n\n    // {\n    //    code: '\u003cscript\u003elet test: string = `Hello World`\u003c/script\u003e\\n\\n\u003cdiv\u003eHello World!\u003c/div\u003e\\n\\n\u003cstyle\u003ediv { color: red; }\u003c/style\u003e'\n    //    map: SourceMap\n    // }\n  }\n  ```\n\n\u003c/details\u003e\n\n\u003e Learn more by looking at [the tests](/test/svelte.test.ts)!\n\n## \u003cimg src=\"https://svelte.dev/favicon.png\" width=\"24\" height=\"24\" /\u003e  createSvelteSFC\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample code\u003c/summary\u003e\n\n  ```ts\n  import { createSFC as createSvelteSFC } from 'sfc-composer/svelte'\n\n  const MagicVueSFC = createSvelteSFC({\n    templates: [\n      {\n        content: '\u003cdiv\u003e{msg}\u003c/div\u003e',\n      }\n    ],\n    script: [\n      {\n        content: 'let test = `Hello World!`;'\n      }\n    ],\n    styles: [\n      {\n        content: '.text { color: red; }',\n      },\n    ],\n})\n```\n\n  #### 🖨️ Will output\n\n  ```\n  \u003cscript\u003e\n  let test = `Hello World!`;\n  \u003c/script\u003e\n\n  \u003cscript setup\u003e\n  const setupMsg = \"Hello from setup!\"\n  \u003c/script\u003e\n\n  \u003cdiv\u003e{msg}\u003c/div\u003e\n\n  \u003cstyle\u003e\n  .text { color: red; }\n  \u003c/style\u003e\n  ```\n\n\u003c/details\u003e\n\n\u003e Learn more by looking at [the tests](/test/svelte.create.test.ts)!\n\n## \u003cimg src=\"https://astro.build/favicon.svg\" width=\"24\" height=\"24\" /\u003e MagicAstroSFC\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample code\u003c/summary\u003e\n\n  ```ts\n  import { MagicSFC as MagicAstroSFC } from 'sfc-composer/astro'\n  import { preprocess } from '@astrojs/compiler'\n\n  async function transformAstroSFC() {\n    const sfc = new MagicAstroSFC(\n      '---\\nlet test: string\\n---\\n\\n'\n      + '\u003cdiv\u003eHello World!\u003c/div\u003e\\n\\n'\n      + '\u003cstyle\u003ediv { color: red; }\u003c/style\u003e',\n      {\n        parser: preprocess\n      }\n    )\n\n    // Process the SFC code through the parser\n    await sfc.parse()\n\n    // Append to the \u003cscript\u003e tag\n    sfc.scripts[0].append('test = `Hello World`')\n\n    return sfc.result()\n\n    // {\n    //    code: '---\\nlet test: string\\ntest = `Hello World`\\n---\\n\\n\u003cdiv\u003eHello World!\u003c/div\u003e\\n\\n\u003cstyle\u003ediv { color: red; }\u003c/style\u003e'\n    //    map: SourceMap\n    // }\n  }\n  ```\n\n\u003c/details\u003e\n\n\u003e Learn more by looking at [the tests](/test/astro.test.ts)!\n\n## \u003cimg src=\"https://astro.build/favicon.svg\" width=\"24\" height=\"24\" /\u003e createAstroSFC\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample code\u003c/summary\u003e\n\n  ```ts\n  import { createSFC as createAstroSFC } from 'sfc-composer/astro'\n\n  const MagicVueSFC = createAstroSFC({\n    templates: [\n      {\n        content: '\u003cdiv\u003e{msg}\u003c/div\u003e',\n      }\n    ],\n    script: [\n      {\n        content: 'let test = `Hello World!`;',\n        attrs: {\n          frontmatter: true\n        }\n      },\n      {\n        content: 'let secondTest = `Hello World`;'\n      }\n    ],\n    styles: [\n      {\n        content: '.text { color: red; }',\n      },\n    ],\n})\n```\n\n  #### 🖨️ Will output\n\n  ```\n  ---\n  let test = `Hello World!`;\n  ---\n\n  \u003cscript\u003e\n  let secondTest = `Hello World`;\n  \u003c/script\u003e\n\n  \u003cdiv\u003e{msg}\u003c/div\u003e\n\n  \u003cstyle\u003e\n  .text { color: red; }\n  \u003c/style\u003e\n  ```\n\n\u003c/details\u003e\n\n\u003e Learn more by looking at [the tests](/test/astro.create.test.ts)!\n\n## Development\n\n- Clone this repository\n- Install latest LTS version of [Node.js](https://nodejs.org/en/)\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev`\n\n## License\n\nMade with 💚\n\nPublished under [MIT License](./LICENSE).\n\n\u003c!-- Badges --\u003e\n\n[npm-version-src]: https://img.shields.io/npm/v/sfc-composer?style=flat-square\n[npm-version-href]: https://npmjs.com/package/sfc-composer\n[npm-downloads-src]: https://img.shields.io/npm/dm/sfc-composer?style=flat-square\n[npm-downloads-href]: https://npmjs.com/package/sfc-composer\n[github-actions-src]: https://img.shields.io/github/actions/workflow/status/tahul/sfc-composer/ci.yml?branch=main\u0026style=flat-square\n[github-actions-href]: https://github.com/tahul/sfc-composer/actions?query=workflow%3Aci\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftahul%2Fsfc-composer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftahul%2Fsfc-composer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftahul%2Fsfc-composer/lists"}