From 49212faf7d8f65540500f78addb120649e3b2c19 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Mon, 13 Jan 2025 18:40:53 +0100 Subject: [PATCH 01/11] fix: remove dynamic from tuono-router --- packages/tuono-router/src/dynamic.tsx | 63 ------------------- packages/tuono-router/src/index.ts | 1 - packages/tuono-router/src/types.ts | 6 +- .../tuono/src/dynamic/route_lazy_loading.tsx | 27 ++++++++ packages/tuono/src/index.ts | 3 +- 5 files changed, 30 insertions(+), 70 deletions(-) delete mode 100644 packages/tuono-router/src/dynamic.tsx create mode 100644 packages/tuono/src/dynamic/route_lazy_loading.tsx diff --git a/packages/tuono-router/src/dynamic.tsx b/packages/tuono-router/src/dynamic.tsx deleted file mode 100644 index 9ff7ac99..00000000 --- a/packages/tuono-router/src/dynamic.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import * as React from 'react' -import type { ReactElement } from 'react' - -import type { RouteComponent } from './types' - -type ImportFn = () => Promise<{ default: RouteComponent }> - -/** - * Helper function to lazy load any component. - * - * The function acts exactly like React.lazy function but also renders the component on the server. - * If you want to just load the component client side use directly the react's lazy function. - * - * It can be wrapped within a React.Suspense component in order to handle its loading state. - */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const dynamic = (importFn: ImportFn): React.JSX.Element => { - /** - * - * This function is just a placeholder. The real work is done by the bundler. - * The custom babel plugin will create two different bundles for the client and the server. - * - * The client will import the React's lazy function while the server will statically - * import the file. - * - * Example: - * - * // User code - * import { dynamic } from 'tuono' - * const MyComponent = dynamic(() => import('./my-component')) - * - * // Client side generated code - * import { lazy } from 'react' - * const MyComponent = lazy(() => import('./my-component')) - * - * // Server side generated code - * import MyComponent from './my-component' - * - * Check the `lazy-fn-vite-plugin` package for more - */ - return <> -} - -export const __tuono__internal__lazyLoadComponent = ( - factory: ImportFn, -): RouteComponent => { - let LoadedComponent: RouteComponent | undefined - const LazyComponent = React.lazy(factory) as unknown as RouteComponent - - const loadComponent = (): Promise => - factory().then((module) => { - LoadedComponent = module.default - }) - - const Component = ( - props: React.ComponentProps, - ): ReactElement => - React.createElement(LoadedComponent || LazyComponent, props) - - Component.preload = loadComponent - - return Component -} diff --git a/packages/tuono-router/src/index.ts b/packages/tuono-router/src/index.ts index fdb28559..a29b44ca 100644 --- a/packages/tuono-router/src/index.ts +++ b/packages/tuono-router/src/index.ts @@ -2,5 +2,4 @@ export { RouterProvider } from './components/RouterProvider' export { default as Link } from './components/Link' export { createRouter } from './router' export { createRoute, createRootRoute } from './route' -export { dynamic, __tuono__internal__lazyLoadComponent } from './dynamic' export { useRouter } from './hooks/useRouter' diff --git a/packages/tuono-router/src/types.ts b/packages/tuono-router/src/types.ts index f6d0c2b7..7d0c8df7 100644 --- a/packages/tuono-router/src/types.ts +++ b/packages/tuono-router/src/types.ts @@ -1,4 +1,4 @@ -import type { ComponentType as ReactComponentType, ReactNode } from 'react' +import type { ReactNode } from 'react' export interface Segment { type: 'pathname' | 'param' | 'wildcard' @@ -22,7 +22,3 @@ export interface RouteProps { children?: ReactNode } - -export type RouteComponent = ReactComponentType & { - preload: () => void -} diff --git a/packages/tuono/src/dynamic/route_lazy_loading.tsx b/packages/tuono/src/dynamic/route_lazy_loading.tsx new file mode 100644 index 00000000..1b647ac9 --- /dev/null +++ b/packages/tuono/src/dynamic/route_lazy_loading.tsx @@ -0,0 +1,27 @@ +import * as React from 'react' +import type { ReactElement } from 'react' + +import type { RouteComponent } from './types' + +type ImportFn = () => Promise<{ default: RouteComponent }> + +export const __tuono__internal__lazyLoadComponent = ( + factory: ImportFn, +): RouteComponent => { + let LoadedComponent: RouteComponent | undefined + const LazyComponent = React.lazy(factory) as unknown as RouteComponent + + const loadComponent = (): Promise => + factory().then((module) => { + LoadedComponent = module.default + }) + + const Component = ( + props: React.ComponentProps, + ): ReactElement => + React.createElement(LoadedComponent || LazyComponent, props) + + Component.preload = loadComponent + + return Component +} diff --git a/packages/tuono/src/index.ts b/packages/tuono/src/index.ts index 11e47498..c6b0f4f4 100644 --- a/packages/tuono/src/index.ts +++ b/packages/tuono/src/index.ts @@ -5,7 +5,8 @@ export { Link, dynamic, useRouter, - __tuono__internal__lazyLoadComponent, } from 'tuono-router' +export { __tuono__internal__lazyLoadComponent } from './dynamic/route_lazy_loading' + export type { TuonoProps } from './types' From a198dff95683cfdf2e66aec61a9dbbbfe814499f Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Mon, 13 Jan 2025 21:13:42 +0100 Subject: [PATCH 02/11] feat: enable client only lazy loading with dynamic --- .../src/constants.ts | 1 + .../src/generator.ts | 22 ++--- packages/tuono-router/src/index.ts | 1 + packages/tuono-router/src/types.ts | 6 +- packages/tuono/src/build/index.ts | 2 +- packages/tuono/src/dynamic/dynamic.tsx | 82 +++++++++++++++++++ .../tuono/src/dynamic/route_lazy_loading.tsx | 2 +- packages/tuono/src/index.ts | 1 + 8 files changed, 103 insertions(+), 14 deletions(-) create mode 100644 packages/tuono/src/dynamic/dynamic.tsx diff --git a/packages/tuono-fs-router-vite-plugin/src/constants.ts b/packages/tuono-fs-router-vite-plugin/src/constants.ts index 2df09828..f91069cc 100644 --- a/packages/tuono-fs-router-vite-plugin/src/constants.ts +++ b/packages/tuono-fs-router-vite-plugin/src/constants.ts @@ -1,3 +1,4 @@ export const ROUTES_FOLDER = './src/routes/' export const LAYOUT_PATH_ID = '__layout' export const GENERATED_ROUTE_TREE = './.tuono/routeTree.gen.ts' +export const DYNAMIC_FN = '__tuono__internal__lazyLoadComponent' diff --git a/packages/tuono-fs-router-vite-plugin/src/generator.ts b/packages/tuono-fs-router-vite-plugin/src/generator.ts index 53e5f5b7..64b18f58 100644 --- a/packages/tuono-fs-router-vite-plugin/src/generator.ts +++ b/packages/tuono-fs-router-vite-plugin/src/generator.ts @@ -22,6 +22,7 @@ import { ROUTES_FOLDER, LAYOUT_PATH_ID, GENERATED_ROUTE_TREE, + DYNAMIC_FN, } from './constants' import { sortRouteNodes } from './sort-route-nodes' @@ -166,17 +167,16 @@ export async function routeGenerator(config = defaultConfig): Promise { const imports = [ ...sortedRouteNodes.map((node) => { const extension = node.filePath.endsWith('mdx') ? '.mdx' : '' - return `const ${ - node.variableName as string - }Import = dynamic(() => import('./${replaceBackslash( - removeExt( - path.relative( - path.dirname(config.generatedRouteTree), - path.resolve(config.folderName, node.filePath), + return `const ${node.variableName as string + }Import = ${DYNAMIC_FN}(() => import('./${replaceBackslash( + removeExt( + path.relative( + path.dirname(config.generatedRouteTree), + path.resolve(config.folderName, node.filePath), + ), + false, ), - false, - ), - )}${extension}'))` + )}${extension}'))` }), ].join('\n') @@ -214,7 +214,7 @@ export async function routeGenerator(config = defaultConfig): Promise { const routeImports = [ '// This file is auto-generated by Tuono', - "import { createRoute, dynamic } from 'tuono'", + `import { createRoute, ${DYNAMIC_FN} } from 'tuono'`, [ `import RootLayoutImport from './${replaceBackslash( path.relative( diff --git a/packages/tuono-router/src/index.ts b/packages/tuono-router/src/index.ts index a29b44ca..8a76e565 100644 --- a/packages/tuono-router/src/index.ts +++ b/packages/tuono-router/src/index.ts @@ -3,3 +3,4 @@ export { default as Link } from './components/Link' export { createRouter } from './router' export { createRoute, createRootRoute } from './route' export { useRouter } from './hooks/useRouter' +export type { RouteProps, RouteComponent } from './types' diff --git a/packages/tuono-router/src/types.ts b/packages/tuono-router/src/types.ts index 7d0c8df7..40fc5c63 100644 --- a/packages/tuono-router/src/types.ts +++ b/packages/tuono-router/src/types.ts @@ -1,4 +1,4 @@ -import type { ReactNode } from 'react' +import type { ReactNode, ComponentType } from 'react' export interface Segment { type: 'pathname' | 'param' | 'wildcard' @@ -22,3 +22,7 @@ export interface RouteProps { children?: ReactNode } + +export type RouteComponent = ComponentType & { + preload: () => void +} diff --git a/packages/tuono/src/build/index.ts b/packages/tuono/src/build/index.ts index 72345d4a..509bb948 100644 --- a/packages/tuono/src/build/index.ts +++ b/packages/tuono/src/build/index.ts @@ -67,7 +67,7 @@ function createBaseViteConfigFromTuonoConfig( react({ include: pluginFilesInclude }), TuonoFsRouterPlugin(), - TuonoLazyFnPlugin({ include: pluginFilesInclude }), + //TuonoLazyFnPlugin({ include: pluginFilesInclude }), ], } diff --git a/packages/tuono/src/dynamic/dynamic.tsx b/packages/tuono/src/dynamic/dynamic.tsx new file mode 100644 index 00000000..3377285e --- /dev/null +++ b/packages/tuono/src/dynamic/dynamic.tsx @@ -0,0 +1,82 @@ +/** + * This component is heavily inspired by Next.js dynamic function + * Link: /~https://github.com/vercel/next.js/blob/1df81bcea62800198884438a2bb27ba14c9d506a/packages/next/src/shared/lib/dynamic.tsx + */ +import * as React from 'react' + +const isServerSide = typeof window === 'undefined' + +type ComponentModule

= { default: React.ComponentType

} + +interface DynamicOptions { + ssr?: boolean + loading?: React.ComponentType | null +} + +type Loader = () => Promise | ComponentModule> + +interface LoadableOptions extends DynamicOptions { + loader: Loader +} + +export type LoadableFn

= ( + opts: LoadableOptions, +) => React.ComponentType

+ +const defaultLoaderOptions: LoadableOptions = { + ssr: true, + loading: null, + loader: () => Promise.resolve(() => null), +} + +function noSSR

( + LoadableInitializer: LoadableFn

, + loadableOptions: LoadableOptions, +): React.ComponentType

{ + if (!isServerSide) { + return LoadableInitializer(loadableOptions) + } + + if (!loadableOptions.loading) return () => null + + const Loading = loadableOptions.loading + // This will only be rendered on the server side + return () => +} + +const Loadable = (options: LoadableOptions) => { + const opts = { ...defaultLoaderOptions, ...options } + const Lazy = React.lazy(() => opts.loader().then()) + const Loading = opts.loading + + function LoadableComponent(props: any): React.JSX.Element { + const fallbackElement = Loading ? : null + + const Wrap = Loading ? React.Suspense : React.Fragment + const wrapProps = Loading ? { fallback: fallbackElement } : {} + + // TODO: In case ssr = false handle also the assets preloading + return ( + + + + ) + } + LoadableComponent.displayName = 'LoadableComponent' + + return LoadableComponent +} + +/** + * This function lets you dynamically import a component. + * It uses [React.lazy()](https://react.dev/reference/react/lazy) with [Suspense](https://react.dev/reference/react/Suspense) under the hood. + */ +export const dynamic =

( + importFn: Loader, + opts?: DynamicOptions, +): React.ComponentType

=> { + if (typeof opts?.ssr === 'boolean' && !opts?.ssr) { + return noSSR(Loadable, { ...opts, loader: importFn }) + } + return Loadable({ ...opts, loader: importFn }) +} diff --git a/packages/tuono/src/dynamic/route_lazy_loading.tsx b/packages/tuono/src/dynamic/route_lazy_loading.tsx index 1b647ac9..22ed582c 100644 --- a/packages/tuono/src/dynamic/route_lazy_loading.tsx +++ b/packages/tuono/src/dynamic/route_lazy_loading.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import type { ReactElement } from 'react' -import type { RouteComponent } from './types' +import type { RouteComponent } from 'tuono-router' type ImportFn = () => Promise<{ default: RouteComponent }> diff --git a/packages/tuono/src/index.ts b/packages/tuono/src/index.ts index c6b0f4f4..dea74d72 100644 --- a/packages/tuono/src/index.ts +++ b/packages/tuono/src/index.ts @@ -8,5 +8,6 @@ export { } from 'tuono-router' export { __tuono__internal__lazyLoadComponent } from './dynamic/route_lazy_loading' +export { dynamic } from './dynamic/dynamic' export type { TuonoProps } from './types' From 1ff9b592b6149e790d8e53c4335a1e66f9889e2b Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Tue, 14 Jan 2025 19:14:17 +0100 Subject: [PATCH 03/11] chore: remove tuono-lazy-fn-vite-plugin --- packages/tuono-lazy-fn-vite-plugin/README.md | 8 - .../tuono-lazy-fn-vite-plugin/package.json | 57 ------ .../src/constants.ts | 3 - .../tuono-lazy-fn-vite-plugin/src/index.ts | 169 ------------------ .../tuono-lazy-fn-vite-plugin/src/utils.ts | 25 --- .../sources/dynamic-only/client.expected.tsx | 9 - .../sources/dynamic-only/server.expected.tsx | 8 - .../tests/sources/dynamic-only/source.tsx | 14 -- .../external-dynamic/client.expected.tsx | 4 - .../external-dynamic/server.expected.tsx | 4 - .../tests/sources/external-dynamic/source.tsx | 7 - .../tests/sources/vanilla/client.expected.tsx | 3 - .../tests/sources/vanilla/server.expected.tsx | 3 - .../tests/sources/vanilla/source.tsx | 6 - .../tests/transpileSource.test.ts | 94 ---------- .../tuono-lazy-fn-vite-plugin/tsconfig.json | 5 - .../tuono-lazy-fn-vite-plugin/vite.config.ts | 12 -- 17 files changed, 431 deletions(-) delete mode 100644 packages/tuono-lazy-fn-vite-plugin/README.md delete mode 100644 packages/tuono-lazy-fn-vite-plugin/package.json delete mode 100644 packages/tuono-lazy-fn-vite-plugin/src/constants.ts delete mode 100644 packages/tuono-lazy-fn-vite-plugin/src/index.ts delete mode 100644 packages/tuono-lazy-fn-vite-plugin/src/utils.ts delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/client.expected.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/server.expected.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/source.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/client.expected.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/server.expected.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/source.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/client.expected.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/server.expected.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/source.tsx delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tests/transpileSource.test.ts delete mode 100644 packages/tuono-lazy-fn-vite-plugin/tsconfig.json delete mode 100644 packages/tuono-lazy-fn-vite-plugin/vite.config.ts diff --git a/packages/tuono-lazy-fn-vite-plugin/README.md b/packages/tuono-lazy-fn-vite-plugin/README.md deleted file mode 100644 index 76135f94..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# tuono-lazy-fn-vite-plugin - -This is a vite plugin for [tuono](/~https://github.com/tuono-labs/tuono). - -This package specifically handles the transpiling of the `dynamic` function -allowing custom componenents to be lazy loaded but also server side rendered. - -Check [tuono](/~https://github.com/tuono-labs/tuono) for more. diff --git a/packages/tuono-lazy-fn-vite-plugin/package.json b/packages/tuono-lazy-fn-vite-plugin/package.json deleted file mode 100644 index 661595d2..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "tuono-lazy-fn-vite-plugin", - "version": "0.17.0", - "description": "Plugin for the tuono's lazy fn. Tuono is the react/rust fullstack framework", - "homepage": "https://tuono.dev", - "scripts": { - "dev": "vite build --watch", - "build": "vite build", - "lint": "eslint .", - "format": "prettier --write --ignore-unknown --ignore-path ../../.prettierignore .", - "format:check": "prettier --check --ignore-unknown --ignore-path ../../.prettierignore .", - "types": "tsc --noEmit", - "test:watch": "vitest", - "test": "vitest run" - }, - "repository": { - "type": "git", - "url": "git+/~https://github.com/tuono-labs/tuono.git", - "directory": "packages/tuono-lazy-fn-vite-plugin" - }, - "keywords": [], - "author": "Valerio Ageno", - "license": "MIT", - "type": "module", - "types": "dist/esm/index.d.ts", - "main": "dist/cjs/index.cjs", - "module": "dist/esm/index.js", - "files": [ - "dist", - "src", - "README.md" - ], - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - }, - "require": { - "types": "./dist/cjs/index.d.cts", - "default": "./dist/cjs/index.cjs" - } - }, - "./package.json": "./package.json" - }, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/types": "^7.24.0", - "vite": "^5.2.11" - }, - "devDependencies": { - "@tanstack/config": "0.7.13", - "@types/babel__core": "^7.20.5", - "prettier": "^3.2.4", - "vitest": "2.1.8" - } -} diff --git a/packages/tuono-lazy-fn-vite-plugin/src/constants.ts b/packages/tuono-lazy-fn-vite-plugin/src/constants.ts deleted file mode 100644 index bed282fe..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/src/constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const TUONO_DYNAMIC_FN_ID = 'dynamic' -export const TUONO_LAZY_FN_ID = '__tuono__internal__lazyLoadComponent' -export const TUONO_MAIN_PACKAGE = 'tuono' diff --git a/packages/tuono-lazy-fn-vite-plugin/src/index.ts b/packages/tuono-lazy-fn-vite-plugin/src/index.ts deleted file mode 100644 index b34eb6ae..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/src/index.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { transformSync } from '@babel/core' -import type { PluginItem as BabelPluginItem } from '@babel/core' -import * as BabelTypes from '@babel/types' -import { createFilter } from 'vite' -import type { Plugin as VitePlugin, Rollup, FilterPattern } from 'vite' - -import { - TUONO_MAIN_PACKAGE, - TUONO_DYNAMIC_FN_ID, - TUONO_LAZY_FN_ID, -} from './constants' -import { isTuonoDynamicFnImported } from './utils' - -/** - * [SERVER build] - * This plugin just removes the `dynamic` imported function from any tuono import - */ -const RemoveTuonoLazyImport: BabelPluginItem = { - name: 'remove-tuono-lazy-import-plugin', - visitor: { - ImportDeclaration: (path) => { - const importNode = path.node - if (importNode.source.value !== TUONO_MAIN_PACKAGE) return - - path.traverse({ - ImportSpecifier: (importSpecifierPath) => { - if (isTuonoDynamicFnImported(importSpecifierPath)) { - importSpecifierPath.remove() - } - }, - }) - - // If there are no specifiers left after traverse - // remove the import to avoid unwanted side effects - if (importNode.specifiers.length === 0) { - path.remove() - } - }, - }, -} - -/** - * [CLIENT build] - * This plugin replace the `dynamic` function with the `__tuono__internal__lazyLoadComponent` one - */ -const ReplaceTuonoLazyImport: BabelPluginItem = { - name: 'replace-tuono-lazy-import-plugin', - visitor: { - ImportSpecifier: (path) => { - if ( - BabelTypes.isIdentifier(path.node.imported) && - isTuonoDynamicFnImported(path) - ) { - path.node.imported.name = TUONO_LAZY_FN_ID - } - }, - }, -} - -const turnLazyIntoStatic = { - VariableDeclaration: ( - path: babel.NodePath, - ): void => { - path.node.declarations.forEach((variableDeclarationNode) => { - const init = variableDeclarationNode.init - - if ( - BabelTypes.isCallExpression(init) && - // ensures that the method call is `TUONO_DYNAMIC_FN_ID` - BabelTypes.isIdentifier(init.callee, { name: TUONO_DYNAMIC_FN_ID }) && - // import name must be an identifier - BabelTypes.isIdentifier(variableDeclarationNode.id) && - // check that the first function parameter is an arrow function - BabelTypes.isArrowFunctionExpression(init.arguments[0]) - ) { - const cmpImportFn = init.arguments[0] - - // ensures that the first parameter is a call expression (may be a block statement) - if (!BabelTypes.isCallExpression(cmpImportFn.body)) return - // ensures that the first parameter is a string literal (the import path) - if (!BabelTypes.isStringLiteral(cmpImportFn.body.arguments[0])) return - - const importName = variableDeclarationNode.id.name - const importPath = cmpImportFn.body.arguments[0].value - - if (importName && importPath) { - const importDeclaration = BabelTypes.importDeclaration( - [ - BabelTypes.importDefaultSpecifier( - BabelTypes.identifier(importName), - ), - ], - BabelTypes.stringLiteral(importPath), - ) - - path.replaceWith(importDeclaration) - } - } - }) - }, -} - -/** - * [SERVER build] - * This plugin statically imports the lazy loaded components - */ -const TurnLazyIntoStaticImport: BabelPluginItem = { - name: 'turn-lazy-into-static-import-plugin', - visitor: { - Program: (path) => { - path.traverse({ - ImportSpecifier: (subPath) => { - if (isTuonoDynamicFnImported(subPath)) { - path.traverse(turnLazyIntoStatic) - } - }, - }) - }, - }, -} - -interface TuonoLazyFnPluginOptions { - include: FilterPattern -} - -export function TuonoLazyFnPlugin( - options: TuonoLazyFnPluginOptions, -): VitePlugin { - const { include } = options - - const filter = createFilter(include) - - return { - name: 'vite-plugin-tuono-lazy-loading', - enforce: 'pre', - transform(code, id, opts): Rollup.TransformResult { - if (!filter(id)) return - - /** - * @todo we should exclude non tsx files from this transformation - * this might benefit build time avoiding running `includes` on non-tsx files. - * This can be executed using `_id` parameter - * which is the filepath that is being processed - */ - - if ( - code.includes(TUONO_DYNAMIC_FN_ID) && - code.includes(TUONO_MAIN_PACKAGE) - ) { - const plugins: Array = [ - ['@babel/plugin-syntax-jsx', {}], - ['@babel/plugin-syntax-typescript', { isTSX: true }], - ] - - if (opts?.ssr) { - plugins.push(RemoveTuonoLazyImport, TurnLazyIntoStaticImport) - } else { - plugins.push(ReplaceTuonoLazyImport) - } - - const res = transformSync(code, { plugins }) - - return res?.code - } - - return code - }, - } -} diff --git a/packages/tuono-lazy-fn-vite-plugin/src/utils.ts b/packages/tuono-lazy-fn-vite-plugin/src/utils.ts deleted file mode 100644 index 4e3390fc..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/src/utils.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - isIdentifier, - isImportDeclaration, - isImportSpecifier, -} from '@babel/types' - -import { TUONO_MAIN_PACKAGE, TUONO_DYNAMIC_FN_ID } from './constants' - -/** - * By a given AST Node path returns true if the path involves an import specifier - * importing {@link TUONO_DYNAMIC_FN_ID} - */ -export const isTuonoDynamicFnImported = (path: babel.NodePath): boolean => { - // If the node isn't an import declaration there is no need to process it - if (!isImportDeclaration(path.parentPath?.node)) return false - - // if the import doesn't import from 'tuono' we don't need to process it - if (path.parentPath.node.source.value !== TUONO_MAIN_PACKAGE) return false - - // ensure that we are processing an import specifier - if (!isImportSpecifier(path.node)) return false - - // finally check if the imported item is `TUONO_DYNAMIC_FN_ID` - return isIdentifier(path.node.imported, { name: TUONO_DYNAMIC_FN_ID }) -} diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/client.expected.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/client.expected.tsx deleted file mode 100644 index 87cbe459..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/client.expected.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React, { Suspense, type JSX } from "react"; -import { __tuono__internal__lazyLoadComponent as dynamic } from "tuono"; -const DynamicComponent = dynamic(() => import("../components/DynamicComponent")); -const Loading = (): JSX.Element => <>Loading; -export default function IndexPage(): JSX.Element { - return }> - - ; -} \ No newline at end of file diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/server.expected.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/server.expected.tsx deleted file mode 100644 index 195d781f..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/server.expected.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React, { Suspense, type JSX } from "react"; -import DynamicComponent from "../components/DynamicComponent"; -const Loading = (): JSX.Element => <>Loading; -export default function IndexPage(): JSX.Element { - return }> - - ; -} \ No newline at end of file diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/source.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/source.tsx deleted file mode 100644 index 98981ad8..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/dynamic-only/source.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { Suspense, type JSX } from "react"; -import { dynamic } from "tuono"; - -const DynamicComponent = dynamic(() => import("../components/DynamicComponent")) - -const Loading = (): JSX.Element => <>Loading - -export default function IndexPage(): JSX.Element { - return ( - }> - - - ); -} \ No newline at end of file diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/client.expected.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/client.expected.tsx deleted file mode 100644 index 2f76de16..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/client.expected.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { createRoute } from 'tuono'; -import { dynamic } from 'external-lib'; -const IndexImport = dynamic(() => import('./../src/routes/index')); -const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]')); diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/server.expected.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/server.expected.tsx deleted file mode 100644 index 2f76de16..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/server.expected.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { createRoute } from 'tuono'; -import { dynamic } from 'external-lib'; -const IndexImport = dynamic(() => import('./../src/routes/index')); -const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]')); diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/source.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/source.tsx deleted file mode 100644 index f3062fee..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/external-dynamic/source.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createRoute } from 'tuono' -import { dynamic } from 'external-lib' - -const IndexImport = dynamic(() => import('./../src/routes/index')) -const PokemonspokemonImport = dynamic( - () => import('./../src/routes/pokemons/[pokemon]'), -) diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/client.expected.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/client.expected.tsx deleted file mode 100644 index 978c3aa1..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/client.expected.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { createRoute, __tuono__internal__lazyLoadComponent as dynamic } from 'tuono'; -const IndexImport = dynamic(() => import('./../src/routes/index')); -const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]')); diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/server.expected.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/server.expected.tsx deleted file mode 100644 index 00aa40c8..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/server.expected.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { createRoute } from 'tuono'; -import IndexImport from "./../src/routes/index"; -import PokemonspokemonImport from "./../src/routes/pokemons/[pokemon]"; diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/source.tsx b/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/source.tsx deleted file mode 100644 index 0f912545..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/sources/vanilla/source.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { createRoute, dynamic } from 'tuono' - -const IndexImport = dynamic(() => import('./../src/routes/index')) -const PokemonspokemonImport = dynamic( - () => import('./../src/routes/pokemons/[pokemon]'), -) diff --git a/packages/tuono-lazy-fn-vite-plugin/tests/transpileSource.test.ts b/packages/tuono-lazy-fn-vite-plugin/tests/transpileSource.test.ts deleted file mode 100644 index ffdbc177..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tests/transpileSource.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import fs from 'node:fs/promises' -import os from 'node:os' - -import { it, expect, describe } from 'vitest' -import type { Plugin } from 'vite' - -import { TuonoLazyFnPlugin } from '../src' - -type ViteTransformHandler = Exclude< - Plugin['transform'], - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - Function | undefined ->['handler'] - -// Create a type-safe transform method -function getTransform(): (...args: Parameters) => string { - /** @warning Keep in sync with {@link createBaseViteConfigFromTuonoConfig} */ - const pluginFilesInclude = /\.(jsx|js|mdx|md|tsx|ts)$/ - - return TuonoLazyFnPlugin({ include: pluginFilesInclude }).transform as never -} - -describe('"dynamic" sources', async () => { - const folderNames = await fs.readdir(`${process.cwd()}/tests/sources`) - - describe.each(folderNames)('%s', async (folderName) => { - const testDirPath = `${process.cwd()}/tests/sources/${folderName}` - - const sourceFilePath = `${testDirPath}/source.tsx` - - const sourceRaw = await fs.readFile(sourceFilePath, 'utf-8') - /** - * When adding `packages/lazy-fn-vite-plugin/tests/sources/dynamic-only` only - * the test involving that fixture were broken on Windows... but not the one in the other fixtures: - * - packages/lazy-fn-vite-plugin/tests/sources/vanilla - * - packages/lazy-fn-vite-plugin/tests/sources/external-dynamic - * - * Awkwardly this doesn't happen on `packages/fs-router-vite-plugin/tests/generator.spec.ts` - * - * Too much pain and sadness to investigate this right now. - * Might worth creating an utility function in the future if this happens again - */ - const source = sourceRaw.replace(new RegExp(os.EOL, 'g'), '\n') - - it('should generate file for client', async () => { - const pluginTransform = getTransform() - const clientBundle = pluginTransform(source, sourceFilePath) - - const expectedClientSrc = `${testDirPath}/client.expected.tsx` - - await expect(clientBundle).toMatchFileSnapshot( - expectedClientSrc, - `${testDirPath} client build should be equal to ${expectedClientSrc}`, - ) - }) - - it('should generate file for server', async () => { - const pluginTransform = getTransform() - const serverBundle = pluginTransform(source, sourceFilePath, { - ssr: true, - }) - - const expectedServerSrc = `${testDirPath}/server.expected.tsx` - - await expect(serverBundle).toMatchFileSnapshot( - expectedServerSrc, - `${testDirPath} server build should be equal to ${expectedServerSrc}`, - ) - }) - }) -}) - -describe('not valid file should not be processed', () => { - const notValidFiles: Array = [ - 'src/styles/module.css', - 'src/pages/file-without-ext', - 'src/pages/file-with-invalid-ext', - 'src/components/fileWithInvalidExt', - 'src/components/sidebar/sidebar-link.module.css', - ] - - it.each(notValidFiles)('"%s"', (fileName) => { - const pluginTransform = getTransform() - - const code = [ - "import { createRoute, dynamic } from 'tuono'", - "const IndexImport = dynamic(() => import('./../src/routes/index'))", - ].join('\n') - - const result = pluginTransform(code, fileName) - - expect(result).toBeUndefined() - }) -}) diff --git a/packages/tuono-lazy-fn-vite-plugin/tsconfig.json b/packages/tuono-lazy-fn-vite-plugin/tsconfig.json deleted file mode 100644 index a30a085c..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src", "tests", "vite.config.ts"], - "exclude": ["tests/sources"] -} diff --git a/packages/tuono-lazy-fn-vite-plugin/vite.config.ts b/packages/tuono-lazy-fn-vite-plugin/vite.config.ts deleted file mode 100644 index c09134a3..00000000 --- a/packages/tuono-lazy-fn-vite-plugin/vite.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackBuildConfig } from '@tanstack/config/build' - -const config = defineConfig({}) - -export default mergeConfig( - config, - tanstackBuildConfig({ - entry: './src/index.ts', - srcDir: './src', - }), -) From 505f3b5f3aa783eb777ed2f6e53da4555c138ae0 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Tue, 14 Jan 2025 19:20:33 +0100 Subject: [PATCH 04/11] tests: align tuono-fs-router-vite-plugin tests --- .../src/constants.ts | 2 +- .../generator/catch_all/routeTree.expected.ts | 8 +++--- .../tests/generator/mdx/routeTree.expected.ts | 10 ++++--- .../routeTree.expected.ts | 26 ++++++++++++++----- .../multi-level/routeTree.expected.ts | 14 +++++++--- .../single-level/routeTree.expected.ts | 10 ++++--- packages/tuono/src/build/index.ts | 1 - .../tuono/src/dynamic/route_lazy_loading.tsx | 2 +- 8 files changed, 50 insertions(+), 23 deletions(-) diff --git a/packages/tuono-fs-router-vite-plugin/src/constants.ts b/packages/tuono-fs-router-vite-plugin/src/constants.ts index f91069cc..7b0718e0 100644 --- a/packages/tuono-fs-router-vite-plugin/src/constants.ts +++ b/packages/tuono-fs-router-vite-plugin/src/constants.ts @@ -1,4 +1,4 @@ export const ROUTES_FOLDER = './src/routes/' export const LAYOUT_PATH_ID = '__layout' export const GENERATED_ROUTE_TREE = './.tuono/routeTree.gen.ts' -export const DYNAMIC_FN = '__tuono__internal__lazyLoadComponent' +export const DYNAMIC_FN = '__tuono__internal__lazyLoadRoute' diff --git a/packages/tuono-fs-router-vite-plugin/tests/generator/catch_all/routeTree.expected.ts b/packages/tuono-fs-router-vite-plugin/tests/generator/catch_all/routeTree.expected.ts index 7910bdd7..29cb3294 100644 --- a/packages/tuono-fs-router-vite-plugin/tests/generator/catch_all/routeTree.expected.ts +++ b/packages/tuono-fs-router-vite-plugin/tests/generator/catch_all/routeTree.expected.ts @@ -1,11 +1,13 @@ // This file is auto-generated by Tuono -import { createRoute, dynamic } from 'tuono' +import { createRoute, __tuono__internal__lazyLoadRoute } from 'tuono' import RootLayoutImport from './routes/__layout' -const IndexImport = dynamic(() => import('./routes/index')) -const PostscatchallImport = dynamic( +const IndexImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/index'), +) +const PostscatchallImport = __tuono__internal__lazyLoadRoute( () => import('./routes/posts/[...catch_all]'), ) diff --git a/packages/tuono-fs-router-vite-plugin/tests/generator/mdx/routeTree.expected.ts b/packages/tuono-fs-router-vite-plugin/tests/generator/mdx/routeTree.expected.ts index 6ee4883a..e4741257 100644 --- a/packages/tuono-fs-router-vite-plugin/tests/generator/mdx/routeTree.expected.ts +++ b/packages/tuono-fs-router-vite-plugin/tests/generator/mdx/routeTree.expected.ts @@ -1,11 +1,15 @@ // This file is auto-generated by Tuono -import { createRoute, dynamic } from 'tuono' +import { createRoute, __tuono__internal__lazyLoadRoute } from 'tuono' import RootLayoutImport from './routes/__layout' -const AboutImport = dynamic(() => import('./routes/about.mdx')) -const IndexImport = dynamic(() => import('./routes/index')) +const AboutImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/about.mdx'), +) +const IndexImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/index'), +) const rootRoute = createRoute({ isRoot: true, component: RootLayoutImport }) diff --git a/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level-root-dynamic/routeTree.expected.ts b/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level-root-dynamic/routeTree.expected.ts index e17e1af6..d686da5e 100644 --- a/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level-root-dynamic/routeTree.expected.ts +++ b/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level-root-dynamic/routeTree.expected.ts @@ -1,15 +1,27 @@ // This file is auto-generated by Tuono -import { createRoute, dynamic } from 'tuono' +import { createRoute, __tuono__internal__lazyLoadRoute } from 'tuono' import RootLayoutImport from './routes/__layout' -const PostslayoutImport = dynamic(() => import('./routes/posts/__layout')) -const AboutImport = dynamic(() => import('./routes/about')) -const IndexImport = dynamic(() => import('./routes/index')) -const PostspostImport = dynamic(() => import('./routes/posts/[post]')) -const PostsIndexImport = dynamic(() => import('./routes/posts/index')) -const PostsMyPostImport = dynamic(() => import('./routes/posts/my-post')) +const PostslayoutImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/posts/__layout'), +) +const AboutImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/about'), +) +const IndexImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/index'), +) +const PostspostImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/posts/[post]'), +) +const PostsIndexImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/posts/index'), +) +const PostsMyPostImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/posts/my-post'), +) const rootRoute = createRoute({ isRoot: true, component: RootLayoutImport }) diff --git a/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level/routeTree.expected.ts b/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level/routeTree.expected.ts index f91e1f6a..2190ffbb 100644 --- a/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level/routeTree.expected.ts +++ b/packages/tuono-fs-router-vite-plugin/tests/generator/multi-level/routeTree.expected.ts @@ -1,12 +1,18 @@ // This file is auto-generated by Tuono -import { createRoute, dynamic } from 'tuono' +import { createRoute, __tuono__internal__lazyLoadRoute } from 'tuono' import RootLayoutImport from './routes/__layout' -const AboutImport = dynamic(() => import('./routes/about')) -const IndexImport = dynamic(() => import('./routes/index')) -const PostsMyPostImport = dynamic(() => import('./routes/posts/my-post')) +const AboutImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/about'), +) +const IndexImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/index'), +) +const PostsMyPostImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/posts/my-post'), +) const rootRoute = createRoute({ isRoot: true, component: RootLayoutImport }) diff --git a/packages/tuono-fs-router-vite-plugin/tests/generator/single-level/routeTree.expected.ts b/packages/tuono-fs-router-vite-plugin/tests/generator/single-level/routeTree.expected.ts index 5e276f01..3db42380 100644 --- a/packages/tuono-fs-router-vite-plugin/tests/generator/single-level/routeTree.expected.ts +++ b/packages/tuono-fs-router-vite-plugin/tests/generator/single-level/routeTree.expected.ts @@ -1,11 +1,15 @@ // This file is auto-generated by Tuono -import { createRoute, dynamic } from 'tuono' +import { createRoute, __tuono__internal__lazyLoadRoute } from 'tuono' import RootLayoutImport from './routes/__layout' -const AboutImport = dynamic(() => import('./routes/about')) -const IndexImport = dynamic(() => import('./routes/index')) +const AboutImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/about'), +) +const IndexImport = __tuono__internal__lazyLoadRoute( + () => import('./routes/index'), +) const rootRoute = createRoute({ isRoot: true, component: RootLayoutImport }) diff --git a/packages/tuono/src/build/index.ts b/packages/tuono/src/build/index.ts index 509bb948..03bf0f3c 100644 --- a/packages/tuono/src/build/index.ts +++ b/packages/tuono/src/build/index.ts @@ -67,7 +67,6 @@ function createBaseViteConfigFromTuonoConfig( react({ include: pluginFilesInclude }), TuonoFsRouterPlugin(), - //TuonoLazyFnPlugin({ include: pluginFilesInclude }), ], } diff --git a/packages/tuono/src/dynamic/route_lazy_loading.tsx b/packages/tuono/src/dynamic/route_lazy_loading.tsx index 22ed582c..bbe82185 100644 --- a/packages/tuono/src/dynamic/route_lazy_loading.tsx +++ b/packages/tuono/src/dynamic/route_lazy_loading.tsx @@ -5,7 +5,7 @@ import type { RouteComponent } from 'tuono-router' type ImportFn = () => Promise<{ default: RouteComponent }> -export const __tuono__internal__lazyLoadComponent = ( +export const __tuono__internal__lazyLoadRoute = ( factory: ImportFn, ): RouteComponent => { let LoadedComponent: RouteComponent | undefined From 2f25c75e89416911a54cda09ab2bc50e84c4f31d Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Tue, 14 Jan 2025 19:20:53 +0100 Subject: [PATCH 05/11] fix: formatting --- .../src/generator.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/tuono-fs-router-vite-plugin/src/generator.ts b/packages/tuono-fs-router-vite-plugin/src/generator.ts index 64b18f58..225835c3 100644 --- a/packages/tuono-fs-router-vite-plugin/src/generator.ts +++ b/packages/tuono-fs-router-vite-plugin/src/generator.ts @@ -167,16 +167,17 @@ export async function routeGenerator(config = defaultConfig): Promise { const imports = [ ...sortedRouteNodes.map((node) => { const extension = node.filePath.endsWith('mdx') ? '.mdx' : '' - return `const ${node.variableName as string - }Import = ${DYNAMIC_FN}(() => import('./${replaceBackslash( - removeExt( - path.relative( - path.dirname(config.generatedRouteTree), - path.resolve(config.folderName, node.filePath), - ), - false, + return `const ${ + node.variableName as string + }Import = ${DYNAMIC_FN}(() => import('./${replaceBackslash( + removeExt( + path.relative( + path.dirname(config.generatedRouteTree), + path.resolve(config.folderName, node.filePath), ), - )}${extension}'))` + false, + ), + )}${extension}'))` }), ].join('\n') From 861bd3eb4ce2cb9f2779ed4a5f124bd9c46f47eb Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Tue, 14 Jan 2025 19:26:41 +0100 Subject: [PATCH 06/11] fix: exports reference --- packages/tuono/src/build/index.ts | 1 - packages/tuono/src/index.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/tuono/src/build/index.ts b/packages/tuono/src/build/index.ts index 03bf0f3c..9781b4d6 100644 --- a/packages/tuono/src/build/index.ts +++ b/packages/tuono/src/build/index.ts @@ -3,7 +3,6 @@ import { build, createServer, mergeConfig } from 'vite' import react from '@vitejs/plugin-react-swc' import inject from '@rollup/plugin-inject' import { TuonoFsRouterPlugin } from 'tuono-fs-router-vite-plugin' -import { TuonoLazyFnPlugin } from 'tuono-lazy-fn-vite-plugin' import type { TuonoConfig } from '../config' diff --git a/packages/tuono/src/index.ts b/packages/tuono/src/index.ts index dea74d72..d7b424c1 100644 --- a/packages/tuono/src/index.ts +++ b/packages/tuono/src/index.ts @@ -7,7 +7,7 @@ export { useRouter, } from 'tuono-router' -export { __tuono__internal__lazyLoadComponent } from './dynamic/route_lazy_loading' +export { __tuono__internal__lazyLoadRoute } from './dynamic/route_lazy_loading' export { dynamic } from './dynamic/dynamic' export type { TuonoProps } from './types' From bacf635c17c4647f95f971ca15e01bd4d73be3b3 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Tue, 14 Jan 2025 19:29:50 +0100 Subject: [PATCH 07/11] fix: build error --- packages/tuono/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tuono/src/index.ts b/packages/tuono/src/index.ts index d7b424c1..fb5b75ad 100644 --- a/packages/tuono/src/index.ts +++ b/packages/tuono/src/index.ts @@ -3,7 +3,6 @@ export { createRootRoute, createRouter, Link, - dynamic, useRouter, } from 'tuono-router' From 7124f7f98594f336a0f6826e99d80666325d3061 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Tue, 14 Jan 2025 21:01:53 +0100 Subject: [PATCH 08/11] fix: linting --- packages/tuono/src/dynamic/dynamic.tsx | 53 +++++++++++++++----------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/tuono/src/dynamic/dynamic.tsx b/packages/tuono/src/dynamic/dynamic.tsx index 3377285e..438a3069 100644 --- a/packages/tuono/src/dynamic/dynamic.tsx +++ b/packages/tuono/src/dynamic/dynamic.tsx @@ -6,33 +6,37 @@ import * as React from 'react' const isServerSide = typeof window === 'undefined' -type ComponentModule

= { default: React.ComponentType

} +interface ComponentModule { + default: React.ComponentType +} interface DynamicOptions { ssr?: boolean - loading?: React.ComponentType | null + loading?: React.ComponentType | null } -type Loader = () => Promise | ComponentModule> +type Loader = () => Promise< + React.ComponentType | ComponentModule +> -interface LoadableOptions extends DynamicOptions { - loader: Loader +interface LoadableOptions extends DynamicOptions { + loader: Loader } -export type LoadableFn

= ( - opts: LoadableOptions, -) => React.ComponentType

+type LoadableFn = ( + options: LoadableOptions, +) => React.ComponentType -const defaultLoaderOptions: LoadableOptions = { +const defaultLoaderOptions: LoadableOptions = { ssr: true, loading: null, loader: () => Promise.resolve(() => null), } -function noSSR

( - LoadableInitializer: LoadableFn

, - loadableOptions: LoadableOptions, -): React.ComponentType

{ +function noSSR( + LoadableInitializer: LoadableFn, + loadableOptions: LoadableOptions, +): React.ComponentType { if (!isServerSide) { return LoadableInitializer(loadableOptions) } @@ -41,15 +45,20 @@ function noSSR

( const Loading = loadableOptions.loading // This will only be rendered on the server side - return () => + function NoSSRLoading(): React.JSX.Element { + return + } + return NoSSRLoading } -const Loadable = (options: LoadableOptions) => { +const Loadable = ( + options: LoadableOptions, +): React.ComponentType => { const opts = { ...defaultLoaderOptions, ...options } const Lazy = React.lazy(() => opts.loader().then()) const Loading = opts.loading - function LoadableComponent(props: any): React.JSX.Element { + function LoadableComponent(props: T): React.JSX.Element { const fallbackElement = Loading ? : null const Wrap = Loading ? React.Suspense : React.Fragment @@ -71,12 +80,12 @@ const Loadable = (options: LoadableOptions) => { * This function lets you dynamically import a component. * It uses [React.lazy()](https://react.dev/reference/react/lazy) with [Suspense](https://react.dev/reference/react/Suspense) under the hood. */ -export const dynamic =

( - importFn: Loader, +export const dynamic = ( + importFn: Loader, opts?: DynamicOptions, -): React.ComponentType

=> { - if (typeof opts?.ssr === 'boolean' && !opts?.ssr) { - return noSSR(Loadable, { ...opts, loader: importFn }) +): React.ComponentType => { + if (typeof opts?.ssr === 'boolean' && !opts.ssr) { + return noSSR(Loadable, { ...opts, loader: importFn }) } - return Loadable({ ...opts, loader: importFn }) + return Loadable({ ...opts, loader: importFn }) } From 5e945905896bb655b28a7843c53cfdc8a69fe268 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Wed, 15 Jan 2025 17:18:59 +0100 Subject: [PATCH 09/11] fix: resolve styling comments --- ..._lazy_loading.tsx => RouteLazyLoading.tsx} | 11 ++++------ packages/tuono/src/dynamic/dynamic.tsx | 20 ++++++++----------- packages/tuono/src/index.ts | 2 +- 3 files changed, 13 insertions(+), 20 deletions(-) rename packages/tuono/src/dynamic/{route_lazy_loading.tsx => RouteLazyLoading.tsx} (61%) diff --git a/packages/tuono/src/dynamic/route_lazy_loading.tsx b/packages/tuono/src/dynamic/RouteLazyLoading.tsx similarity index 61% rename from packages/tuono/src/dynamic/route_lazy_loading.tsx rename to packages/tuono/src/dynamic/RouteLazyLoading.tsx index bbe82185..3fb82a60 100644 --- a/packages/tuono/src/dynamic/route_lazy_loading.tsx +++ b/packages/tuono/src/dynamic/RouteLazyLoading.tsx @@ -1,15 +1,13 @@ -import * as React from 'react' +import { lazy, createElement } from 'react' import type { ReactElement } from 'react' import type { RouteComponent } from 'tuono-router' type ImportFn = () => Promise<{ default: RouteComponent }> -export const __tuono__internal__lazyLoadRoute = ( - factory: ImportFn, -): RouteComponent => { +export const RouteLazyLoading = (factory: ImportFn): RouteComponent => { let LoadedComponent: RouteComponent | undefined - const LazyComponent = React.lazy(factory) as unknown as RouteComponent + const LazyComponent = lazy(factory) const loadComponent = (): Promise => factory().then((module) => { @@ -18,8 +16,7 @@ export const __tuono__internal__lazyLoadRoute = ( const Component = ( props: React.ComponentProps, - ): ReactElement => - React.createElement(LoadedComponent || LazyComponent, props) + ): ReactElement => createElement(LoadedComponent || LazyComponent, props) Component.preload = loadComponent diff --git a/packages/tuono/src/dynamic/dynamic.tsx b/packages/tuono/src/dynamic/dynamic.tsx index 438a3069..c7b8ee1f 100644 --- a/packages/tuono/src/dynamic/dynamic.tsx +++ b/packages/tuono/src/dynamic/dynamic.tsx @@ -2,8 +2,8 @@ * This component is heavily inspired by Next.js dynamic function * Link: /~https://github.com/vercel/next.js/blob/1df81bcea62800198884438a2bb27ba14c9d506a/packages/next/src/shared/lib/dynamic.tsx */ -import * as React from 'react' - +import { lazy, Suspense, Fragment } from 'react' +import type { ComponentType } from 'react' const isServerSide = typeof window === 'undefined' interface ComponentModule { @@ -23,9 +23,7 @@ interface LoadableOptions extends DynamicOptions { loader: Loader } -type LoadableFn = ( - options: LoadableOptions, -) => React.ComponentType +type LoadableFn = (options: LoadableOptions) => ComponentType const defaultLoaderOptions: LoadableOptions = { ssr: true, @@ -51,17 +49,15 @@ function noSSR( return NoSSRLoading } -const Loadable = ( - options: LoadableOptions, -): React.ComponentType => { +function Loadable(options: LoadableOptions): ComponentType { const opts = { ...defaultLoaderOptions, ...options } - const Lazy = React.lazy(() => opts.loader().then()) + const Lazy = lazy(() => opts.loader().then()) const Loading = opts.loading function LoadableComponent(props: T): React.JSX.Element { const fallbackElement = Loading ? : null - const Wrap = Loading ? React.Suspense : React.Fragment + const Wrap = Loading ? Suspense : Fragment const wrapProps = Loading ? { fallback: fallbackElement } : {} // TODO: In case ssr = false handle also the assets preloading @@ -80,10 +76,10 @@ const Loadable = ( * This function lets you dynamically import a component. * It uses [React.lazy()](https://react.dev/reference/react/lazy) with [Suspense](https://react.dev/reference/react/Suspense) under the hood. */ -export const dynamic = ( +export function dynamic( importFn: Loader, opts?: DynamicOptions, -): React.ComponentType => { +): ComponentType { if (typeof opts?.ssr === 'boolean' && !opts.ssr) { return noSSR(Loadable, { ...opts, loader: importFn }) } diff --git a/packages/tuono/src/index.ts b/packages/tuono/src/index.ts index fb5b75ad..93525d99 100644 --- a/packages/tuono/src/index.ts +++ b/packages/tuono/src/index.ts @@ -6,7 +6,7 @@ export { useRouter, } from 'tuono-router' -export { __tuono__internal__lazyLoadRoute } from './dynamic/route_lazy_loading' +export { RouteLazyLoading as __tuono__internal__lazyLoadRoute } from './dynamic/RouteLazyLoading' export { dynamic } from './dynamic/dynamic' export type { TuonoProps } from './types' From c66ed54331dcf8b9dd19608a65c9e23aee978692 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Wed, 15 Jan 2025 19:19:27 +0100 Subject: [PATCH 10/11] fix: refine dependencies --- packages/tuono/package.json | 1 - pnpm-lock.yaml | 28 ---------------------------- 2 files changed, 29 deletions(-) diff --git a/packages/tuono/package.json b/packages/tuono/package.json index 64e43a3b..ebb7bc3b 100644 --- a/packages/tuono/package.json +++ b/packages/tuono/package.json @@ -99,7 +99,6 @@ "@vitejs/plugin-react-swc": "^3.7.0", "fast-text-encoding": "^1.0.6", "tuono-fs-router-vite-plugin": "workspace:*", - "tuono-lazy-fn-vite-plugin": "workspace:*", "tuono-router": "workspace:*", "vite": "^5.2.11", "web-streams-polyfill": "^4.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1d19de3..187f817a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -186,9 +186,6 @@ importers: tuono-fs-router-vite-plugin: specifier: workspace:* version: link:../tuono-fs-router-vite-plugin - tuono-lazy-fn-vite-plugin: - specifier: workspace:* - version: link:../tuono-lazy-fn-vite-plugin tuono-router: specifier: workspace:* version: link:../tuono-router @@ -252,31 +249,6 @@ importers: specifier: 2.1.8 version: 2.1.8(@types/node@22.10.6)(jsdom@25.0.1)(sugarss@4.0.1(postcss@8.5.0)) - packages/tuono-lazy-fn-vite-plugin: - dependencies: - '@babel/core': - specifier: ^7.24.4 - version: 7.26.0 - '@babel/types': - specifier: ^7.24.0 - version: 7.26.3 - vite: - specifier: ^5.2.11 - version: 5.4.11(@types/node@22.10.6)(sugarss@4.0.1(postcss@8.5.0)) - devDependencies: - '@tanstack/config': - specifier: 0.7.13 - version: 0.7.13(@types/node@22.10.6)(esbuild@0.21.5)(rollup@4.25.0)(typescript@5.7.3)(vite@5.4.11(@types/node@22.10.6)(sugarss@4.0.1(postcss@8.5.0))) - '@types/babel__core': - specifier: ^7.20.5 - version: 7.20.5 - prettier: - specifier: ^3.2.4 - version: 3.4.2 - vitest: - specifier: 2.1.8 - version: 2.1.8(@types/node@22.10.6)(jsdom@25.0.1)(sugarss@4.0.1(postcss@8.5.0)) - packages/tuono-router: dependencies: react-intersection-observer: From 727d870195c873230b104f6ee42093545049ab01 Mon Sep 17 00:00:00 2001 From: Valerio Ageno Date: Wed, 15 Jan 2025 19:26:43 +0100 Subject: [PATCH 11/11] fix: linting --- packages/tuono/src/dynamic/dynamic.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/tuono/src/dynamic/dynamic.tsx b/packages/tuono/src/dynamic/dynamic.tsx index c7b8ee1f..022f0b49 100644 --- a/packages/tuono/src/dynamic/dynamic.tsx +++ b/packages/tuono/src/dynamic/dynamic.tsx @@ -4,6 +4,7 @@ */ import { lazy, Suspense, Fragment } from 'react' import type { ComponentType } from 'react' + const isServerSide = typeof window === 'undefined' interface ComponentModule {