Skip to content

Commit

Permalink
use rpc for file adding
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-8 committed Jul 26, 2024
1 parent ba9fd43 commit 1cd8631
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 83 deletions.
4 changes: 4 additions & 0 deletions packages/kitbook/src/lib/kitbook-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ export type DeepPartial<T> = {

export interface RPCFunctions {
svelte_modules: () => Promise<SvelteModules>
open_or_create_variant: ({ filepath, props }: { filepath: string, props: Record<string, any> }) => void
open_or_create_file: ({ filepath, template }: { filepath: string, template: string }) => void
// notifications
module_updated: (filepath: string) => void
open_in_editor: (url: string) => void
}

export type SvelteModules = Record<string, SvelteModule>
Expand Down
13 changes: 9 additions & 4 deletions packages/kitbook/src/lib/modules/rpc-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,38 @@ import { browser } from '$app/environment'
export const rpc_client = create_rpc_client_stores()

function create_rpc_client_stores() {
let functions: BirpcReturn<RPCFunctions, Pick<RPCFunctions, 'module_updated'>>
let _functions: BirpcReturn<RPCFunctions, Pick<RPCFunctions, 'module_updated' | 'open_in_editor'>>
const svelte_modules = writable<SvelteModules>({})
const latest_edited_filepath = writable<string | null>(null)

if (browser) {
createHotContext().then((hot) => {
functions = createRPCClient<RPCFunctions, Pick<RPCFunctions, 'module_updated'>>(
_functions = createRPCClient<RPCFunctions, Pick<RPCFunctions, 'module_updated' | 'open_in_editor'>>(
RPC_NAME,
hot,
{
module_updated(filepath) {
latest_edited_filepath.set(filepath)
update_svelte_modules()
},
open_in_editor(url) {
fetch(url)
},
},
)
update_svelte_modules()

async function update_svelte_modules() {
const routes = await functions.svelte_modules()
const routes = await _functions.svelte_modules()
svelte_modules.set(routes)
}
})
}

return {
functions,
get functions() {
return _functions
},
svelte_modules,
latest_edited_filepath,
}
Expand Down
38 changes: 11 additions & 27 deletions packages/kitbook/src/lib/open/openFiles.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { rpc_client } from '../modules/rpc-client'
import { getFilenameAndExtension } from './get-filename-and-extension'
import { serializeIntersection } from './serialize'

Expand All @@ -7,9 +8,6 @@ export function openComponent(filepath: string, viteBase: string) {
}

export function openVariants(filepath: string, componentDetail?: SvelteComponentDetail) {
if (!import.meta.hot)
return alert('Dev server must be running with HMR enabled to use this feature.')

if (!componentDetail?.options)
return sendOpenVariantsRequest(filepath, {})

Expand All @@ -20,18 +18,15 @@ export function openVariants(filepath: string, componentDetail?: SvelteComponent
}

export function sendOpenVariantsRequest(filepath: string, serializedState: Record<string, any>) {
if (!import.meta.hot)
return alert('Dev server must be running with HMR enabled to use this feature.')

import.meta.hot.send('kitbook:to-server:open-variants', { filepath, props: serializedState || {} })
rpc_client.functions.open_or_create_variant({ filepath, props: serializedState || {} })
}

export function openMarkdown(filepath: string) {
const markdownTemplate = 'You can write some documentation for your component here using markdown.'
ensureFileExists(filepath, markdownTemplate)
}

export function openComposition({ filepath, compositionName }: { filepath: string; compositionName?: string }) {
export function openComposition({ filepath, compositionName }: { filepath: string, compositionName?: string }) {
const { filepathWithoutExtension, filenameWithoutExtensions, extension } = getFilenameAndExtension(filepath)

const svelteCompositionTemplate = `<script context="module" lang="ts">
Expand Down Expand Up @@ -73,15 +68,11 @@ Place your Svelte composition here.
}

function ensureFileExists(filepath: string, template: string) {
// TODO: could jump to GitHub instead of error if no dev server - use githubURL + filepath
if (!import.meta.hot)
return alert('Dev server must be running with HMR enabled to use this feature.')

const pageProofPath = filepath
.replace('+page', '_page')
.replace('+layout', '_layout')

import.meta.hot.send('kitbook:to-server:ensure-file-exists', { filepath: pageProofPath, template })
rpc_client.functions.open_or_create_file({ filepath: pageProofPath, template })
}

export function createNewPage(filepath: string) {
Expand All @@ -90,14 +81,14 @@ export function createNewPage(filepath: string) {
</script>
Hi {data.name}`
import.meta.hot.send('kitbook:to-server:ensure-file-exists', { filepath, template })
rpc_client.functions.open_or_create_file({ filepath, template })

const pageTemplate = `export const load = (() => {
return { name: 'Bill' }
})`
import.meta.hot.send('kitbook:to-server:ensure-file-exists', { filepath: filepath.replace('+page.svelte', '+page.ts'), template: pageTemplate })
rpc_client.functions.open_or_create_file({ filepath: filepath.replace('+page.svelte', '+page.ts'), template: pageTemplate })

import.meta.hot.send('kitbook:to-server:open-variants', { filepath, props: { data: { name: 'John' } } })
rpc_client.functions.open_or_create_variant({ filepath, props: { data: { name: 'John' } } })
}

export function createNewServerEndpoint(filepath: string) {
Expand Down Expand Up @@ -131,7 +122,7 @@ export const POST: RequestHandler = async ({ locals: { getSession }, request })
}
}
`
import.meta.hot.send('kitbook:to-server:ensure-file-exists', { filepath, template })
rpc_client.functions.open_or_create_file({ filepath, template })
const testTemplate = `import { POST, type OperationRequestBody, type OperationResponseBody } from './+server'
import { request } from '$lib/mocks/sveltekit-endpoint-helper'
import { ResponseCodes } from '$lib/response-codes'
Expand Down Expand Up @@ -166,7 +157,7 @@ describe(POST, () => {
})
})
`
import.meta.hot.send('kitbook:to-server:ensure-file-exists', { filepath: filepath.replace('+server.ts', '_server.test.ts'), template: testTemplate })
rpc_client.functions.open_or_create_file({ filepath: filepath.replace('+server.ts', '_server.test.ts'), template: testTemplate })
}

export function createNewComponent(filepath: string) {
Expand All @@ -175,13 +166,6 @@ export function createNewComponent(filepath: string) {
</script>
Hi {name}`
import.meta.hot.send('kitbook:to-server:ensure-file-exists', { filepath, template })
import.meta.hot.send('kitbook:to-server:open-variants', { filepath, props: { name: 'John' } })
}

if (import.meta.hot) {
import.meta.hot.on('kitbook:to-client:open-file', ({ filepath, viteBase }) => {
const file_loc = `${filepath}:1:1`
fetch(`${viteBase}/__open-in-editor?file=${encodeURIComponent(file_loc)}`)
})
rpc_client.functions.open_or_create_file({ filepath, template })
rpc_client.functions.open_or_create_variant({ filepath, props: { data: { name: 'John' } } })
}
54 changes: 54 additions & 0 deletions packages/kitbook/src/lib/plugins/files/files.plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { access, constants, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import type { Plugin } from 'vite'
import type { KitbookPluginContext } from '../vite.js'
import { removeQuotesFromSerializedFunctions } from '../../open/serialize.js'

export function FilesPlugin({ rpc_functions, settings }: KitbookPluginContext): Plugin {
function writeFileIfNeededThenOpen(filepath: string, template: string) {
access(filepath, constants.F_OK, (err) => {
if (err) {
const directory = dirname(filepath)
mkdirSync(directory, { recursive: true })
writeFileSync(filepath, template)
console.info(`added ${filepath}`)
}

const file_location = `${filepath}:1:1`
const open_in_editor_url = `${settings.viewer.__internal.viteBase}/__open-in-editor?file=${encodeURIComponent(file_location)}`
rpc_functions.open_in_editor(open_in_editor_url)
})
}

rpc_functions.open_or_create_variant = ({ filepath, props }) => {
const props_without_newlines_tabs = JSON.stringify(props || {}, null, 2)
.replace(/\\n/g, '').replace(/\\t/g, '')
const code = getVariantsTemplate().replace('shared = {}', `shared = ${props_without_newlines_tabs}`)
const code_with_component_reference = code.replace('Template.svelte', filepath.split('/').pop())
const template = removeQuotesFromSerializedFunctions(code_with_component_reference)

const variantsPath = filepath
.replace('.svelte', '.variants.ts')
.replace('+page', '_page')
.replace('+layout', '_layout')

writeFileIfNeededThenOpen(variantsPath, template)
}

rpc_functions.open_or_create_file = ({ filepath, template }) => {
writeFileIfNeededThenOpen(filepath, template)
}

return {
name: 'vite-plugin-kitbook:files',
enforce: 'pre',
apply: 'serve',
}
}

function getVariantsTemplate() {
const _dirname = dirname(fileURLToPath(import.meta.url))
const filepath = resolve(_dirname, '../virtual/Template.variants.ts.txt')
return readFileSync(filepath, 'utf-8')
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ import type { RPCFunctions } from '../../kitbook-types'
import type { KitbookPluginContext } from '../vite.js'
import { get_svelte_modules } from './get-svelte-modules.js'

export function RPCPlugin(context: KitbookPluginContext): Plugin {
export function RPCPlugin({ config, rpc_functions }: KitbookPluginContext): Plugin {
return {
name: 'vite-plugin-kitbook:rpc',
enforce: 'pre',
apply: 'serve', // TODO: remove later once also getting modules from build

configResolved(_config) {
context.config = _config
config = _config
},

configureServer(server) {
context.rpc_functions.svelte_modules = () => get_svelte_modules(server, context.config.root)
const rpc_server = createRPCServer<RPCFunctions>(RPC_NAME, server.ws, rpc_functions)

const rpc_server = createRPCServer<RPCFunctions>(RPC_NAME, server.ws, context.rpc_functions)
rpc_functions.svelte_modules = () => get_svelte_modules(server, config.root)
rpc_functions.open_in_editor = (url) => {
rpc_server.open_in_editor.asEvent(url)
}

const debounce_module_updated = debounce((filepath: string) => {
rpc_server.module_updated.asEvent(filepath)
Expand Down
44 changes: 2 additions & 42 deletions packages/kitbook/src/lib/plugins/viewer/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { access, constants, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { readFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import type { HMRBroadcasterClient, Plugin } from 'vite'
import { removeQuotesFromSerializedFunctions } from '../../open/serialize.js'
import type { Plugin } from 'vite'
import type { KitbookPluginContext } from '../vite.js'

const LOAD_VIEWER_ID = 'virtual:kitbook-load-viewer.js'
Expand Down Expand Up @@ -39,26 +38,6 @@ export function ViewerPlugin({ settings }: KitbookPluginContext): Plugin {
server.ws.on('kitbook:to-server:tools:change-state', (data) => {
server.ws.send('kitbook:to-client:tools:change-state', data)
})

server.ws.on('kitbook:to-server:ensure-file-exists', ({ filepath, template }, client) => {
writeFileIfNeededThenOpen(filepath, template, settings.viewer.__internal.viteBase, client)
})

server.ws.on('kitbook:to-server:open-variants', ({ filepath, props }, client) => {
// TODO: parse Svelte file to get props if props is null (make it an empty object if from Viewer and component simply has no props)
const props_without_newlines_tabs = JSON.stringify(props || {}, null, 2)
.replace(/\\n/g, '').replace(/\\t/g, '')
const code = getVariantsTemplate().replace('shared = {}', `shared = ${props_without_newlines_tabs}`)
const code_with_component_reference = code.replace('Template.svelte', filepath.split('/').pop())
const template = removeQuotesFromSerializedFunctions(code_with_component_reference)

const variantsPath = filepath
.replace('.svelte', '.variants.ts')
.replace('+page', '_page')
.replace('+layout', '_layout')

writeFileIfNeededThenOpen(variantsPath, template, settings.viewer.__internal.viteBase, client)
})
},
}
}
Expand All @@ -69,22 +48,3 @@ function componentListenerCode(): string {
const filepath = resolve(_dirname, './listenForComponentsElements.js')
return readFileSync(filepath, 'utf-8')
}

function writeFileIfNeededThenOpen(filepath: string, template: string, viteBase: string, client: HMRBroadcasterClient) {
access(filepath, constants.F_OK, (err) => {
if (err) {
const directory = dirname(filepath)
mkdirSync(directory, { recursive: true })
writeFileSync(filepath, template)
console.info(`added ${filepath}`)
}

client.send('kitbook:to-client:open-file', { filepath, viteBase })
})
}

function getVariantsTemplate() {
const _dirname = dirname(fileURLToPath(import.meta.url))
const filepath = resolve(_dirname, '../virtual/Template.variants.ts.txt')
return readFileSync(filepath, 'utf-8')
}
7 changes: 6 additions & 1 deletion packages/kitbook/src/lib/plugins/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { merge_user_settings_with_defaults } from './context/merge-user-settings
import { copy_kitbook_routes } from './context/copy-kitbook-routes.js'
import { MainPlugin } from './main/plugin.js'
import { ViewerPlugin } from './viewer/plugin.js'
import { RPCPlugin } from './rpc/plugin'
import { RPCPlugin } from './rpc/rpc.plugin.js'
import { FilesPlugin } from './files/files.plugin.js'

/**
* Vite plugin to add a Kitbook to SvelteKit projects. Will automatically add Kitbook routes to `src/routes/kitbook` unless you update the `routesDirectory` and `kitbookRoute` settings.
Expand All @@ -16,6 +17,7 @@ export function kitbook(user_settings: Partial<KitbookSettings> = {}): Plugin[]
MainPlugin(context.settings),
ViewerPlugin(context),
RPCPlugin(context),
FilesPlugin(context),
]
}

Expand All @@ -29,7 +31,10 @@ function create_context(user_settings: Partial<KitbookSettings>): KitbookPluginC
rpc_functions: {
// @ts-expect-error function set in RPCPlugin
svelte_modules: () => {},
open_or_create_variant: ({ filepath, props }) => {},
open_or_create_file: ({filepath, template}) => {},
module_updated: (filepath) => {},
open_in_editor: (url) => {},
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import View from '../../view/View.svelte'
import { openComposition } from '../../open/openFiles'
import type { CompositionModule, KitbookSettings, Language } from '../../kitbook-types'
import { dev } from '$app/environment'
export let compositionsModules: Record<string, CompositionModule>
export let pathWithoutExtension: string
Expand Down Expand Up @@ -47,7 +48,11 @@
<button
class="capitalize relative z-2"
type="button"
on:click={() => openComposition({ filepath: `${pathWithoutExtension}.svelte`, compositionName })}
on:click={() => {
if (!dev)
return
openComposition({ filepath: `${pathWithoutExtension}.svelte`, compositionName })
}}
title="Edit Composition">
<span class="i-carbon-chart-treemap align--2px" />
{compositionName === 'default' ? '' : compositionName} composition
Expand Down
3 changes: 3 additions & 0 deletions packages/kitbook/src/lib/routes/[...file]/Variants.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type { KitbookSettings, Language, VariantsModule, Viewport } from '../../kitbook-types'
import View from '../../view/View.svelte'
import { openVariants } from '../../open/openFiles'
import { dev } from '$app/environment'
export let variantsModule: VariantsModule
export let pathWithoutExtension: string
Expand Down Expand Up @@ -47,6 +48,8 @@
class="capitalize relative z-2"
type="button"
on:click={() => {
if (!dev)
return
openVariants(`${pathWithoutExtension}.svelte`)
}}
title="Edit Variant">
Expand Down
4 changes: 0 additions & 4 deletions packages/kitbook/src/lib/server-events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ export interface ToolsComponentDetails {

declare module 'vite/types/customEvent' {
interface CustomEventMap {
'kitbook:to-server:open-variants': { filepath: string, props: Record<string, any> }
'kitbook:to-server:ensure-file-exists': FilenameWithTemplate
'kitbook:to-client:open-file': { filepath: string, viteBase: string }

'kitbook:to-server:tools:request-component-details': Record<string, any>
'kitbook:to-client:tools:request-component-details': Record<string, any>

Expand Down

0 comments on commit 1cd8631

Please sign in to comment.