Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { provide } from '@nano_kit/store'
import {
LocationNavigation$,
serverNavigation,
setDehydrationContext
setDehydrationInjector
} from '@nano_kit/svelte-kit'
import { routes } from '#src/stores/router'
import type { LayoutServerLoad } from './$types'

export const load: LayoutServerLoad = () => {
const contextRef = setDehydrationContext([
const injectorRef = setDehydrationInjector([
provide(LocationNavigation$, serverNavigation(routes))
])

return {
contextRef
injectorRef
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
getKitNavigation,
Link,
LocationNavigation$,
setHydrationContext
setHydrationInjector
} from '@nano_kit/svelte-kit'
import { routes } from '#src/stores/router'
import '../app.css'

let { data, children } = $props()

setHydrationContext({
fromRef: () => data.contextRef,
context: [
setHydrationInjector({
fromRef: () => data.injectorRef,
injector: [
provide(LocationNavigation$, getKitNavigation(routes))
]
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import CharacterPage from '#src/ui/pages/Character.svelte'
import { onMount } from 'svelte';

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import CharactersPage from '#src/ui/pages/Characters.svelte'

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import EpisodePage from '#src/ui/pages/Episode.svelte'

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import EpisodesPage from '#src/ui/pages/Episodes.svelte'

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import LocationPage from '#src/ui/pages/Location.svelte'

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import LocationsPage from '#src/ui/pages/Locations.svelte'

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import {
CookieStore,
LocationNavigation$,
serverNavigation,
setDehydrationContext
setDehydrationInjector
} from '@nano_kit/svelte-kit'
import { CookieStore$ } from '@nano_kit/platform-web'
import { routes } from '#src/stores/router'
import type { LayoutServerLoad } from './$types'

export const load: LayoutServerLoad = ({ cookies }) => {
const contextRef = setDehydrationContext([
const injectorRef = setDehydrationInjector([
provide(LocationNavigation$, serverNavigation(routes)),
provide(CookieStore$, new CookieStore(cookies))
])

return {
contextRef
injectorRef
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import {
LocationNavigation$,
getKitNavigation,
setHydrationContext
setHydrationInjector
} from '@nano_kit/svelte-kit'
import { routes } from '#src/stores/router'
import '../app.css'

let { data, children } = $props()

setHydrationContext({
fromRef: () => data.contextRef,
context: [
setHydrationInjector({
fromRef: () => data.injectorRef,
injector: [
provide(LocationNavigation$, getKitNavigation(routes))
]
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setHydrationContext } from '@nano_kit/svelte-kit'
import { setHydrationInjector } from '@nano_kit/svelte-kit'
import HomePage from '#src/ui/pages/Home.svelte'

let { data } = $props()

setHydrationContext({
setHydrationInjector({
dehydrated: () => data.dehydrated
})
</script>
Expand Down
6 changes: 3 additions & 3 deletions examples/weather/react-nano_kit-di/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createRoot } from 'react-dom/client'
import { InjectionContextProvider } from '@nano_kit/react'
import { InjectorProvider } from '@nano_kit/react'
import { App } from './App.jsx'
import './app.css'

const root = createRoot(document.getElementById('app')!)

root.render(
<InjectionContextProvider>
<InjectorProvider>
<App/>
</InjectionContextProvider>
</InjectorProvider>
)
4 changes: 2 additions & 2 deletions examples/weather/svelte-nano_kit-di/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { setInjectionContext } from '@nano_kit/svelte'
import { setInjector } from '@nano_kit/svelte'
import CityInput from './components/CityInput.svelte'
import Weather from './components/Weather.svelte'
import Forecast from './components/Forecast.svelte'

setInjectionContext()
setInjector()
</script>

<main class="app">
Expand Down
29 changes: 17 additions & 12 deletions packages/kida/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,12 +445,11 @@ There are also other methods to work with object maps:

The dependency injection system enables modular architecture and makes testing easier by allowing dependencies to be easily replaced with mocks. It also plays a critical role in SSR scenarios by isolating state between requests.

Use factory functions with `inject` to retrieve dependencies:
Use invocable tokens with `inject` to retrieve dependencies. An invocable token can be a function, or a class with `static injectable = true as const`. For class tokens, the simplest option is to extend `Injectable`.

```ts
import { inject, signal, mountable, onMountEffect, action } from 'kida'
import { inject, Injectable, signal, mountable, onMountEffect, action } from 'kida'

/* Factory function that defines a user store */
function User$() {
const $userId = signal(null)
const $user = mountable(signal(null))
Expand All @@ -473,9 +472,15 @@ function User$() {

return { $userId, $user }
}

class ApiClient$ extends Injectable {
getUser(id: number) {
return fetch(`/user/${id}`).then(response => response.json())
}
}
```

Call `inject(Factory$)` inside another factory to compose dependencies:
Call `inject(Token$)` inside another invocable token to compose dependencies:

```ts
import { inject, signal } from 'kida'
Expand All @@ -486,36 +491,36 @@ function App$() {
}
```

### `provide` / `InjectionContext` / `run`
### `provide` / `Injector` / `run`

Use `provide` to override dependencies with custom values. Pass the providers to `InjectionContext` and run your code within it using `run`:
Use `provide` to override dependencies with custom values. Pass the providers to `Injector` and run your code within it using `run`:

```ts
import { InjectionContext, provide, inject, run } from 'kida'
import { Injector, provide, inject, run } from 'kida'

function Theme$() {
return 'light'
}

const context = new InjectionContext([
const injector = new Injector([
provide(Theme$, 'dark')
])

run(context, () => {
run(injector, () => {
const theme = inject(Theme$) // 'dark'
})
```

This pattern is especially useful in tests to mock dependencies:

```ts
import { InjectionContext, provide, inject, run } from 'kida'
import { Injector, provide, inject, run } from 'kida'

const context = new InjectionContext([
const injector = new Injector([
provide(ApiClient$, mockApiClient)
])

run(context, () => {
run(injector, () => {
const { $user } = inject(User$)
// $user will use mockApiClient
})
Expand Down
1 change: 1 addition & 0 deletions packages/kida/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default [
'@typescript-eslint/unified-signatures': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-extraneous-class': 'off',
'no-implicit-coercion': 'off',
'consistent-return': 'off',
'symbol-description': 'off',
Expand Down
Loading