@tanstack/start-plugin-core 1.132.0-alpha.0 → 1.132.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/esm/create-server-fn-plugin/compiler.d.ts +61 -0
  2. package/dist/esm/create-server-fn-plugin/compiler.js +336 -0
  3. package/dist/esm/create-server-fn-plugin/compiler.js.map +1 -0
  4. package/dist/esm/create-server-fn-plugin/handleCreateServerFn.d.ts +6 -0
  5. package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js +85 -0
  6. package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js.map +1 -0
  7. package/dist/esm/create-server-fn-plugin/plugin.d.ts +3 -0
  8. package/dist/esm/create-server-fn-plugin/plugin.js +113 -0
  9. package/dist/esm/create-server-fn-plugin/plugin.js.map +1 -0
  10. package/dist/esm/index.d.ts +1 -0
  11. package/dist/esm/index.js +2 -0
  12. package/dist/esm/index.js.map +1 -1
  13. package/dist/esm/output-directory.js +5 -2
  14. package/dist/esm/output-directory.js.map +1 -1
  15. package/dist/esm/plugin.d.ts +1 -1
  16. package/dist/esm/plugin.js +23 -14
  17. package/dist/esm/plugin.js.map +1 -1
  18. package/dist/esm/schema.d.ts +20 -28
  19. package/dist/esm/schema.js +10 -14
  20. package/dist/esm/schema.js.map +1 -1
  21. package/dist/esm/start-compiler-plugin/compilers.d.ts +15 -0
  22. package/dist/esm/start-compiler-plugin/compilers.js +131 -0
  23. package/dist/esm/start-compiler-plugin/compilers.js.map +1 -0
  24. package/dist/esm/start-compiler-plugin/constants.d.ts +1 -0
  25. package/dist/esm/start-compiler-plugin/constants.js +13 -0
  26. package/dist/esm/start-compiler-plugin/constants.js.map +1 -0
  27. package/dist/esm/start-compiler-plugin/envOnly.d.ts +5 -0
  28. package/dist/esm/start-compiler-plugin/envOnly.js +41 -0
  29. package/dist/esm/start-compiler-plugin/envOnly.js.map +1 -0
  30. package/dist/esm/start-compiler-plugin/isomorphicFn.d.ts +4 -0
  31. package/dist/esm/start-compiler-plugin/isomorphicFn.js +49 -0
  32. package/dist/esm/start-compiler-plugin/isomorphicFn.js.map +1 -0
  33. package/dist/esm/start-compiler-plugin/middleware.d.ts +4 -0
  34. package/dist/esm/start-compiler-plugin/middleware.js +51 -0
  35. package/dist/esm/start-compiler-plugin/middleware.js.map +1 -0
  36. package/dist/esm/{start-compiler-plugin.d.ts → start-compiler-plugin/plugin.d.ts} +1 -8
  37. package/dist/esm/start-compiler-plugin/plugin.js +96 -0
  38. package/dist/esm/start-compiler-plugin/plugin.js.map +1 -0
  39. package/dist/esm/start-compiler-plugin/serverFileRoute.d.ts +4 -0
  40. package/dist/esm/start-compiler-plugin/serverFileRoute.js +38 -0
  41. package/dist/esm/start-compiler-plugin/serverFileRoute.js.map +1 -0
  42. package/dist/esm/start-compiler-plugin/utils.d.ts +13 -0
  43. package/dist/esm/start-compiler-plugin/utils.js +30 -0
  44. package/dist/esm/start-compiler-plugin/utils.js.map +1 -0
  45. package/package.json +8 -8
  46. package/src/create-server-fn-plugin/compiler.ts +456 -0
  47. package/src/create-server-fn-plugin/handleCreateServerFn.ts +153 -0
  48. package/src/create-server-fn-plugin/plugin.ts +138 -0
  49. package/src/index.ts +2 -0
  50. package/src/output-directory.ts +13 -6
  51. package/src/plugin.ts +24 -21
  52. package/src/schema.ts +10 -16
  53. package/src/start-compiler-plugin/compilers.ts +195 -0
  54. package/src/start-compiler-plugin/constants.ts +9 -0
  55. package/src/start-compiler-plugin/envOnly.ts +58 -0
  56. package/src/start-compiler-plugin/isomorphicFn.ts +78 -0
  57. package/src/start-compiler-plugin/middleware.ts +79 -0
  58. package/src/start-compiler-plugin/plugin.ts +122 -0
  59. package/src/start-compiler-plugin/serverFileRoute.ts +59 -0
  60. package/src/start-compiler-plugin/utils.ts +41 -0
  61. package/dist/esm/compilers.d.ts +0 -21
  62. package/dist/esm/compilers.js +0 -395
  63. package/dist/esm/compilers.js.map +0 -1
  64. package/dist/esm/start-compiler-plugin.js +0 -78
  65. package/dist/esm/start-compiler-plugin.js.map +0 -1
  66. package/src/compilers.ts +0 -659
  67. package/src/start-compiler-plugin.ts +0 -115
