Skip to content

Commit

Permalink
feat: new React hook useData() enabling using Telefunc for SSR data…
Browse files Browse the repository at this point in the history
… fetching
  • Loading branch information
brillout committed Sep 13, 2022
1 parent 03fa87a commit 7d8a757
Show file tree
Hide file tree
Showing 20 changed files with 83 additions and 42 deletions.
2 changes: 1 addition & 1 deletion examples/vite-plugin-ssr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"express": "^4.17.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-streaming": "^0.3.1",
"react-streaming": "^0.3.2",
"telefunc": "0.1.25",
"typescript": "^4.7.4",
"vite": "^3.0.9",
Expand Down
11 changes: 4 additions & 7 deletions examples/vite-plugin-ssr/pages/index/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
export { TodoList }

import React, { useState } from 'react'
import { onNewTodo, loadTodoItems } from './TodoList.telefunc.js'
import { useAsync } from 'react-streaming'

export { TodoList }
import { useData } from 'telefunc/react'

function TodoList() {
const todoItemsInitial = useAsync('loadTodoItems', async () => {
const todoItems = await loadTodoItems()
return todoItems
})
const todoItemsInitial = useData(loadTodoItems)
const [todoItems, setTodoItems] = useState(todoItemsInitial)
const [draft, setDraft] = useState('')
return (
Expand Down
3 changes: 1 addition & 2 deletions examples/vite-plugin-ssr/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ import react from '@vitejs/plugin-react'
import ssr from 'vite-plugin-ssr/plugin'

export default {
plugins: [react(), ssr(), telefunc()],
ssr: { external: ['react-streaming'] }
plugins: [react(), ssr(), telefunc()]
}
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions telefunc/client/react/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../../shared/react'
1 change: 1 addition & 0 deletions telefunc/node/react/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../../shared/react'
11 changes: 0 additions & 11 deletions telefunc/node/server/runTelefunc/getTelefunctionKey.ts

This file was deleted.

7 changes: 4 additions & 3 deletions telefunc/node/server/runTelefunc/getTelefunctions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export { getTelefunctions }

import { assertUsage, isCallable } from '../../utils'
import { assertUsage, isCallable, getTelefunctionKey } from '../../utils'
import type { Telefunction, TelefuncFiles } from '../types'
import { getTelefunctionKey } from './getTelefunctionKey'
import { getTelefunctionName } from './getTelefunctionName'

async function getTelefunctions(runContext: { telefuncFilesLoaded: TelefuncFiles }): Promise<{
Expand All @@ -11,12 +10,14 @@ async function getTelefunctions(runContext: { telefuncFilesLoaded: TelefuncFiles
const telefunctions: Record<string, Telefunction> = {}
Object.entries(runContext.telefuncFilesLoaded).forEach(([telefunctionFilePath, telefuncFileExports]) => {
Object.entries(telefuncFileExports).forEach(([telefunctionFileExport, exportValue]) => {
const telefunctionKey = getTelefunctionKey({ telefunctionFilePath, telefunctionFileExport })
const telefunctionKey = getTelefunctionKey(telefunctionFilePath, telefunctionFileExport)
assertTelefunction(exportValue, {
telefunctionFileExport,
telefunctionFilePath
})
telefunctions[telefunctionKey] = exportValue
// @ts-ignore
// telefunctions[telefunctionKey]._key = telefunctionKey
})
})

Expand Down
5 changes: 2 additions & 3 deletions telefunc/node/server/runTelefunc/parseHttpRequest.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export { parseHttpRequest }

import { parse } from '@brillout/json-s/parse'
import { getTelefunctionKey } from './getTelefunctionKey'
import { assertUsage, hasProp, getProjectError, getUrlPathname, assert } from '../../utils'
import { assertUsage, hasProp, getProjectError, getUrlPathname, assert, getTelefunctionKey } from '../../utils'
import { getTelefunctionName } from './getTelefunctionName'

function parseHttpRequest(runContext: {
Expand Down Expand Up @@ -75,7 +74,7 @@ function parseHttpRequest(runContext: {
const telefunctionFilePath = bodyParsed.file
const telefunctionFileExport = bodyParsed.name
const telefunctionArgs = bodyParsed.args
const telefunctionKey = getTelefunctionKey({ telefunctionFilePath, telefunctionFileExport })
const telefunctionKey = getTelefunctionKey(telefunctionFilePath, telefunctionFileExport)
const telefunctionName = getTelefunctionName({ telefunctionFilePath, telefunctionFileExport })

return {
Expand Down
21 changes: 15 additions & 6 deletions telefunc/node/transformer/transformTelefuncFileSSR.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { transformTelefuncFileSSR }

import { getExportNames } from './getExportNames'
import { assertPosixPath } from '../utils'
import { assertPosixPath, getTelefunctionKey } from './utils'

async function transformTelefuncFileSSR(src: string, id: string, root: string) {
assertPosixPath(id)
Expand All @@ -18,16 +18,25 @@ async function transformTelefuncFileSSR(src: string, id: string, root: string) {
function getCode(exportNames: readonly string[], src: string, filePath: string) {
assertPosixPath(filePath)

const telefuncImport = 'import { __internal_addTelefunction } from "telefunc";'
let code = src;

// No break line between `telefuncImport` and `src` in order to preserve the source map's line mapping
let code = telefuncImport + src
{
const telefuncImport = 'import { __internal_addTelefunction } from "telefunc";'
// No break line between `telefuncImport` and `src` in order to preserve the source map's line mapping
code = telefuncImport + src
}

const extraLines: string[] = []

code += '\n\n'
for (const exportName of exportNames) {
code += `__internal_addTelefunction(${exportName}, "${exportName}", "${filePath}");`
code += '\n'
extraLines.push(`__internal_addTelefunction(${exportName}, "${exportName}", "${filePath}");`)
const telefunctionKey = getTelefunctionKey(filePath, exportName)
extraLines.push(`${exportName}['_key'] = ${JSON.stringify(telefunctionKey)};`)
}

code += '\n' + extraLines.join('\n')

return code
}

17 changes: 13 additions & 4 deletions telefunc/node/transformer/transformTelefuncFileSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,27 @@ function transformTelefuncFileSync(id: string, root: string, exportNames: readon
}

export function getCode(exportNames: readonly string[], telefuncFilePath: string) {
const lines = []
const lines: string[] = []

lines.push('// @ts-nocheck')

lines.push(`import { __internal_fetchTelefunc } from 'telefunc/client';`)

exportNames.forEach((exportName) => {
const exportValue = `(...args) => __internal_fetchTelefunc('${telefuncFilePath}', '${exportName}', args);`
const varName = exportName === 'default' ? 'defaultExport' : exportName

lines.push(`const ${varName} = (...args) => __internal_fetchTelefunc('${telefuncFilePath}', '${exportName}', args);`)

{
assert(!telefuncFilePath.includes(':'))
const key = `${telefuncFilePath}:${exportName}`
lines.push(`${varName}._key = ${JSON.stringify(key)};`)
}

if (exportName === 'default') {
lines.push(`export default ${exportValue}`)
lines.push(`export default ${varName};`)
} else {
lines.push(`export const ${exportName} = ${exportValue};`)
lines.push(`export { ${varName} };`)
}
})

Expand Down
2 changes: 2 additions & 0 deletions telefunc/node/transformer/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// TODO
export * from '../../node/utils'
3 changes: 2 additions & 1 deletion telefunc/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export * from '../utils/isPromise'
export * from '../utils/moduleExists'
export * from '../utils/cast'
export * from '../utils/filesystemPathHandling'
export * from '../utils./../utils/unique'
export * from '../utils/unique'
export * from '../utils/nodeRequire'
export * from '../utils/getUrlPathname'
export * from '../utils/getGlobalObject'
Expand All @@ -16,3 +16,4 @@ export * from '../utils/projectInfo'
export * from '../utils/objectAssign'
export * from '../utils/lowercaseFirstLetter'
export * from '../utils/dynamicImport'
export * from '../utils/getTelefunctionKey'
2 changes: 2 additions & 0 deletions telefunc/node/vite/transform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Plugin } from 'vite'
import { transformTelefuncFile } from '../transformer/transformTelefuncFile'
import { transformTelefuncFileSSR } from '../transformer/transformTelefuncFileSSR'
import { generateShield } from '../server/shield/codegen/transformer'
import { assert, toPosixPath, viteIsSSR_options } from './utils'

Expand All @@ -21,6 +22,7 @@ function transform(): Plugin {
if (!viteIsSSR_options(options)) {
return transformTelefuncFile(code, id, root)
} else {
code = (await transformTelefuncFileSSR(code, id, root)).code
if (id.endsWith('.ts')) {
return generateShield(code)
}
Expand Down
2 changes: 2 additions & 0 deletions telefunc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
"typescript": "^4.7.4",
"vite": "^3.0.9"
},
"peerDependencies": { "react-streaming": "^0.3.2" },
"peerDependenciesMeta": { "react-streaming": { "optional": true } },
"files": [
"dist/cjs/",
"dist/esm/",
Expand Down
3 changes: 3 additions & 0 deletions telefunc/react.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Help TS's resolver until it supports `package.json#exports`
export * from './dist/esm/client/react'
export { default } from './dist/esm/client/react'
1 change: 1 addition & 0 deletions telefunc/shared/react/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useData } from './useData'
17 changes: 17 additions & 0 deletions telefunc/shared/react/useData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export { useData }

import { useAsync } from 'react-streaming'
import { assert } from './utils'

function useData<Telefunction extends (...args: any[]) => any>(
telefunction: Telefunction,
...args: Parameters<Telefunction>
): Awaited<ReturnType<Telefunction>> {
// @ts-ignore
const telefunctionKey = telefunction._key as string
assert(telefunctionKey)
const asyncFn: () => ReturnType<Telefunction> = () => telefunction(...args)
const key = [telefunctionKey, ...args]
const result = useAsync(key, asyncFn)
return result
}
1 change: 1 addition & 0 deletions telefunc/shared/react/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../../utils/assert'
7 changes: 7 additions & 0 deletions telefunc/utils/getTelefunctionKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { assert } from './assert'

export function getTelefunctionKey(filePath: string, exportName: string) {
assert(!filePath.includes(':')) // This assert isn't actually necessary since `telefunctionKey` is never parsed
const telefunctionKey = filePath + ':' + exportName
return telefunctionKey
}

0 comments on commit 7d8a757

Please sign in to comment.