Skip to content

Commit

Permalink
Add hydrate method to style sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
drozdzynski committed May 28, 2024
1 parent bb70b5f commit 2416abd
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-ears-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@teiler/core": patch
---

Add `hydrate` method to style sheet
6 changes: 6 additions & 0 deletions packages/core/src/constructor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ describe('insert', () => {
const sheet = {
insert: jest.fn(),
dump: jest.fn<() => string>(),
extract: jest.fn<() => { css: string; ids: string[] }>(),
hydrate: jest.fn<(ids: string[]) => void>(),
}

const definition: StyleDefinition<'div', {}> = {
Expand All @@ -200,6 +202,8 @@ describe('insert', () => {
const sheet = {
insert: jest.fn(),
dump: jest.fn<() => string>(),
extract: jest.fn<() => { css: string; ids: string[] }>(),
hydrate: jest.fn<(ids: string[]) => void>(),
}

const definition: StyleDefinition<'div', {}> = {
Expand All @@ -221,6 +225,8 @@ describe('insert', () => {
const sheet = {
insert: jest.fn(),
dump: jest.fn<() => string>(),
extract: jest.fn<() => { css: string; ids: string[] }>(),
hydrate: jest.fn<(ids: string[]) => void>(),
}

const definition: StyleDefinition<'div', {}> = {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/sheet/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,22 @@ describe('createStyleSheet SSR', () => {
expect(sheet.dump()).toContain('my-rule { color: red }')
})
})

describe('extract', () => {
test('should extract the CSS and IDs from the stylesheet', () => {
const sheet = createStyleSheet({})
sheet.insert('my-rule', 'my-rule { color: red }')
const { css, ids } = sheet.extract()
expect(css).toContain('my-rule { color: red }')
expect(ids).toContain('my-rule')
})
})

describe('hydrate', () => {
test('should fill the cache with the provided IDs', () => {
const sheet = createStyleSheet({})
sheet.hydrate(['my-rule'])
sheet.insert('my-rule', 'my-rule { color: red }')
expect(sheet.dump()).toContain('')
})
})
19 changes: 18 additions & 1 deletion packages/core/src/sheet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type Options = {
export type Sheet = {
insert(key: string, styles: string): void
dump(): string
extract(): { css: string; ids: string[] }
hydrate(ids: string[]): void
}

export default function createStyleSheet(_options: Options): Sheet {
Expand All @@ -17,13 +19,28 @@ export default function createStyleSheet(_options: Options): Sheet {
..._options,
}

let cache: string[] = []

const isSSR = typeof document === 'undefined'
const styleTag = isSSR ? createServerTag() : createBrowserTag(options.container)

return {
insert: (key: string, styles: string) => styleTag.insertRule(key, styles),
insert: (key: string, styles: string) => {
if (cache.includes(key) === false) {
styleTag.insertRule(key, styles)
}
},
dump: () => {
return styleTag.getAllRules()
},
extract: () => {
return {
css: styleTag.getAllRules(),
ids: styleTag.getAllKeys(),
}
},
hydrate: (ids: string[]) => {
cache = ids || []
},
}
}
7 changes: 7 additions & 0 deletions packages/core/src/sheet/tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ type Tag = {
deleteRule(key: string): void
getRule(key: string): string
getAllRules(): string
getAllKeys(): string[]
[k: string]: unknown
}

Expand Down Expand Up @@ -34,6 +35,9 @@ export function createServerTag(): Tag {
getAllRules: function (): string {
return Object.values(rules).join(' ')
},
getAllKeys: function (): string[] {
return Object.keys(rules)
},
}
}

Expand All @@ -60,5 +64,8 @@ export function createBrowserTag(container?: HTMLElement): Tag {
getAllRules: function (): string {
return Array.from(inserted.values()).reduce((string, node) => string + ' ' + node.textContent, '')
},
getAllKeys: function (): string[] {
return Array.from(inserted.keys())
},
}
}
39 changes: 38 additions & 1 deletion packages/vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export default defineNuxtPlugin({
enforce: "pre",
async setup(nuxtApp) {
const styleSheet = createStyleSheet({})
nuxtApp.vueApp.provide('styleSheet', styleSheet)
nuxtApp.vueApp.provide('STYLE_SHEET', styleSheet)

if (process.server) {
useHead(() => {
Expand All @@ -156,6 +156,43 @@ export default defineNuxtPlugin({
});
```

## Hydration

This method allows you to pre-fill the cache with specific style IDs, optimizing performance by avoiding redundant insertions. Here's how you can use it with **NuxtJS**:

```ts
import { createStyleSheet } from "@teiler/core"

export default defineNuxtPlugin({
name: "teiler",
enforce: "pre",
async setup(nuxtApp) {
const styleSheet = createStyleSheet({})
nuxtApp.vueApp.provide('STYLE_SHEET', styleSheet)

if (process.server) {
useHead(() => {
const { css, ids } = styleSheet.extract()

return ({
style: [{ children: css, type: 'text/css', 'data-teiler': ids.join(' ')}],
})
})
} else {
const element = document.querySelector('style[data-teiler]')
if (element) {
const ids = element.getAttribute('data-teiler')?.split(' ') || []
styleSheet.hydrate(ids)
}
}
},
env: {
islands: true,
},
});

```

## Sew a Pattern

This tool simplifies the creation of consistent and reusable visual styles for components across various web frameworks. It provides a pattern-based approach, where patterns serve as blueprints for defining the visual style of components.
Expand Down

0 comments on commit 2416abd

Please sign in to comment.