@@ -0,0 +1,78 @@
1
+ import * as t from '@babel/types'
2
+ import { getRootCallExpression } from './utils'
3
+ import type * as babel from '@babel/core'
4
+
5
+ import type { CompileOptions } from './compilers'
6
+
7
+ export function handleCreateIsomorphicFnCallExpression(
8
+ path: babel.NodePath<t.CallExpression>,
9
+ opts: CompileOptions,
10
+ ) {
11
+ const rootCallExpression = getRootCallExpression(path)
12
+
13
+ // if (debug)
14
+ // console.info(
15
+ // 'Handling createIsomorphicFn call expression:',
16
+ // rootCallExpression.toString(),
17
+ // )
18
+
19
+ const callExpressionPaths = {
20
+ client: null as babel.NodePath<t.CallExpression> | null,
21
+ server: null as babel.NodePath<t.CallExpression> | null,
22
+ }
23
+
24
+ const validMethods = Object.keys(callExpressionPaths)
25
+
26
+ rootCallExpression.traverse({
27
+ MemberExpression(memberExpressionPath) {
28
+ if (t.isIdentifier(memberExpressionPath.node.property)) {
29
+ const name = memberExpressionPath.node.property
30
+ .name as keyof typeof callExpressionPaths
31
+
32
+ if (
33
+ validMethods.includes(name) &&
34
+ memberExpressionPath.parentPath.isCallExpression()
35
+ ) {
36
+ callExpressionPaths[name] = memberExpressionPath.parentPath
37
+ }
38
+ }
39
+ },
40
+ })
41
+
42
+ if (
43
+ validMethods.every(
44
+ (method) =>
45
+ !callExpressionPaths[method as keyof typeof callExpressionPaths],
46
+ )
47
+ ) {
48
+ const variableId = rootCallExpression.parentPath.isVariableDeclarator()
49
+ ? rootCallExpression.parentPath.node.id
50
+ : null
51
+ console.warn(
52
+ 'createIsomorphicFn called without a client or server implementation!',
53
+ 'This will result in a no-op function.',
54
+ 'Variable name:',
55
+ t.isIdentifier(variableId) ? variableId.name : 'unknown',
56
+ )
57
+ }
58
+
59
+ const envCallExpression = callExpressionPaths[opts.env]
60
+
61
+ if (!envCallExpression) {
62
+ // if we don't have an implementation for this environment, default to a no-op
63
+ rootCallExpression.replaceWith(
64
+ t.arrowFunctionExpression([], t.blockStatement([])),
65
+ )
66
+ return
67
+ }
68
+
69
+ const innerInputExpression = envCallExpression.node.arguments[0]
70
+
71
+ if (!t.isExpression(innerInputExpression)) {
72
+ throw new Error(
73
+ `createIsomorphicFn().${opts.env}(func) must be called with a function!`,
74
+ )
75
+ }
76
+
77
+ rootCallExpression.replaceWith(innerInputExpression)
78
+ }
@@ -0,0 +1,79 @@
1
+ import * as t from '@babel/types'
2
+ import { getRootCallExpression } from './utils'
3
+ import type * as babel from '@babel/core'
4
+
5
+ import type { CompileOptions } from './compilers'
6
+
7
+ export function handleCreateMiddlewareCallExpression(
8
+ path: babel.NodePath<t.CallExpression>,
9
+ opts: CompileOptions,
10
+ ) {
11
+ const rootCallExpression = getRootCallExpression(path)
12
+
13
+ // if (debug)
14
+ // console.info(
15
+ // 'Handling createMiddleware call expression:',
16
+ // rootCallExpression.toString(),
17
+ // )
18
+
19
+ const callExpressionPaths = {
20
+ middleware: null as babel.NodePath<t.CallExpression> | null,
21
+ validator: null as babel.NodePath<t.CallExpression> | null,
22
+ client: null as babel.NodePath<t.CallExpression> | null,
23
+ server: null as babel.NodePath<t.CallExpression> | null,
24
+ }
25
+
26
+ const validMethods = Object.keys(callExpressionPaths)
27
+
28
+ rootCallExpression.traverse({
29
+ MemberExpression(memberExpressionPath) {
30
+ if (t.isIdentifier(memberExpressionPath.node.property)) {
31
+ const name = memberExpressionPath.node.property
32
+ .name as keyof typeof callExpressionPaths
33
+
34
+ if (
35
+ validMethods.includes(name) &&
36
+ memberExpressionPath.parentPath.isCallExpression()
37
+ ) {
38
+ callExpressionPaths[name] = memberExpressionPath.parentPath
39
+ }
40
+ }
41
+ },
42
+ })
43
+
44
+ if (callExpressionPaths.validator) {
45
+ const innerInputExpression = callExpressionPaths.validator.node.arguments[0]
46
+
47
+ if (!innerInputExpression) {
48
+ throw new Error(
49
+ 'createMiddleware().validator() must be called with a validator!',
50
+ )
51
+ }
52
+
53
+ // If we're on the client, remove the validator call expression
54
+ if (opts.env === 'client') {
55
+ if (t.isMemberExpression(callExpressionPaths.validator.node.callee)) {
56
+ callExpressionPaths.validator.replaceWith(
57
+ callExpressionPaths.validator.node.callee.object,
58
+ )
59
+ }
60
+ }
61
+ }
62
+
63
+ const serverFnPath = callExpressionPaths.server?.get(
64
+ 'arguments.0',
65
+ ) as babel.NodePath<any>
66
+
67
+ if (
68
+ callExpressionPaths.server &&
69
+ serverFnPath.node &&
70
+ opts.env === 'client'
71
+ ) {
72
+ // If we're on the client, remove the server call expression
73
+ if (t.isMemberExpression(callExpressionPaths.server.node.callee)) {
74
+ callExpressionPaths.server.replaceWith(
75
+ callExpressionPaths.server.node.callee.object,
76
+ )
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,122 @@
1
+ import { fileURLToPath, pathToFileURL } from 'node:url'
2
+ import { createRequire } from 'node:module'
3
+ import { logDiff } from '@tanstack/router-utils'
4
+
5
+ import { VIRTUAL_MODULES } from '@tanstack/start-server-core'
6
+ import { normalizePath } from 'vite'
7
+ import path from 'pathe'
8
+ import { VITE_ENVIRONMENT_NAMES } from '../constants'
9
+ import { compileStartOutputFactory } from './compilers'
10
+ import { transformFuncs } from './constants'
11
+ import type { ViteEnvironmentNames } from '../constants'
12
+ import type { Plugin } from 'vite'
13
+ import type { CompileStartFrameworkOptions } from './compilers'
14
+
15
+ const debug =
16
+ process.env.TSR_VITE_DEBUG &&
17
+ ['true', 'start-plugin'].includes(process.env.TSR_VITE_DEBUG)
18
+
19
+ export type TanStackStartViteOptions = {
20
+ globalMiddlewareEntry: string
21
+ }
22
+
23
+ const tokenRegex = new RegExp(transformFuncs.join('|'))
24
+
25
+ const require = createRequire(import.meta.url)
26
+
27
+ function resolveRuntimeFiles(opts: { package: string; files: Array<string> }) {
28
+ const pkgRoot = resolvePackage(opts.package)
29
+ const basePath = path.join(pkgRoot, 'dist', 'esm')
30
+
31
+ return opts.files.map((file) => normalizePath(path.join(basePath, file)))
32
+ }
33
+
34
+ function resolvePackage(packageName: string): string {
35
+ const pkgRoot = path.dirname(require.resolve(packageName + '/package.json'))
36
+ return pkgRoot
37
+ }
38
+
39
+ export function startCompilerPlugin(
40
+ framework: CompileStartFrameworkOptions,
41
+ ): Plugin {
42
+ const compileStartOutput = compileStartOutputFactory(framework)
43
+
44
+ return {
45
+ name: 'tanstack-start-core:compiler',
46
+ enforce: 'pre',
47
+ applyToEnvironment(env) {
48
+ return [
49
+ VITE_ENVIRONMENT_NAMES.client,
50
+ VITE_ENVIRONMENT_NAMES.server,
51
+ ].includes(env.name as ViteEnvironmentNames)
52
+ },
53
+ transform: {
54
+ filter: {
55
+ code: tokenRegex,
56
+ id: {
57
+ exclude: [
58
+ VIRTUAL_MODULES.serverFnManifest,
59
+ // N.B. the following files either just re-export or provide the runtime implementation of those functions
60
+ // we do not want to include them in the transformation
61
+ // however, those packages (especially start-client-core ATM) also USE these functions
62
+ // (namely `createIsomorphicFn` in `packages/start-client-core/src/getRouterInstance.ts`) and thus need to be transformed
63
+ ...resolveRuntimeFiles({
64
+ package: '@tanstack/start-client-core',
65
+ files: [
66
+ 'index.js',
67
+ 'createIsomorphicFn.js',
68
+ 'envOnly.js',
69
+ 'createServerFn.js',
70
+ 'createMiddleware.js',
71
+ 'serverFnFetcher.js',
72
+ ],
73
+ }),
74
+ ...resolveRuntimeFiles({
75
+ package: '@tanstack/start-server-core',
76
+ files: [
77
+ 'index.js',
78
+ 'server-functions-handler.js',
79
+ 'serverRoute.js',
80
+ ],
81
+ }),
82
+ ...resolveRuntimeFiles({
83
+ package: `@tanstack/${framework}-start-client`,
84
+ files: ['index.js'],
85
+ }),
86
+ ],
87
+ },
88
+ },
89
+ handler(code, id) {
90
+ const env =
91
+ this.environment.name === VITE_ENVIRONMENT_NAMES.client
92
+ ? 'client'
93
+ : this.environment.name === VITE_ENVIRONMENT_NAMES.server
94
+ ? 'server'
95
+ : (() => {
96
+ throw new Error(
97
+ `Environment ${this.environment.name} not configured`,
98
+ )
99
+ })()
100
+
101
+ const url = pathToFileURL(id)
102
+ url.searchParams.delete('v')
103
+ id = fileURLToPath(url).replace(/\\/g, '/')
104
+
105
+ if (debug) console.info(`${env} Compiling Start: `, id)
106
+
107
+ const compiled = compileStartOutput({
108
+ code,
109
+ filename: id,
110
+ env,
111
+ })
112
+
113
+ if (debug) {
114
+ logDiff(code, compiled.code)
115
+ console.log('Output:\n', compiled.code + '\n\n')
116
+ }
117
+
118
+ return compiled
119
+ },
120
+ },
121
+ }
122
+ }
@@ -0,0 +1,59 @@
1
+ import * as t from '@babel/types'
2
+ import type * as babel from '@babel/core'
3
+
4
+ import type { CompileOptions, CompileStartFrameworkOptions } from './compilers'
5
+
6
+ export function handleCreateServerFileRouteCallExpressionFactory(
7
+ framework: CompileStartFrameworkOptions,
8
+ method:
9
+ | 'createServerFileRoute'
10
+ | 'createServerRoute'
11
+ | 'createServerRootRoute',
12
+ ) {
13
+ return function handleCreateServerFileRouteCallExpression(
14
+ path: babel.NodePath<t.CallExpression>,
15
+ opts: CompileOptions,
16
+ ) {
17
+ const PACKAGES = { start: `@tanstack/${framework}-start/server` }
18
+
19
+ let highestParent: babel.NodePath<any> = path
20
+
21
+ while (highestParent.parentPath && !highestParent.parentPath.isProgram()) {
22
+ highestParent = highestParent.parentPath
23
+ }
24
+
25
+ const programPath = highestParent.parentPath as babel.NodePath<t.Program>
26
+
27
+ // If we're on the client, remove the entire variable
28
+ if (opts.env === 'client') {
29
+ highestParent.remove()
30
+ return
31
+ }
32
+
33
+ let isCreateServerFileRouteImported = false as boolean
34
+
35
+ programPath.traverse({
36
+ ImportDeclaration(importPath) {
37
+ const importSource = importPath.node.source.value
38
+ if (importSource === PACKAGES.start) {
39
+ const specifiers = importPath.node.specifiers
40
+ isCreateServerFileRouteImported ||= specifiers.some((specifier) => {
41
+ return (
42
+ t.isImportSpecifier(specifier) &&
43
+ t.isIdentifier(specifier.imported) &&
44
+ specifier.imported.name === method
45
+ )
46
+ })
47
+ }
48
+ },
49
+ })
50
+
51
+ if (!isCreateServerFileRouteImported) {
52
+ const importDeclaration = t.importDeclaration(
53
+ [t.importSpecifier(t.identifier(method), t.identifier(method))],
54
+ t.stringLiteral(PACKAGES.start),
55
+ )
56
+ programPath.node.body.unshift(importDeclaration)
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,41 @@
1
+ import { codeFrameColumns } from '@babel/code-frame'
2
+ import type * as t from '@babel/types'
3
+ import type * as babel from '@babel/core'
4
+
5
+ export function getRootCallExpression(path: babel.NodePath<t.CallExpression>) {
6
+ // Find the highest callExpression parent
7
+ let rootCallExpression: babel.NodePath<t.CallExpression> = path
8
+
9
+ // Traverse up the chain of CallExpressions
10
+ while (rootCallExpression.parentPath.isMemberExpression()) {
11
+ const parent = rootCallExpression.parentPath
12
+ if (parent.parentPath.isCallExpression()) {
13
+ rootCallExpression = parent.parentPath
14
+ }
15
+ }
16
+
17
+ return rootCallExpression
18
+ }
19
+
20
+ export function codeFrameError(
21
+ code: string,
22
+ loc: {
23
+ start: { line: number; column: number }
24
+ end: { line: number; column: number }
25
+ },
26
+ message: string,
27
+ ) {
28
+ const frame = codeFrameColumns(
29
+ code,
30
+ {
31
+ start: loc.start,
32
+ end: loc.end,
33
+ },
34
+ {
35
+ highlightCode: true,
36
+ message,
37
+ },
38
+ )
39
+
40
+ return new Error(frame)
41
+ }
@@ -1,21 +0,0 @@
1
- import { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils';
2
- import * as babel from '@babel/core';
3
- import * as t from '@babel/types';
4
- export type CompileStartFrameworkOptions = 'react' | 'solid';
5
- export declare function compileStartOutputFactory(framework: CompileStartFrameworkOptions): (opts: CompileOptions) => GeneratorResult;
6
- export declare const handleServerOnlyCallExpression: (path: babel.NodePath<t.CallExpression>, opts: CompileOptions) => void;
7
- export declare const handleClientOnlyCallExpression: (path: babel.NodePath<t.CallExpression>, opts: CompileOptions) => void;
8
- export type CompileOptions = ParseAstOptions & {
9
- env: 'server' | 'client';
10
- dce?: boolean;
11
- filename: string;
12
- };
13
- export type IdentifierConfig = {
14
- name: string;
15
- handleCallExpression: (path: babel.NodePath<t.CallExpression>, opts: CompileOptions) => void;
16
- paths: Array<babel.NodePath>;
17
- };
18
- export declare function handleCreateServerFnCallExpression(path: babel.NodePath<t.CallExpression>, opts: CompileOptions): void;
19
- export declare function handleCreateMiddlewareCallExpression(path: babel.NodePath<t.CallExpression>, opts: CompileOptions): void;
20
- export declare function handleCreateIsomorphicFnCallExpression(path: babel.NodePath<t.CallExpression>, opts: CompileOptions): void;
21
- export declare function getRootCallExpression(path: babel.NodePath<t.CallExpression>): babel.NodePath<t.CallExpression>;