diff --git a/docs/components/Example.tsx b/docs/components/Example.tsx index 78876293..d022a6af 100644 --- a/docs/components/Example.tsx +++ b/docs/components/Example.tsx @@ -22,7 +22,7 @@ function Timestamp({ children }: { children: TimestampType }) { fontSize: '1.13em', fontWeight: 'bold', fontFamily: 'monospace', - marginRight: 2 + marginRight: 2, }} > {children} diff --git a/docs/headings.ts b/docs/headings.ts index cdaa3584..769f7cd1 100644 --- a/docs/headings.ts +++ b/docs/headings.ts @@ -200,6 +200,11 @@ export const headings: HeadingDefinition[] = [ title: '`root`', url: '/root', }, + { + level: 2, + title: '`shield`', + url: '/shield-config', + }, { level: 4, title: 'Plugins', diff --git a/docs/pages/shield-config/+Page.mdx b/docs/pages/shield-config/+Page.mdx new file mode 100644 index 00000000..8331b137 --- /dev/null +++ b/docs/pages/shield-config/+Page.mdx @@ -0,0 +1,19 @@ +import { Link, Warning } from '@brillout/docpress' +import { ConfigWhereServer } from '../../components' + +**Environment**: server. +**Default**: `false`. + +Whether to generate `shield()` in development. + +```js +// Environment: server + +import { config } from 'telefunc' + +config.shield.dev = true +``` + +This can slow down development speed. Depending on your app and how fast your computer is, the decreased development speed can range from unnoticeable to significant. + + diff --git a/docs/pages/shield/+Page.mdx b/docs/pages/shield/+Page.mdx index aa4d0aaf..e93f590d 100644 --- a/docs/pages/shield/+Page.mdx +++ b/docs/pages/shield/+Page.mdx @@ -43,6 +43,10 @@ export async function hello({ name }: { name: string }) { With Telefunc, not only can we seamlessly re-use types across our frontend and backend code, but we also get automatic type-safety at runtime. If we use a TypeScript ORM (e.g. [Prisma](https://www.prisma.io/)) or SQL builder (e.g. [Kysely](https://github.com/koskimas/kysely) and [others](https://github.com/stars/brillout/lists/sql)), then we get end-to-end type safety all the way from database to frontend. +> For a faster development, Telefunc doesn't generate `shield()` and your telefunction arguments aren't validated during development. +> Telefunc only generates `shield()` upon building your app for production. +> You can enable the generation of `shield()` for development by setting `config.shield.dev` to `true`. + > Telefunc's automatic `shield()` generation only works for stacks that transpile server-side code (Next.js, Vite, Vike, SvelteKit, Nuxt, etc.). > > For stacks that don't transpile server-side code (e.g. React Native, CRA, Parcel), we need to define `shield()` manually ourselves: see . diff --git a/telefunc/node/server/serverConfig.ts b/telefunc/node/server/serverConfig.ts index f3b0cd2d..980528ae 100644 --- a/telefunc/node/server/serverConfig.ts +++ b/telefunc/node/server/serverConfig.ts @@ -21,8 +21,12 @@ type ConfigUser = { telefuncFiles?: string[] /** Your project root directory, e.g. `/home/alice/code/my-app/` */ root?: string - /** Wether to disable ETag cache headers */ + /** Whether to disable ETag cache headers */ disableEtag?: boolean + shield?: { + /** Whether to generate shield during development */ + dev?: boolean + } } type ConfigResolved = { telefuncUrl: string @@ -30,6 +34,7 @@ type ConfigResolved = { disableEtag: boolean telefuncFiles: string[] | null disableNamingConvention: boolean + shield: { dev: boolean } } const configUser: ConfigUser = new Proxy({}, { set: validateUserConfig }) @@ -38,6 +43,7 @@ function getServerConfig(): ConfigResolved { return { disableEtag: configUser.disableEtag ?? false, disableNamingConvention: configUser.disableNamingConvention ?? false, + shield: { dev: configUser.shield?.dev ?? false }, telefuncUrl: configUser.telefuncUrl || '/_telefunc', telefuncFiles: (() => { if (configUser.telefuncFiles) { @@ -68,7 +74,7 @@ function validateUserConfig(configUserUnwrapped: ConfigUser, prop: string, val: ) configUserUnwrapped[prop] = val } else if (prop === 'telefuncFiles') { - const wrongType = '`config.telefuncFiles` should be a list of paths' + const wrongType = 'config.telefuncFiles should be a list of paths' assertUsage(Array.isArray(val), wrongType) val.forEach((val: unknown) => { assertUsage(typeof val === 'string', wrongType) @@ -80,7 +86,13 @@ function validateUserConfig(configUserUnwrapped: ConfigUser, prop: string, val: assertUsage(typeof val === 'boolean', 'config.disableEtag should be a boolean') configUserUnwrapped[prop] = val } else if (prop === 'disableNamingConvention') { - assertUsage(typeof val === 'boolean', '`config.disableNamingConvention` should be a boolean') + assertUsage(typeof val === 'boolean', 'config.disableNamingConvention should be a boolean') + configUserUnwrapped[prop] = val + } else if (prop === 'shield') { + assertUsage(typeof val === 'object' && val !== null, 'config.shield should be a object') + if ('dev' in val) { + assertUsage(typeof (val as { dev: unknown }).dev === 'boolean', 'config.shield.dev should be a boolean') + } configUserUnwrapped[prop] = val } else { assertUsage(false, `Unknown config.${prop}`) diff --git a/telefunc/node/server/shield/codegen/generateShield.ts b/telefunc/node/server/shield/codegen/generateShield.ts index c235aafd..0f4c066a 100644 --- a/telefunc/node/server/shield/codegen/generateShield.ts +++ b/telefunc/node/server/shield/codegen/generateShield.ts @@ -84,7 +84,7 @@ function getProject(telefuncFilePath: string, telefuncFileCode: string, appRootD path.dirname(telefuncFilePath), `__telefunc_shieldGen_${path.basename(telefuncFilePath)}`, ) - const shieldGenSource = project.createSourceFile(shieldGenFilePath) + const shieldGenSource = project.createSourceFile(shieldGenFilePath, undefined, { overwrite: true }) shieldGenSource.addImportDeclaration({ moduleSpecifier: getImportPath(shieldGenFilePath, typeToShieldFilePath), namedImports: ['ShieldArrStr'], diff --git a/telefunc/node/transformer/transformTelefuncFileServerSide.ts b/telefunc/node/transformer/transformTelefuncFileServerSide.ts index 3ddc9e19..a44185ca 100644 --- a/telefunc/node/transformer/transformTelefuncFileServerSide.ts +++ b/telefunc/node/transformer/transformTelefuncFileServerSide.ts @@ -3,6 +3,7 @@ export { transformTelefuncFileServerSide } import { getExportNames } from './getExportNames' import { assertPosixPath } from './utils' import { generateShield } from '../server/shield/codegen/generateShield' +import { getServerConfig } from '../server/serverConfig' async function transformTelefuncFileServerSide( src: string, @@ -17,7 +18,8 @@ async function transformTelefuncFileServerSide( const exportNames = await getExportNames(src) let code = decorateTelefunctions(exportNames, src, id.replace(appRootDir, ''), appRootDir, skipRegistration) - if (id.endsWith('.ts') && !isDev) { + const config = getServerConfig() + if (id.endsWith('.ts') && (!isDev || config.shield.dev)) { code = generateShield(code, id, appRootDir) }