Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Tahul/sfc-composer

👨‍đŸ”Ŧ Pre-compiler helpers for Single File Components
https://github.com/Tahul/sfc-composer

compiler components sfc transformer

Last synced: about 1 month ago
JSON representation

👨‍đŸ”Ŧ Pre-compiler helpers for Single File Components

Awesome Lists containing this project

README

        

# sfc-composer

[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Github Actions][github-actions-src]][github-actions-href]

> 👨‍đŸ”Ŧ Pre-compiler helpers for Single File Components

> Currently supports: [.vue](https://vuejs.org), [.svelte](https://svelte.dev), [.astro](https://astro.build)

> [🕹ī¸ Playground](https://sfc-composer.netlify.app)

## Usage

Install package:

```bash
pnpm install sfc-composer
```

```js
import { MagicSFC as MagicVueSFC } from 'sfc-composer/vue'
import { MagicSFC as MagicSvelteSFC } from 'sfc-composer/svelte'
import { MagicSFC as MagicAstroSFC } from 'sfc-composer/astro'
```

## Internals

### ⚙ī¸ MagicSFC class

`MagicSFC` is the root interface supplied to be extended by framework-specific child classes.

- `scripts: MagicBlock[]`

Referring to `` or any `JavaScript/TypeScript` contexts of SFCs.

- `templates: MagicBlock<T>[]`

Referring to `<template>` parts of SFCs.

- `styles: MagicBlock<T>[]`

Referring to `<style>` parts of SFCs.

- `customs: MagicBlock<T>[]`

Custom blocks from frameworks parsers supporting that feature.

- `getSourcemap(options?: SourceMapOptions): SourceMap`

Generates a [version 3 sourcemap](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit) like [`MagicString`](https://www.npmjs.com/package/magic-string).

- `getTransformResult(): TransformResult`

Compatible with [Vite](https://vitejs.dev) `transform()` hook result.

- `parse(): Promise<MagicSFC>`

Uses the parser to update `MagicSFC` blocks.

Should be implemented by child classes.

Learn more about all the usages by looking at [the tests](/test/index.test.ts)!

### ⚙ī¸ How MagicSFC works

When using the `parse` function, `MagicSFC` will split the supplied component using your framework native tooling.

The parsing result will be splitted into a standard format recognizing `templates`, `scripts` and `styles` blocks.

Each 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.

Each of these function, when called, will both apply your changes on the local block.

You also get access to `_loc` and `_source` on every `MagicBlock`, which are standard copies of the block positioning and content.

When calling `result`, you will get the `code` as a string, and an appropriate `SourceMap` object.

Look at the [implementation](./src/proxy.ts).

### ⚙ī¸ createSFC functions

Frameworks exports a `createSfc` function that makes generating SFCs programatically easier.

They all support the same input aguments:

```ts
import { createSFC as createVueSFC } from 'sfc-composer/vue'
import { createSFC as createSvelteSFC } from 'sfc-composer/svelte'
import { createSFC as createAstroSFC } from 'sfc-composer/astro'

const writeableSFC = {
templates: [
{
content: '<div>Hello World!</div>'
}
],
scripts: [
{
content: 'console.log(`Hello World!`)'
}
],
styles: [
{
content: 'div { color: red; }'
}
]
}

// Will output a valid Svelte SFC
createSvelteSFC(writeableSFC)

// Will output a valid Astro SFC
createAstroSFC(writeableSFC)

// Will output a valid Vue SFC
createVueSFC({
...writeableSFC,
// Vue also natively supports `customs` block in its parser.
customs: [
{
type: 'i18n',
content: '{ "fr": "Bonjour!", "en": "Hello!" }',
}
]
})
```

## <img src="https://vuejs.org/logo.svg" width="24" height="24" /> MagicVueSFC

<details>
<summary>Example code</summary>

```ts
import { MagicSFC as MagicVueSFC } from 'sfc-composer/vue'
import { parse } from 'vue/compiler-sfc'

async function transformVueSFC() {
const sfc = new MagicVueSFC(
'<template><div>Hello World!</div></template>'
+ '<script setup>let test: string'
+ 'div { color: red; }',
{
parser: parse
}
)

// Process the SFC code through the parser
await sfc.parse()

// Append to the tag
sfc.scripts[0].append(' = `Hello World`')

return sfc.result()

// {
// code: '<template><div>Hello World!</div></template>\n\n<script setup>let test: string = `Hello World`\n\ndiv { color: red; }'
// map: SourceMap
// }
}
```

> Learn more by looking at [the tests](/test/vue.test.ts).

## createVueSFC

Example code

```ts
import { createSFC as createVueSFC } from 'sfc-composer/vue'

const MagicVueSFC = createVueSFC({
templates: [
{
content: '

{{ msg }}
',
}
],
script: [
{
content: 'export default { data() { return { msg: "Hello, world!" } } }'
},
{
content: 'const setupMsg = "Hello from setup!"',
}
],
styles: [
{
lang: 'scss',
scoped: true,
content: '.text { color: red; }',
},
],
})
```

#### 🖨ī¸ Will output

```

export default { data() { return { msg: "Hello, world!" } }


const setupMsg = "Hello from setup!"


{{ msg }}


.text { color: red; }

```

> Learn more by looking at [the tests](/test/vue.create.test.ts)!

## MagicSvelteSFC

Example code

```ts
import { MagicSFC as MagicSvelteSFC } from 'sfc-composer/svelte'
import { preprocess } from 'svelte/compiler'

async function transformSvelteSFC() {
const sfc = new MagicSvelteSFC(
'let test: string\n\n'
+ '

Hello World!
\n\n'
+ 'div { color: red; }',
{
parser: preprocess
}
)

// Process the SFC code through the parser
await sfc.parse()

// Append to the tag
sfc.scripts[0].append(' = `Hello World`')

return sfc.result()

// {
// code: '<script>let test: string = `Hello World`\n\n

Hello World!
\n\ndiv { color: red; }'
// map: SourceMap
// }
}
```

> Learn more by looking at [the tests](/test/svelte.test.ts)!

## createSvelteSFC

Example code

```ts
import { createSFC as createSvelteSFC } from 'sfc-composer/svelte'

const MagicVueSFC = createSvelteSFC({
templates: [
{
content: '

{msg}
',
}
],
script: [
{
content: 'let test = `Hello World!`;'
}
],
styles: [
{
content: '.text { color: red; }',
},
],
})
```

#### 🖨ī¸ Will output

```

let test = `Hello World!`;


const setupMsg = "Hello from setup!"

{msg}


.text { color: red; }

```

> Learn more by looking at [the tests](/test/svelte.create.test.ts)!

## MagicAstroSFC

Example code

```ts
import { MagicSFC as MagicAstroSFC } from 'sfc-composer/astro'
import { preprocess } from '@astrojs/compiler'

async function transformAstroSFC() {
const sfc = new MagicAstroSFC(
'---\nlet test: string\n---\n\n'
+ '

Hello World!
\n\n'
+ 'div { color: red; }',
{
parser: preprocess
}
)

// Process the SFC code through the parser
await sfc.parse()

// Append to the tag
sfc.scripts[0].append('test = `Hello World`')

return sfc.result()

// {
// code: '---\nlet test: string\ntest = `Hello World`\n---\n\n<div>Hello World!</div>\n\n<style>div { color: red; }</style>'
// map: SourceMap
// }
}
```

</details>

> Learn more by looking at [the tests](/test/astro.test.ts)!

## <img src="https://astro.build/favicon.svg" width="24" height="24" /> createAstroSFC

<details>
<summary>Example code</summary>

```ts
import { createSFC as createAstroSFC } from 'sfc-composer/astro'

const MagicVueSFC = createAstroSFC({
templates: [
{
content: '<div>{msg}</div>',
}
],
script: [
{
content: 'let test = `Hello World!`;',
attrs: {
frontmatter: true
}
},
{
content: 'let secondTest = `Hello World`;'
}
],
styles: [
{
content: '.text { color: red; }',
},
],
})
```

#### 🖨ī¸ Will output

```
---
let test = `Hello World!`;
---

<script>
let secondTest = `Hello World`;

{msg}


.text { color: red; }

```

> Learn more by looking at [the tests](/test/astro.create.test.ts)!

## Development

- Clone this repository
- Install latest LTS version of [Node.js](https://nodejs.org/en/)
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
- Install dependencies using `pnpm install`
- Run interactive tests using `pnpm dev`

## License

Made with 💚

Published under [MIT License](./LICENSE).

[npm-version-src]: https://img.shields.io/npm/v/sfc-composer?style=flat-square
[npm-version-href]: https://npmjs.com/package/sfc-composer
[npm-downloads-src]: https://img.shields.io/npm/dm/sfc-composer?style=flat-square
[npm-downloads-href]: https://npmjs.com/package/sfc-composer
[github-actions-src]: https://img.shields.io/github/actions/workflow/status/tahul/sfc-composer/ci.yml?branch=main&style=flat-square
[github-actions-href]: https://github.com/tahul/sfc-composer/actions?query=workflow%3Aci