mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
chore(deps-dev): update eslint to v9 (#147)
This commit is contained in:
committed by
GitHub
parent
5fc68a1926
commit
11d425faa9
@@ -1,106 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"reportUnusedDisableDirectives": true,
|
||||
"ignorePatterns": ["**/build", "**/dist"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint", "import"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@typescript-eslint/stylistic",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript",
|
||||
"prettier",
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2020": true,
|
||||
},
|
||||
"parserOptions": {
|
||||
"tsconfigRootDir": ".",
|
||||
"project": true,
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2020,
|
||||
},
|
||||
"settings": {
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [".ts", ".tsx"],
|
||||
},
|
||||
"import/resolver": {
|
||||
"typescript": true,
|
||||
},
|
||||
"react": {
|
||||
"version": "detect",
|
||||
},
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/no-wrapper-object-types": "error",
|
||||
"@typescript-eslint/no-empty-object-type": "error",
|
||||
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||
"@typescript-eslint/ban-ts-comment": "error",
|
||||
"@typescript-eslint/consistent-type-definitions": "error",
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{ "prefer": "type-imports" },
|
||||
],
|
||||
"@typescript-eslint/explicit-module-boundary-types": "error",
|
||||
"@typescript-eslint/method-signature-style": ["error", "property"],
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"error",
|
||||
{
|
||||
"selector": "typeParameter",
|
||||
"format": ["PascalCase"],
|
||||
"leadingUnderscore": "forbid",
|
||||
"trailingUnderscore": "forbid",
|
||||
"custom": {
|
||||
"regex": "^(T|T[A-Z][A-Za-z]+)$",
|
||||
"match": true,
|
||||
},
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-deprecated": "error",
|
||||
"@typescript-eslint/no-empty-function": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-condition": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": "error",
|
||||
"@typescript-eslint/no-inferrable-types": [
|
||||
"error",
|
||||
{ "ignoreParameters": true },
|
||||
],
|
||||
"import/default": "error",
|
||||
"import/export": "error",
|
||||
"import/namespace": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-cycle": "error",
|
||||
"import/no-duplicates": "off",
|
||||
"import/no-named-as-default-member": "error",
|
||||
"import/no-unused-modules": "error",
|
||||
"import/order": [
|
||||
"off",
|
||||
{
|
||||
"groups": [
|
||||
"builtin",
|
||||
"external",
|
||||
"internal",
|
||||
"parent",
|
||||
"sibling",
|
||||
"index",
|
||||
"object",
|
||||
"type",
|
||||
],
|
||||
},
|
||||
],
|
||||
"no-case-declarations": "error",
|
||||
"no-empty": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-shadow": "error",
|
||||
"no-undef": "off",
|
||||
"sort-imports": "off",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import eslint from '@eslint/js'
|
||||
import tseslint from 'typescript-eslint'
|
||||
// @ts-expect-error no types are available for this plugin
|
||||
import eslintPluginImport from 'eslint-plugin-import'
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
// #region shared
|
||||
'**/build',
|
||||
'**/dist',
|
||||
'**/vite.config.ts.timestamp**',
|
||||
// #endregion shared
|
||||
|
||||
// #region package-specific
|
||||
'packages/fs-router-vite-plugin/tests/generator/**',
|
||||
|
||||
'packages/tuono/bin/**',
|
||||
// #endregion package-specific
|
||||
],
|
||||
},
|
||||
{
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: 'error',
|
||||
},
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
eslintPluginImport.flatConfigs.recommended,
|
||||
eslintPluginImport.flatConfigs.typescript,
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: true,
|
||||
},
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
// #region @typescript-eslint
|
||||
'@typescript-eslint/array-type': 'error',
|
||||
'@typescript-eslint/no-wrapper-object-types': 'error',
|
||||
'@typescript-eslint/no-empty-object-type': 'error',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'error',
|
||||
{ prefer: 'type-imports' },
|
||||
],
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'error',
|
||||
'@typescript-eslint/method-signature-style': ['error', 'property'],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'typeParameter',
|
||||
format: ['PascalCase'],
|
||||
leadingUnderscore: 'forbid',
|
||||
trailingUnderscore: 'forbid',
|
||||
custom: {
|
||||
regex: '^(T|T[A-Z][A-Za-z]+)$',
|
||||
match: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-deprecated': 'error',
|
||||
'@typescript-eslint/no-empty-function': 'error',
|
||||
'@typescript-eslint/no-empty-interface': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': [
|
||||
'error',
|
||||
{ ignoreParameters: true },
|
||||
],
|
||||
// #endregion @typescript-eslint
|
||||
|
||||
// #region import
|
||||
'import/default': 'error',
|
||||
'import/export': 'error',
|
||||
'import/namespace': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-cycle': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-named-as-default-member': 'error',
|
||||
'import/no-unused-modules': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
'newlines-between': 'always-and-inside-groups',
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
'sibling',
|
||||
'index',
|
||||
'object',
|
||||
],
|
||||
},
|
||||
],
|
||||
// #endregion import
|
||||
|
||||
// #region misc
|
||||
/**
|
||||
* @todo some of this might be removed.
|
||||
* They are handled by other plugin and / or typescript
|
||||
*/
|
||||
'no-case-declarations': 'error',
|
||||
'no-empty': 'error',
|
||||
'no-prototype-builtins': 'error',
|
||||
'no-redeclare': 'error',
|
||||
'no-shadow': 'error',
|
||||
'no-undef': 'off',
|
||||
'sort-imports': 'off',
|
||||
},
|
||||
},
|
||||
)
|
||||
+8
-9
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"name": "workspace",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387",
|
||||
"scripts": {
|
||||
"dev": "turbo dev --filter=./packages/*",
|
||||
@@ -21,24 +23,21 @@
|
||||
"author": "Valerio Ageno",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.15.0",
|
||||
"@tanstack/config": "^0.7.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/react": "^18.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint": "^9.15.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"prettier": "^3.2.4",
|
||||
"typescript": "^5.4.5",
|
||||
"turbo": "^2.2.3",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "8.15.0",
|
||||
"vite": "^5.2.11",
|
||||
"vitest": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"turbo": "^2.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"lint": "eslint --ext .ts,.tsx ./src -c ../../.eslintrc",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown '**/*'",
|
||||
"format:check": "prettier --check --ignore-unknown '**/*'",
|
||||
"types": "tsc --noEmit",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { buildRouteConfig } from './build-route-config'
|
||||
|
||||
const routes = [
|
||||
@@ -61,11 +62,11 @@ const routes = [
|
||||
},
|
||||
]
|
||||
|
||||
describe('buildRouteConfig works', async () => {
|
||||
describe('buildRouteConfig works', () => {
|
||||
it('Should build the correct config', () => {
|
||||
const expectedConfig =
|
||||
'PostsMyPostRoute,PostsIndexRoute,PostspostIndexRoute'
|
||||
const config = buildRouteConfig(routes)
|
||||
expect(config).toStrictEqual(expectedConfig)
|
||||
expect(config).toStrictEqual(
|
||||
'PostsMyPostRoute,PostsIndexRoute,PostspostIndexRoute',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import * as fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
import { format } from 'prettier'
|
||||
|
||||
import { buildRouteConfig } from './build-route-config'
|
||||
import { hasParentRoute } from './has-parent-route'
|
||||
|
||||
import {
|
||||
cleanPath,
|
||||
determineNodePath,
|
||||
@@ -19,7 +21,6 @@ import {
|
||||
import type { Config, RouteNode } from './types'
|
||||
import { ROUTES_FOLDER, ROOT_PATH_ID, GENERATED_ROUTE_TREE } from './constants'
|
||||
|
||||
import { format } from 'prettier'
|
||||
import { sortRouteNodes } from './sort-route-nodes'
|
||||
import isDefaultExported from './utils/is-default-exported'
|
||||
|
||||
@@ -130,7 +131,7 @@ export async function routeGenerator(config = defaultConfig): Promise<void> {
|
||||
|
||||
// Loop over the flat list of routeNodes and
|
||||
// build up a tree based on the routeNodes' routePath
|
||||
const handleNode = async (node: RouteNode): Promise<void> => {
|
||||
const handleNode = (node: RouteNode): void => {
|
||||
const parentRoute = hasParentRoute(routeNodes, node, node.routePath)
|
||||
|
||||
if (parentRoute) node.parent = parentRoute
|
||||
@@ -149,7 +150,7 @@ export async function routeGenerator(config = defaultConfig): Promise<void> {
|
||||
}
|
||||
|
||||
for (const node of preRouteNodes) {
|
||||
await handleNode(node)
|
||||
handleNode(node)
|
||||
}
|
||||
|
||||
const routeConfigChildrenText = buildRouteConfig(routeNodes)
|
||||
@@ -237,7 +238,8 @@ export async function routeGenerator(config = defaultConfig): Promise<void> {
|
||||
|
||||
const routeTreeContent = await fsp
|
||||
.readFile(path.resolve(config.generatedRouteTree), 'utf-8')
|
||||
.catch((err: any) => {
|
||||
.catch((e) => {
|
||||
const err = e as Error & { code?: string }
|
||||
if (err.code === 'ENOENT') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { hasParentRoute } from './has-parent-route'
|
||||
|
||||
const routes = [
|
||||
@@ -70,7 +71,7 @@ const dynamicRoute = {
|
||||
cleanedPath: '/posts/[post]',
|
||||
}
|
||||
|
||||
describe('hasParentRoute works', async () => {
|
||||
describe('hasParentRoute works', () => {
|
||||
it('Should detect parent route', () => {
|
||||
const parentRoute = hasParentRoute(routes, myPost, myPost.path)
|
||||
expect(parentRoute).toStrictEqual(parent)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { routeGenerator } from './generator'
|
||||
|
||||
import { normalize } from 'path'
|
||||
|
||||
import type { Plugin } from 'vite'
|
||||
|
||||
import { routeGenerator } from './generator'
|
||||
|
||||
const ROUTES_DIRECTORY_PATH = './src/routes'
|
||||
|
||||
let lock = false
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { sortRouteNodes } from './sort-route-nodes'
|
||||
|
||||
const routes = [
|
||||
@@ -106,7 +107,7 @@ const expectedSorting = [
|
||||
},
|
||||
]
|
||||
|
||||
describe('sortRouteNodes works', async () => {
|
||||
describe('sortRouteNodes works', () => {
|
||||
it('Should correctly sort the nodes', () => {
|
||||
const sorted = sortRouteNodes(routes)
|
||||
expect(sorted).toStrictEqual(expectedSorting)
|
||||
|
||||
@@ -35,7 +35,7 @@ export function routePathToVariable(routePath: string): string {
|
||||
|
||||
export function multiSortBy<T>(
|
||||
arr: T[],
|
||||
accessors: ((item: T) => any)[] = [(d): any => d],
|
||||
accessors: ((item: T) => unknown)[] = [(d): unknown => d],
|
||||
): T[] {
|
||||
return arr
|
||||
.map((d, i) => [d, i] as const)
|
||||
@@ -55,7 +55,7 @@ export function multiSortBy<T>(
|
||||
continue
|
||||
}
|
||||
|
||||
return ao > bo ? 1 : -1
|
||||
return (ao as number) > (bo as number) ? 1 : -1
|
||||
}
|
||||
|
||||
return ai - bi
|
||||
@@ -81,8 +81,8 @@ export function removeTrailingUnderscores(s?: string): string | undefined {
|
||||
/**
|
||||
* Removes all segments from a given path that start with an underscore ('_').
|
||||
*
|
||||
* @param {string} routePath - The path from which to remove segments. Defaults to '/'.
|
||||
* @returns {string} The path with all underscore-prefixed segments removed.
|
||||
* @param routePath - The path from which to remove segments. Defaults to '/'.
|
||||
* @returns The path with all underscore-prefixed segments removed.
|
||||
* @example
|
||||
* removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'
|
||||
*/
|
||||
@@ -101,8 +101,9 @@ export function trimPathLeft(pathToTrim: string): string {
|
||||
}
|
||||
|
||||
export function removeLastSlash(str: string): string {
|
||||
if (str.length > 1 && str.endsWith('/'))
|
||||
if (str.length > 1 && str.endsWith('/')) {
|
||||
return str.substring(0, str.length - 1)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { routeGenerator } from '../src/generator'
|
||||
|
||||
describe('generator works', async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src", "vite.config.ts"]
|
||||
"include": ["src", "tests", "vite.config.ts"],
|
||||
"exclude": ["tests/generator/**"]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"lint": "eslint --ext .ts,.tsx ./src -c ../../.eslintrc",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown '**/*'",
|
||||
"format:check": "prettier --check --ignore-unknown '**/*'",
|
||||
"types": "tsc --noEmit",
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import type { Plugin } from 'vite'
|
||||
import * as babel from '@babel/core'
|
||||
import type { PluginItem } from '@babel/core'
|
||||
import { isTuonoDynamicFnImported } from './utils'
|
||||
|
||||
import {
|
||||
TUONO_MAIN_PACKAGE,
|
||||
TUONO_DYNAMIC_FN_ID,
|
||||
TUONO_LAZY_FN_ID,
|
||||
} from './constants'
|
||||
|
||||
import * as t from '@babel/types'
|
||||
|
||||
import type { Plugin } from 'vite'
|
||||
import type { PluginItem } from '@babel/core'
|
||||
import type {
|
||||
Identifier,
|
||||
CallExpression,
|
||||
@@ -18,6 +9,13 @@ import type {
|
||||
StringLiteral,
|
||||
} from '@babel/types'
|
||||
|
||||
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
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { TUONO_MAIN_PACKAGE, TUONO_DYNAMIC_FN_ID } from './constants'
|
||||
import type * as t from '@babel/types'
|
||||
import type {
|
||||
Identifier,
|
||||
ImportDeclaration,
|
||||
ImportSpecifier,
|
||||
} from '@babel/types'
|
||||
|
||||
import type { Identifier, ImportDeclaration } from '@babel/types'
|
||||
import { TUONO_MAIN_PACKAGE, TUONO_DYNAMIC_FN_ID } from './constants'
|
||||
|
||||
export const isTuonoDynamicFnImported = (
|
||||
path: babel.NodePath<t.ImportSpecifier>,
|
||||
path: babel.NodePath<ImportSpecifier>,
|
||||
): boolean => {
|
||||
if ((path.node.imported as Identifier).name !== TUONO_DYNAMIC_FN_ID) {
|
||||
return false
|
||||
|
||||
+21
-4
@@ -1,4 +1,6 @@
|
||||
import { it, expect, describe } from 'vitest'
|
||||
import type { Plugin } from 'vite'
|
||||
|
||||
import { LazyLoadingPlugin } from '../src'
|
||||
|
||||
const SOURCE_CODE = `
|
||||
@@ -20,9 +22,21 @@ const PokemonspokemonImport = dynamic(
|
||||
)
|
||||
`
|
||||
|
||||
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<ViteTransformHandler>) => string {
|
||||
return LazyLoadingPlugin().transform as never
|
||||
}
|
||||
|
||||
describe('Transpile tuono source', () => {
|
||||
it('Into the client bundle', () => {
|
||||
const bundle = LazyLoadingPlugin().transform?.(SOURCE_CODE, 'id')
|
||||
const pluginTransform = getTransform()
|
||||
const bundle = pluginTransform(SOURCE_CODE, 'id')
|
||||
expect(bundle)
|
||||
.toBe(`import { createRoute, lazyLoadComponent as dynamic } from 'tuono';
|
||||
const IndexImport = dynamic(() => import('./../src/routes/index'));
|
||||
@@ -30,7 +44,8 @@ const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[po
|
||||
})
|
||||
|
||||
it('Into the server bundle', () => {
|
||||
const bundle = LazyLoadingPlugin().transform?.(SOURCE_CODE, 'id', {
|
||||
const pluginTransform = getTransform()
|
||||
const bundle = pluginTransform(SOURCE_CODE, 'id', {
|
||||
ssr: true,
|
||||
})
|
||||
expect(bundle).toBe(`import { createRoute } from 'tuono';
|
||||
@@ -41,7 +56,8 @@ import PokemonspokemonImport from "./../src/routes/pokemons/[pokemon]";`)
|
||||
|
||||
describe('Non tuono dynamic function', () => {
|
||||
it('Into the client bundle', () => {
|
||||
const bundle = LazyLoadingPlugin().transform?.(NON_DYNAMIC_SOURCE, 'id')
|
||||
const pluginTransform = getTransform()
|
||||
const bundle = pluginTransform(NON_DYNAMIC_SOURCE, 'id')
|
||||
expect(bundle).toBe(`import { createRoute } from 'tuono';
|
||||
import { dynamic } from 'external-lib';
|
||||
const IndexImport = dynamic(() => import('./../src/routes/index'));
|
||||
@@ -49,7 +65,8 @@ const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[po
|
||||
})
|
||||
|
||||
it('Into the server bundle', () => {
|
||||
const bundle = LazyLoadingPlugin().transform?.(NON_DYNAMIC_SOURCE, 'id', {
|
||||
const pluginTransform = getTransform()
|
||||
const bundle = pluginTransform(NON_DYNAMIC_SOURCE, 'id', {
|
||||
ssr: true,
|
||||
})
|
||||
expect(bundle).toBe(`import { createRoute } from 'tuono';
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src", "vite.config.ts"]
|
||||
"include": ["src", "tests", "vite.config.ts"]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"lint": "eslint --ext .ts,.tsx ./src -c ../../.eslintrc",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown '**/*'",
|
||||
"format:check": "prettier --check --ignore-unknown '**/*'",
|
||||
"types": "tsc --noEmit",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import * as React from 'react'
|
||||
import { useRouter } from '../hooks/useRouter'
|
||||
import type { AnchorHTMLAttributes, MouseEvent } from 'react'
|
||||
import useRoute from '../hooks/useRoute'
|
||||
import type { AnchorHTMLAttributes } from 'react'
|
||||
import { useInView } from 'react-intersection-observer'
|
||||
|
||||
import { useRouter } from '../hooks/useRouter'
|
||||
import useRoute from '../hooks/useRoute'
|
||||
|
||||
interface TuonoLinkProps {
|
||||
/**
|
||||
* If "true" the route gets loaded when the link enters the viewport. Default "true"
|
||||
@@ -28,7 +29,7 @@ export default function Link(
|
||||
triggerOnce: true,
|
||||
})
|
||||
|
||||
const handleTransition = (e: MouseEvent<HTMLAnchorElement>): void => {
|
||||
const handleTransition: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||
e.preventDefault()
|
||||
props.onClick?.(e)
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { useRouterStore } from '../hooks/useRouterStore'
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
import NotFound from './NotFound'
|
||||
import useRoute from '../hooks/useRoute'
|
||||
|
||||
interface MatchesProps {
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
import NotFound from './NotFound'
|
||||
|
||||
interface MatchesProps<TServerSideProps = unknown> {
|
||||
// user defined props
|
||||
serverSideProps: any
|
||||
serverSideProps: TServerSideProps
|
||||
}
|
||||
|
||||
export function Matches({ serverSideProps }: MatchesProps): React.JSX.Element {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { useInternalRouter } from '../hooks/useInternalRouter'
|
||||
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
import Link from './Link'
|
||||
import { useInternalRouter } from '../hooks/useInternalRouter'
|
||||
|
||||
export default function NotFound(): React.JSX.Element {
|
||||
const router = useInternalRouter()
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import * as React from 'react'
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest'
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
|
||||
import type { Route } from '../route'
|
||||
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
import '@testing-library/jest-dom'
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import type { Route } from '../route'
|
||||
import { useServerSideProps } from '../hooks/useServerSideProps'
|
||||
|
||||
interface MatchProps {
|
||||
interface RouteMatchProps<TServerSideProps = unknown> {
|
||||
route: Route
|
||||
// User defined server side props
|
||||
serverSideProps: any
|
||||
serverSideProps: TServerSideProps
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,7 +17,7 @@ interface MatchProps {
|
||||
export const RouteMatch = ({
|
||||
route,
|
||||
serverSideProps,
|
||||
}: MatchProps): React.JSX.Element => {
|
||||
}: RouteMatchProps): React.JSX.Element => {
|
||||
const { data, isLoading } = useServerSideProps(route, serverSideProps)
|
||||
|
||||
const routes = React.useMemo(() => loadParentComponents(route), [route.id])
|
||||
@@ -28,20 +29,20 @@ export const RouteMatch = ({
|
||||
)
|
||||
}
|
||||
|
||||
interface TraverseRootComponentsProps {
|
||||
interface ParentProps<TData = unknown> {
|
||||
children: React.ReactNode
|
||||
data: TData
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
interface TraverseRootComponentsProps<TData = unknown> {
|
||||
routes: Route[]
|
||||
data: any
|
||||
data: TData
|
||||
isLoading: boolean
|
||||
children?: React.ReactNode
|
||||
index?: number
|
||||
}
|
||||
|
||||
interface ParentProps {
|
||||
children: React.ReactNode
|
||||
data: any
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
/*
|
||||
* This component traverses and renders
|
||||
* all the components that wraps the selected route (__root).
|
||||
@@ -84,7 +85,7 @@ const TraverseRootComponents = React.memo(
|
||||
)
|
||||
|
||||
const loadParentComponents = (route: Route, loader: Route[] = []): Route[] => {
|
||||
const parentComponent = route.options?.getParentRoute?.()
|
||||
const parentComponent = route.options.getParentRoute?.() as Route
|
||||
|
||||
loader.push(parentComponent)
|
||||
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import * as React from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import type { Router } from '../router'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const routerContext = React.createContext<Router>(null!)
|
||||
|
||||
const TUONO_CONTEXT = '__TUONO_CONTEXT__'
|
||||
const TUONO_CONTEXT_GLOBAL_NAME = '__TUONO_CONTEXT__'
|
||||
|
||||
export function getRouterContext(): any {
|
||||
export function getRouterContext(): React.Context<Router> {
|
||||
if (typeof document === 'undefined') {
|
||||
return routerContext
|
||||
}
|
||||
|
||||
if (window[TUONO_CONTEXT as any]) {
|
||||
return window[TUONO_CONTEXT as any]
|
||||
if (window[TUONO_CONTEXT_GLOBAL_NAME]) {
|
||||
return window[TUONO_CONTEXT_GLOBAL_NAME]
|
||||
}
|
||||
|
||||
window[TUONO_CONTEXT as any] = routerContext as any
|
||||
window[TUONO_CONTEXT_GLOBAL_NAME] = routerContext
|
||||
|
||||
return routerContext
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
import React from 'react'
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
|
||||
import { useListenBrowserUrlUpdates } from '../hooks/useListenBrowserUrlUpdates'
|
||||
import { initRouterStore } from '../hooks/useRouterStore'
|
||||
import type { ServerProps } from '../types'
|
||||
import type { Router } from '../router'
|
||||
|
||||
import { getRouterContext } from './RouterContext'
|
||||
import { Matches } from './Matches'
|
||||
|
||||
type Router = any
|
||||
|
||||
interface RouterContextProviderProps {
|
||||
router: Router
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
interface RouterProviderProps {
|
||||
router: Router
|
||||
serverProps?: ServerProps
|
||||
}
|
||||
|
||||
function RouterContextProvider({
|
||||
router,
|
||||
children,
|
||||
@@ -27,7 +23,11 @@ function RouterContextProvider({
|
||||
router.update({
|
||||
...router.options,
|
||||
...rest,
|
||||
// @ts-expect-error router options do not have context as property and I was unable to find any usage of it,
|
||||
// so is this spread required?
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
context: {
|
||||
// @ts-expect-error see previous
|
||||
...router.options.context,
|
||||
},
|
||||
})
|
||||
@@ -41,6 +41,11 @@ function RouterContextProvider({
|
||||
)
|
||||
}
|
||||
|
||||
interface RouterProviderProps {
|
||||
router: Router
|
||||
serverProps?: ServerProps
|
||||
}
|
||||
|
||||
export function RouterProvider({
|
||||
router,
|
||||
serverProps,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react'
|
||||
import type { ReactElement, ComponentType } from 'react'
|
||||
|
||||
import type { RouteComponent } from './types'
|
||||
|
||||
type ImportFn = () => Promise<{ default: React.ComponentType<any> }>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import type React from 'react'
|
||||
|
||||
import type { Router } from './router'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__TUONO__ROUTER__: Router
|
||||
__TUONO_SSR_PROPS__?: {
|
||||
props?: unknown
|
||||
}
|
||||
|
||||
__TUONO_CONTEXT__?: React.Context<Router>
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { getRouterContext } from '../components/RouterContext'
|
||||
import type { Router } from '../router'
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useRouterStore } from './useRouterStore'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useRouterStore } from './useRouterStore'
|
||||
|
||||
/**
|
||||
* This hook is meant to handle just browser related location updates
|
||||
* like the back and forward buttons.
|
||||
@@ -8,8 +9,9 @@ import { useEffect } from 'react'
|
||||
export const useListenBrowserUrlUpdates = (): void => {
|
||||
const updateLocation = useRouterStore((st) => st.updateLocation)
|
||||
|
||||
const updateLocationOnPopStateChange = ({ target }: any): void => {
|
||||
const { pathname, hash, href, search } = target.location
|
||||
const updateLocationOnPopStateChange = ({ target }: PopStateEvent): void => {
|
||||
const { pathname, hash, href, search } = (target as typeof window).location
|
||||
|
||||
updateLocation({
|
||||
pathname,
|
||||
hash,
|
||||
@@ -18,8 +20,10 @@ export const useListenBrowserUrlUpdates = (): void => {
|
||||
search: Object.fromEntries(new URLSearchParams(search)),
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('popstate', updateLocationOnPopStateChange)
|
||||
|
||||
return (): void => {
|
||||
window.removeEventListener('popstate', updateLocationOnPopStateChange)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest'
|
||||
import useRoute from './useRoute'
|
||||
import { cleanup } from '@testing-library/react'
|
||||
|
||||
import useRoute from './useRoute'
|
||||
|
||||
describe('Test useRoute fn', () => {
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
})
|
||||
afterEach(cleanup)
|
||||
|
||||
test('match routes by ids', () => {
|
||||
vi.mock('./useInternalRouter.tsx', () => ({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Route } from '../route'
|
||||
|
||||
import { useInternalRouter } from './useInternalRouter'
|
||||
|
||||
const DYNAMIC_PATH_REGEX = /\[(.*?)\]/
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
|
||||
import type { Route } from '../route'
|
||||
import { useRouterStore } from './useRouterStore'
|
||||
import { fromUrlToParsedLocation } from '../utils/from-url-to-parsed-location'
|
||||
|
||||
import { useRouterStore } from './useRouterStore'
|
||||
|
||||
const isServer = typeof document === 'undefined'
|
||||
|
||||
interface UseServerSidePropsReturn {
|
||||
data: any
|
||||
interface UseServerSidePropsReturn<TData> {
|
||||
data: TData
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__TUONO_SSR_PROPS__: any
|
||||
}
|
||||
}
|
||||
|
||||
interface TuonoApi {
|
||||
data?: any
|
||||
info: {
|
||||
@@ -26,7 +22,7 @@ interface TuonoApi {
|
||||
const fetchClientSideData = async (): Promise<TuonoApi> => {
|
||||
const slash = location.pathname.endsWith('/') ? '' : '/'
|
||||
const res = await fetch(`/__tuono/data${location.pathname}${slash}data.json`)
|
||||
const data: TuonoApi = await res.json()
|
||||
const data = (await res.json()) as TuonoApi
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -40,7 +36,7 @@ export function useServerSideProps<T>(
|
||||
route: Route,
|
||||
// User defined props
|
||||
serverSideProps: T,
|
||||
): UseServerSidePropsReturn {
|
||||
): UseServerSidePropsReturn<T> {
|
||||
const isFirstRendering = useRef<boolean>(true)
|
||||
const [location, updateLocation] = useRouterStore((st) => [
|
||||
st.location,
|
||||
@@ -48,15 +44,15 @@ export function useServerSideProps<T>(
|
||||
])
|
||||
const [isLoading, setIsLoading] = useState<boolean>(
|
||||
// Force loading if has handler
|
||||
route.options.hasHandler &&
|
||||
!!route.options.hasHandler &&
|
||||
// Avoid loading on the server
|
||||
!isServer &&
|
||||
// Avoid loading if first rendering
|
||||
!isFirstRendering.current,
|
||||
)
|
||||
|
||||
const [data, setData] = useState<any>(
|
||||
serverSideProps ?? window.__TUONO_SSR_PROPS__?.props,
|
||||
const [data, setData] = useState<T | undefined>(
|
||||
(serverSideProps ?? window.__TUONO_SSR_PROPS__?.props) as T,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -68,6 +64,8 @@ export function useServerSideProps<T>(
|
||||
}
|
||||
// After client side routing load again the remote data
|
||||
if (route.options.hasHandler) {
|
||||
// The error management is already handled inside the IIFE
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
;(async (): Promise<void> => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
@@ -86,7 +84,7 @@ export function useServerSideProps<T>(
|
||||
updateLocation(parsedLocation)
|
||||
return
|
||||
}
|
||||
setData(response.data)
|
||||
setData(response.data as T)
|
||||
} catch (error) {
|
||||
throw Error('Failed loading Server Side Data', { cause: error })
|
||||
} finally {
|
||||
@@ -101,5 +99,5 @@ export function useServerSideProps<T>(
|
||||
}
|
||||
}, [location.pathname])
|
||||
|
||||
return { isLoading, data }
|
||||
return { isLoading, data: data as T }
|
||||
}
|
||||
|
||||
@@ -3,35 +3,41 @@ import type { RouteComponent } from './types'
|
||||
import { trimPathLeft, joinPaths } from './utils'
|
||||
|
||||
interface RouteOptions {
|
||||
id?: string
|
||||
isRoot?: boolean
|
||||
getParentRoute?: () => Route
|
||||
path?: string
|
||||
component: RouteComponent
|
||||
hasHandler?: boolean
|
||||
}
|
||||
|
||||
export function createRoute(options: RouteOptions): Route {
|
||||
return new Route(options)
|
||||
}
|
||||
|
||||
export const rootRouteId = '__root__'
|
||||
const rootRouteId = '__root__'
|
||||
|
||||
export class Route {
|
||||
parentRoute!: any
|
||||
options: RouteOptions
|
||||
|
||||
id?: string
|
||||
fullPath!: string
|
||||
isRoot: boolean
|
||||
path?: string
|
||||
options: any
|
||||
fullPath!: string
|
||||
|
||||
children?: Route[]
|
||||
parentRoute!: any
|
||||
/** @todo check if this is required */
|
||||
router: RouterType
|
||||
isRoot: boolean
|
||||
originalIndex?: number
|
||||
component: RouteComponent
|
||||
|
||||
'$$typeof': symbol
|
||||
|
||||
constructor(options: RouteOptions) {
|
||||
this.isRoot = options.isRoot ?? typeof options.getParentRoute !== 'function'
|
||||
this.options = options
|
||||
;(this as any).$$typeof = Symbol.for('react.memo')
|
||||
this.$$typeof = Symbol.for('react.memo')
|
||||
|
||||
this.component = options.component
|
||||
}
|
||||
@@ -39,9 +45,9 @@ export class Route {
|
||||
init = (originalIndex: number): void => {
|
||||
this.originalIndex = originalIndex
|
||||
|
||||
const isRoot = !this.options?.path && !this.options?.id
|
||||
const isRoot = !this.options.path && !this.options.id
|
||||
|
||||
this.parentRoute = this.options?.getParentRoute?.()
|
||||
this.parentRoute = this.options.getParentRoute?.()
|
||||
|
||||
if (isRoot) {
|
||||
this.path = rootRouteId
|
||||
@@ -54,7 +60,7 @@ export class Route {
|
||||
path = trimPathLeft(path)
|
||||
}
|
||||
|
||||
const customId = this.options?.id || path
|
||||
const customId = this.options.id || path
|
||||
|
||||
// Strip the parentId prefix from the first level of children
|
||||
let id = isRoot ? rootRouteId : joinPaths([customId])
|
||||
|
||||
@@ -3,15 +3,15 @@ import type { ComponentType as ReactComponentType } from 'react'
|
||||
import { trimPath, trimPathRight } from './utils'
|
||||
import type { Route } from './route'
|
||||
|
||||
type RouteTree = any
|
||||
type RouteTree = Route
|
||||
|
||||
interface CreateRouter {
|
||||
interface CreateRouterOptions {
|
||||
routeTree: RouteTree
|
||||
basePath?: string
|
||||
options?: RouteOptions
|
||||
options?: RouterOptions
|
||||
}
|
||||
|
||||
interface RouteOptions {
|
||||
interface RouterOptions {
|
||||
component?: ReactComponentType
|
||||
hasHandler?: boolean
|
||||
routeTree?: RouteTree
|
||||
@@ -19,32 +19,39 @@ interface RouteOptions {
|
||||
|
||||
export type RouterType = any
|
||||
|
||||
export function createRouter(options: CreateRouter): Router {
|
||||
export function createRouter(options: CreateRouterOptions): Router {
|
||||
return new Router(options)
|
||||
}
|
||||
|
||||
export class Router {
|
||||
options?: RouteOptions
|
||||
options?: RouterOptions
|
||||
basePath = '/'
|
||||
routeTree: any
|
||||
routeTree?: RouteTree
|
||||
|
||||
/** Not used */
|
||||
history: any
|
||||
|
||||
isServer = typeof document === 'undefined'
|
||||
|
||||
routesById: Record<string, Route> = {}
|
||||
// Not used
|
||||
|
||||
/** Not used */
|
||||
routesByPath: Record<string, Route> = {}
|
||||
|
||||
/** Not used */
|
||||
flatRoutes: any
|
||||
|
||||
constructor(options: CreateRouter) {
|
||||
constructor(options: CreateRouterOptions) {
|
||||
this.update({
|
||||
...options,
|
||||
})
|
||||
|
||||
if (!this.isServer) {
|
||||
;(window as any).__TSR__ROUTER__ = this
|
||||
window.__TUONO__ROUTER__ = this
|
||||
}
|
||||
}
|
||||
|
||||
update = (newOptions: CreateRouter): void => {
|
||||
update = (newOptions: CreateRouterOptions): void => {
|
||||
this.options = {
|
||||
...this.options,
|
||||
...newOptions,
|
||||
@@ -82,7 +89,7 @@ export class Router {
|
||||
})
|
||||
}
|
||||
|
||||
recurseRoutes([this.routeTree])
|
||||
recurseRoutes([this.routeTree as Route])
|
||||
}
|
||||
|
||||
#updateBasePath = (basePath?: string): void => {
|
||||
|
||||
@@ -5,17 +5,17 @@ export interface Segment {
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface ServerProps {
|
||||
export interface ServerProps<TProps = unknown> {
|
||||
router: {
|
||||
href: string
|
||||
pathname: string
|
||||
searchStr: string
|
||||
}
|
||||
props: any
|
||||
props: TProps
|
||||
}
|
||||
|
||||
export interface RouteProps {
|
||||
data: any
|
||||
export interface RouteProps<TData = unknown> {
|
||||
data: TData
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"lint": "eslint --ext .ts,.tsx ./src -c ../../.eslintrc",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown '**/*'",
|
||||
"format:check": "prettier --check --ignore-unknown '**/*'",
|
||||
"types": "tsc --noEmit",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react'
|
||||
import { hydrateRoot } from 'react-dom/client'
|
||||
import { RouterProvider, createRouter } from 'tuono-router'
|
||||
import type { createRoute } from 'tuono-router'
|
||||
import { HelmetProvider } from 'react-helmet-async'
|
||||
|
||||
type RouteTree = any
|
||||
type RouteTree = ReturnType<typeof createRoute>
|
||||
|
||||
export function hydrate(routeTree: RouteTree): void {
|
||||
// Create a new router instance
|
||||
|
||||
@@ -4,8 +4,9 @@ import { renderToString, renderToStaticMarkup } from 'react-dom/server'
|
||||
import type { HelmetServerState } from 'react-helmet-async'
|
||||
import { HelmetProvider } from 'react-helmet-async'
|
||||
import { RouterProvider, createRouter } from 'tuono-router'
|
||||
import type { createRoute } from 'tuono-router'
|
||||
|
||||
type RouteTree = any
|
||||
type RouteTree = ReturnType<typeof createRoute>
|
||||
type Mode = 'Dev' | 'Prod'
|
||||
|
||||
const TUONO_DEV_SERVER_PORT = 3000
|
||||
@@ -37,17 +38,20 @@ function generateJsScripts(jsBundles: string[], mode: Mode): string {
|
||||
|
||||
export function serverSideRendering(routeTree: RouteTree) {
|
||||
return function render(payload: string | undefined): string {
|
||||
const props = payload ? JSON.parse(payload) : {}
|
||||
const serverProps = (payload ? JSON.parse(payload) : {}) as Record<
|
||||
string,
|
||||
unknown
|
||||
>
|
||||
|
||||
const mode = props.mode as Mode
|
||||
const jsBundles = props.jsBundles as string[]
|
||||
const cssBundles = props.cssBundles as string[]
|
||||
const mode = serverProps.mode as Mode
|
||||
const jsBundles = serverProps.jsBundles as string[]
|
||||
const cssBundles = serverProps.cssBundles as string[]
|
||||
const router = createRouter({ routeTree }) // Render the app
|
||||
|
||||
const helmetContext = {}
|
||||
const app = renderToString(
|
||||
<HelmetProvider context={helmetContext}>
|
||||
<RouterProvider router={router} serverProps={props} />
|
||||
<RouterProvider router={router} serverProps={serverProps as never} />
|
||||
</HelmetProvider>,
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,5 @@
|
||||
"compilerOptions": {
|
||||
"jsx": "react"
|
||||
},
|
||||
"include": ["src", "tests", "vite.config.ts"],
|
||||
"exclude": ["vite.config.ts"]
|
||||
"include": ["src", "tests", "vite.config.ts"]
|
||||
}
|
||||
|
||||
Generated
+284
-236
File diff suppressed because it is too large
Load Diff
+29
-18
@@ -1,28 +1,39 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
// Typechecking
|
||||
"strict": true,
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"checkJs": true,
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "Bundler",
|
||||
"noEmit": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
// Modules
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "ES2020"
|
||||
},
|
||||
"include": [".eslintrc.cjs", "prettier.config.js"],
|
||||
"exclude": ["node_modules"]
|
||||
|
||||
// Emit
|
||||
"noEmit": true,
|
||||
"declaration": true,
|
||||
|
||||
// JavaScript Support
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
|
||||
// Interop Constraints
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
// Language and Environment
|
||||
"target": "ES2020",
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
|
||||
// Completeness
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"globalDependencies": ["eslint.config.js"],
|
||||
"tasks": {
|
||||
"lint": {
|
||||
"dependsOn": ["^build"]
|
||||
|
||||
Reference in New Issue
Block a user