Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90da869277 | |||
| 80c4affaa8 | |||
| aa087193fe | |||
| af7e51f69b | |||
| 1b62d8ddc2 | |||
| 0839579733 | |||
| 7f9bf08f76 | |||
| 79ec1c6922 | |||
| c68246df83 | |||
| abc0ad7120 | |||
| 4356ca1cff | |||
| d6215d009c | |||
| 0b501e95a5 | |||
| f157ff37e0 | |||
| 11d425faa9 | |||
| 5fc68a1926 | |||
| ec4577c187 | |||
| 8052de8ad5 | |||
| 2fda959cd6 | |||
| 05fa8a5ae2 | |||
| a341b41e9a | |||
| a2e0a4d78a | |||
| 4fb1d6077c |
@@ -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",
|
||||
},
|
||||
}
|
||||
@@ -3,13 +3,21 @@ name: Documentation Website CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'main'
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `typescript.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `typescript.yml`
|
||||
- 'apps/documentation/**'
|
||||
pull_request:
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `typescript.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `typescript.yml`
|
||||
- 'apps/documentation/**'
|
||||
|
||||
jobs:
|
||||
@@ -29,7 +37,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Install tuono
|
||||
run: cargo install tuono@0.12.3
|
||||
run: cargo install tuono@0.15.0
|
||||
|
||||
- name: Build project
|
||||
working-directory: ./apps/documentation
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Deploy documentation website on AWS S3
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'main'
|
||||
paths:
|
||||
- '.github/**'
|
||||
- 'apps/documentation/**'
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Install tuono
|
||||
run: cargo install tuono@0.12.3
|
||||
run: cargo install tuono@0.15.0
|
||||
|
||||
- name: Build project
|
||||
working-directory: ./apps/documentation
|
||||
|
||||
@@ -34,10 +34,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
- name: Setup rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
toolchain: 'stable'
|
||||
|
||||
- uses: katyo/publish-crates@v2
|
||||
with:
|
||||
@@ -80,10 +80,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
- name: Setup rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
toolchain: 'stable'
|
||||
|
||||
- uses: katyo/publish-crates@v2
|
||||
with:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
name: Repo root CI
|
||||
|
||||
# All workflows are triggered based on specific paths,
|
||||
# the root repository is something that is not applicable to rust nor typescript
|
||||
# so it has been moved in a standalone workflow
|
||||
@@ -6,14 +7,14 @@ name: Repo root CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'main'
|
||||
paths:
|
||||
- '.github/**'
|
||||
- './*'
|
||||
- '*'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/**'
|
||||
- './*'
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
|
||||
@@ -3,13 +3,15 @@ name: Rust CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'main'
|
||||
paths:
|
||||
- '.github/**'
|
||||
- 'Cargo.toml'
|
||||
- 'crates/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/**'
|
||||
- 'Cargo.toml'
|
||||
- 'crates/**'
|
||||
|
||||
env:
|
||||
@@ -43,7 +45,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
|
||||
- name: Setup rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
|
||||
- run: cargo build --verbose
|
||||
- run: cargo test --verbose
|
||||
|
||||
@@ -55,5 +61,8 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- run: cargo fmt --all -- --check
|
||||
- run: cargo clippy -- -D warnings
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Spell Checker
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'main'
|
||||
|
||||
pull_request:
|
||||
|
||||
|
||||
@@ -3,13 +3,21 @@ name: Typescript CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'main'
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `ci-documentation.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `ci-documentation.yml`
|
||||
- 'packages/**'
|
||||
pull_request:
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `ci-documentation.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `ci-documentation.yml`
|
||||
- 'packages/**'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -24,3 +24,6 @@ examples/*/pnpm-lock.yaml
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# Files, generated by the code editors
|
||||
.vscode/
|
||||
@@ -1,5 +1,5 @@
|
||||

|
||||

|
||||

|
||||

|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
# How to Contribute to Tuono
|
||||
@@ -7,15 +7,19 @@
|
||||
## Contributions
|
||||
|
||||
Any feature contribution or suggestion is strongly appreciated.
|
||||
Since the current project size, there isn't yet a defined way to start a discussion. Consider [opening a new issue](https://github.com/Valerioageno/tuono/issues/new/choose)
|
||||
or to reach me using my email address, [valerioageno@yahoo.it](mailto:valerioageno@ahoo.it). I'm also available on Twitter (X); DM @valerioageno.
|
||||
|
||||
We are currently managing the tasks' prioritization in the [Road to V1](https://github.com/orgs/tuono-labs/projects/2) project. You can pick any task that you see in the `ready` column that is not already assigned.
|
||||
|
||||
If you want to contribute on something that is in the `backlog` column, or it hasn't been scoped yet, please drop a message in the [#general](https://discord.com/invite/khQzPa654B) discord channel so we can all have visibility of it.
|
||||
|
||||
Consider [opening a new issue](https://github.com/tuono-labs/tuono/issues/new/choose) if you find a bug.
|
||||
|
||||
## Bugs
|
||||
|
||||
**Did you find a bug?**
|
||||
|
||||
- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/Valerioageno/tuono/issues).
|
||||
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/Valerioageno/tuono/issues/new/choose). Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
|
||||
- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/tuono-labs/tuono/issues).
|
||||
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/tuono-labs/tuono/issues/new/choose). Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
|
||||
|
||||
**Did you write a patch that fixes a bug?**
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ members = [
|
||||
]
|
||||
exclude = [
|
||||
"apps/documentation",
|
||||
"examples/wit-mdx",
|
||||
"examples/with-mdx",
|
||||
"examples/tuono-app",
|
||||
"examples/tuono-tutorial",
|
||||
"benches/tuono"
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
# Tuono
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/Valerioageno/tuono/main/assets/logo.png" width="160px">
|
||||
<img align="right" src="https://raw.githubusercontent.com/tuono-labs/tuono/main/assets/logo.png" width="160px">
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
**Tuono is a full-stack web framework for building React applications using Rust as the backend with
|
||||
a strong focus on usability and performance.**
|
||||
@@ -48,7 +48,7 @@ by Tuono based on the files defined within the `./src/routes` directory.
|
||||
The Tuono API tries to stick as much as possible to the Next.js one (or at least takes a huge inspiration
|
||||
from it). The major difference is the backend system. While Next.js relies entirely on Node/Deno/Bun,
|
||||
Tuono runs the server without any intermediary runtime. This enables impressive performance improvements
|
||||
(check the benchmarks [here](https://github.com/Valerioageno/tuono/tree/main/benches)).
|
||||
(check the benchmarks [here](https://github.com/tuono-labs/tuono/tree/main/benches)).
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -61,7 +61,7 @@ Then run `cargo install tuono`.
|
||||
To list all the available commands, run `tuono -h`
|
||||
|
||||
To create a new project, run `tuono new [NAME]` (optionally, you can pass the `--template` (or `-t`) flag - check the
|
||||
[examples](https://github.com/Valerioageno/tuono/tree/main/examples) folder).
|
||||
[examples](https://github.com/tuono-labs/tuono/tree/main/examples) folder).
|
||||
|
||||
Then, to run the local development environment, install the JS dependencies (`npm install`) and run inside the project folder `tuono dev`
|
||||
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
@@ -8,7 +8,7 @@ name = "tuono"
|
||||
path = ".tuono/main.rs"
|
||||
|
||||
[dependencies]
|
||||
tuono_lib = "0.12.3"
|
||||
tuono_lib = "0.15.0"
|
||||
glob = "0.3.1"
|
||||
time = { version = "0.3", features = ["macros"] }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
"description": "The react/rust fullstack framework documentation",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .ts,.tsx ./src -c .eslintrc",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown './src/**/*'",
|
||||
"format:check": "prettier --check --ignore-unknown './src/**/*'",
|
||||
"types": "tsc --noEmit"
|
||||
@@ -18,7 +19,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"tuono": "npm:tuono@0.12.3"
|
||||
"tuono": "npm:tuono@0.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mdx": "^2.0.13",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = {
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-preset-mantine': {},
|
||||
'postcss-simple-vars': {
|
||||
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 709 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 15 KiB |
@@ -28,12 +28,6 @@ export default function TuonoBreadcrumbs({
|
||||
"position": 1,
|
||||
"name": "Tuono - The React/Rust fullstack framework",
|
||||
"item": "https://tuono.dev"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "Tuono - Documentation",
|
||||
"item": "https://tuono.dev/documentation"
|
||||
}${breadcrumbs.length > 0 ? ',' : ''}
|
||||
${breadcrumbs
|
||||
.map((br, i) =>
|
||||
@@ -54,13 +48,7 @@ export default function TuonoBreadcrumbs({
|
||||
mb="md"
|
||||
mt="md"
|
||||
>
|
||||
<Button
|
||||
href="/documentation"
|
||||
component={Link}
|
||||
variant="subtle"
|
||||
radius="xl"
|
||||
p={5}
|
||||
>
|
||||
<Button href="/" component={Link} variant="subtle" radius="xl" p={5}>
|
||||
<IconBolt />
|
||||
</Button>
|
||||
{breadcrumbs.map((br) => (
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IconEdit } from '@tabler/icons-react'
|
||||
import { useRouter } from 'tuono'
|
||||
|
||||
const GITHUB_URL =
|
||||
'https://github.com/Valerioageno/tuono/tree/main/apps/documentation/src/routes'
|
||||
'https://github.com/tuono-labs/tuono/tree/main/apps/documentation/src/routes'
|
||||
|
||||
export default function EditPage(): JSX.Element {
|
||||
const { pathname } = useRouter()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { JSX } from 'react'
|
||||
import type { JSX, HTMLAttributes } from 'react'
|
||||
import { Code } from '@mantine/core'
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
export default function MdxCode(
|
||||
props: HTMLAttributes<HTMLPreElement>,
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import type { JSX } from 'react'
|
||||
import { CodeHighlight } from '@mantine/code-highlight'
|
||||
|
||||
import styles from './mdx-pre.module.css'
|
||||
|
||||
interface PreProps {
|
||||
children: any
|
||||
children: {
|
||||
props: {
|
||||
children: string
|
||||
className?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function MdxPre({ children }: PreProps): JSX.Element {
|
||||
return (
|
||||
<CodeHighlight
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { JSX } from 'react'
|
||||
import type { JSX, ReactNode } from 'react'
|
||||
import { MDXProvider } from '@mdx-js/react'
|
||||
|
||||
import MdxLink from './mdx-link'
|
||||
import type { ReactNode } from 'react'
|
||||
import MdxPre from './mdx-pre'
|
||||
import MdxQuote from './mdx-quote'
|
||||
import MdxCode from './mdx-code'
|
||||
|
||||
@@ -8,6 +8,7 @@ export default function MdxTitle(props: TitleProps): JSX.Element {
|
||||
data-order={props.order}
|
||||
mt={20}
|
||||
{...props}
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
id={String(props.children ?? '')
|
||||
.toLowerCase()
|
||||
.replaceAll(' ', '-')}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import type { JSX } from 'react'
|
||||
import { Flex, Button, ActionIcon, Group } from '@mantine/core'
|
||||
import {
|
||||
IconBrandGithub,
|
||||
IconBook,
|
||||
IconBrandDiscord,
|
||||
} from '@tabler/icons-react'
|
||||
import { Link } from 'tuono'
|
||||
import { Flex, ActionIcon, Group } from '@mantine/core'
|
||||
import { IconBrandGithub, IconBrandDiscord } from '@tabler/icons-react'
|
||||
|
||||
import ThemeBtn from '../theme-btn'
|
||||
|
||||
@@ -13,21 +8,11 @@ export default function Actions(): JSX.Element {
|
||||
return (
|
||||
<Flex gap={8}>
|
||||
<Group gap={8}>
|
||||
<Button
|
||||
component={Link}
|
||||
href="/documentation"
|
||||
visibleFrom="sm"
|
||||
size="compact-lg"
|
||||
rightSection={<IconBook />}
|
||||
autoContrast
|
||||
>
|
||||
Get started
|
||||
</Button>
|
||||
<ActionIcon
|
||||
variant="default"
|
||||
size="lg"
|
||||
aria-label="Check the project on github"
|
||||
href="https://github.com/Valerioageno/tuono"
|
||||
href="https://github.com/tuono-labs/tuono"
|
||||
target="_blank"
|
||||
component="a"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { JSX } from 'react'
|
||||
import { AppShell, Burger, Button, Flex } from '@mantine/core'
|
||||
import { Link, useRouter } from 'tuono'
|
||||
import { Link } from 'tuono'
|
||||
|
||||
import Actions from './actions'
|
||||
|
||||
@@ -10,7 +10,6 @@ interface NavbarProps {
|
||||
}
|
||||
|
||||
export default function Navbar({ opened, toggle }: NavbarProps): JSX.Element {
|
||||
const { pathname } = useRouter()
|
||||
return (
|
||||
<AppShell.Header p="sm">
|
||||
<Flex justify="space-between">
|
||||
@@ -19,14 +18,7 @@ export default function Navbar({ opened, toggle }: NavbarProps): JSX.Element {
|
||||
</Button>
|
||||
<Flex align="center" gap={8}>
|
||||
<Actions />
|
||||
{pathname.startsWith('/documentation') && (
|
||||
<Burger
|
||||
opened={opened}
|
||||
onClick={toggle}
|
||||
hiddenFrom="sm"
|
||||
size="sm"
|
||||
/>
|
||||
)}
|
||||
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</AppShell.Header>
|
||||
|
||||
@@ -10,11 +10,7 @@ interface SidebarProps {
|
||||
export default function Sidebar({ close }: SidebarProps): JSX.Element {
|
||||
return (
|
||||
<AppShell.Navbar p="md">
|
||||
<SidebarLink
|
||||
href="/documentation"
|
||||
label="Getting started"
|
||||
onClick={close}
|
||||
/>
|
||||
<SidebarLink href="/" label="Home" onClick={close} />
|
||||
<SidebarLink
|
||||
href="/documentation/installation"
|
||||
label="Installation"
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useEffect, useRef, useState } from 'react'
|
||||
import { useRouter, Link } from 'tuono'
|
||||
import { IconList } from '@tabler/icons-react'
|
||||
import { Box, rem, ScrollArea, Text } from '@mantine/core'
|
||||
|
||||
import { getHeadings, type Heading } from './get-headings'
|
||||
import classes from './table-of-content.module.css'
|
||||
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
// declaration.d.ts
|
||||
declare module '*.css'
|
||||
declare module '*.css' {
|
||||
const CSSModule: Record<string, string>
|
||||
export default CSSModule
|
||||
}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
|
||||
import {
|
||||
ColorSchemeScript,
|
||||
createTheme,
|
||||
MantineProvider,
|
||||
AppShell,
|
||||
Container,
|
||||
} from '@mantine/core'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { Head, useRouter } from 'tuono'
|
||||
import Navbar from '../components/navbar'
|
||||
import { Head } from 'tuono'
|
||||
|
||||
import EditPage from '@/components/edit-page'
|
||||
import MdxProvider from '@/components/mdx-provider'
|
||||
import Navbar from '@/components/navbar'
|
||||
import Sidebar from '@/components/sidebar'
|
||||
|
||||
import '@mantine/core/styles.css'
|
||||
import '@mantine/code-highlight/styles.css'
|
||||
|
||||
import Sidebar from '../components/sidebar'
|
||||
|
||||
interface RootRouteProps {
|
||||
children: ReactNode
|
||||
}
|
||||
@@ -61,29 +65,14 @@ const theme = createTheme({
|
||||
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
const [opened, { toggle }] = useDisclosure()
|
||||
|
||||
const { pathname } = useRouter()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<meta charSet="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
</Head>
|
||||
@@ -98,8 +87,13 @@ export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<Navbar opened={opened} toggle={toggle} />
|
||||
{pathname.startsWith('/documentation') && <Sidebar close={toggle} />}
|
||||
{children}
|
||||
<Sidebar close={toggle} />
|
||||
<AppShell.Main>
|
||||
<Container id="mdx-root" component="article" size="md" p={20}>
|
||||
<MdxProvider>{children}</MdxProvider>
|
||||
<EditPage />
|
||||
</Container>
|
||||
</AppShell.Main>
|
||||
</AppShell>
|
||||
</MantineProvider>
|
||||
</>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
import { AppShell, Container } from '@mantine/core'
|
||||
|
||||
import MdxProvider from '../../components/mdx-provider'
|
||||
import EditPage from '../../components/edit-page'
|
||||
|
||||
interface RootRouteProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
return (
|
||||
<AppShell.Main>
|
||||
<Container id="mdx-root" component="article" size="md" p={20}>
|
||||
<MdxProvider>{children}</MdxProvider>
|
||||
<EditPage />
|
||||
</Container>
|
||||
</AppShell.Main>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Application state"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../components/meta-tags'
|
||||
description="Learn how to add features to your Tuono application"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Application state' }]} />
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - CLI"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../components/meta-tags'
|
||||
description="Tuono is the CLI that provides all the needed commands to handle the full-stack project."
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'CLI' }]} />
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Contributing"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../components/meta-tags'
|
||||
description="The project is massive - if you like it, do consider contributing!"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: '✨ Contributing' }]} />
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Contributing"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="The project is massive - if you like it, do consider contributing!"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: '✨ Contributing' }]} />
|
||||
|
||||
@@ -28,11 +28,10 @@ The `tuono` project can mostly be split into the following subdomains:
|
||||
To check what the knowledge requirements are for each domain, check the
|
||||
[requirements](#requirements) section below.
|
||||
|
||||
Currently, I'm keeping a private dashboard to prioritize new features and bug fixes, but if you
|
||||
want to propose something, please open a new issue on GitHub or reach out to me using
|
||||
my email address [valerioageno@yahoo.it](mailto:valerioageno@yahoo.it). I'm also available
|
||||
on Twitter (X) DMs `@valerioageno`, [Linkedin](https://www.linkedin.com/in/valerioageno)
|
||||
and discord `@__v__v__`.
|
||||
We are currently managing the tasks' prioritization in the [Road to V1](https://github.com/orgs/tuono-labs/projects/2) project.
|
||||
You can pick any task that you see in the `ready` column that is not already assigned.
|
||||
|
||||
If you want to contribute on something that is in the `backlog` column, or it hasn't been scoped yet, please drop a message in the [#general](https://discord.com/invite/khQzPa654B) discord channel so we can all have visibility of it.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Contributing - Local development"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Contribute to Tuono. Learn here how to setup the repository for local development"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Breadcrumbs, { Element } from '../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
import MetaTags from '../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Installation"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing/intro"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Routing' }]} />
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - API fetching"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to fetch remote APIs on the backend"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Components"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to manage the components in a Tuono codebase"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Conclusion"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="You just created a multi thread full stack application with Rust and React"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Development setup"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to setup a new Tuono project"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Dynamic routes"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to catch more endpoint with the same route loading dynamic data"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Error handling"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to handle the server side error on your Tuono project"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Tutorial"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="This tutorial is meant to give you a sneak peek at the framework and is intended to evolve during the development - be sure to have installed the latest version"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Tutorial' }]} />
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Building for production"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to build the production project and run the optimize version"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Redirection"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to redirect to different route from the server"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '../../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - SEO and meta tags"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '../../../components/meta-tags'
|
||||
description="Learn how to handle meaningful meta tags for your Tuono project"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '../../../components/breadcrumbs'
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import MetaTags from '../../components/meta-tags'
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Documentation"
|
||||
canonical="https://tuono.dev/documentation"
|
||||
canonical="https://tuono.dev"
|
||||
description="Tuono is a full-stack framework for building React applications using Rust as the backend."
|
||||
/>
|
||||
|
||||
import Breadcrumbs from '../../components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs />
|
||||
|
||||
@@ -36,7 +36,7 @@ Tuono addresses the following two limits:
|
||||
|
||||
#### NodeJs/Deno/Bun are the only runtimes that allow a React app to be server-side rendered (SSR)? (no)
|
||||
|
||||
Tuono is the first full-stack React framework with the server side written in Rust (check the [ssr-rs](https://github.com/Valerioageno/ssr-rs) crate).
|
||||
Tuono is the first full-stack React framework with the server side written in Rust (check the [ssr-rs](https://github.com/tuono-labs/ssr-rs) crate).
|
||||
Because of this, Tuono is extremely fast, and the requests are handled by a multithreaded Rust server.
|
||||
React is still React - it is just superpowered.
|
||||
|
||||
@@ -51,4 +51,4 @@ The routing is handled by Tuono based on the files defined within the `./src/rou
|
||||
The Tuono API tries to stick as much as possible to the Next.js one (or at least takes a huge inspiration
|
||||
from it). The major difference is the backend system. While Next.js relies entirely on Node/Deno/Bun,
|
||||
Tuono runs the server without any intermediary runtime. This enables impressive performance improvements
|
||||
(check the benchmarks [here](https://github.com/Valerioageno/tuono/tree/main/benches)).
|
||||
(check the benchmarks [here](https://github.com/tuono-labs/tuono/tree/main/benches)).
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { JSX } from 'react'
|
||||
|
||||
import Hero from '../components/hero'
|
||||
import MetaTags from '../components/meta-tags'
|
||||
|
||||
export default function IndexPage(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<MetaTags
|
||||
title="Tuono - The React/Rust full-stack framework"
|
||||
canonical="https://tuono.dev"
|
||||
description="The technologies we love seamlessly working together to unleash the highest web performance ever met on React"
|
||||
/>
|
||||
<Hero />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
use tuono_lib::reqwest::StatusCode;
|
||||
use tuono_lib::{Request, Response};
|
||||
use tuono_lib::axum::http::{header, HeaderMap};
|
||||
use glob::glob;
|
||||
use time::OffsetDateTime;
|
||||
use tuono_lib::axum::http::{header, HeaderMap, StatusCode};
|
||||
use tuono_lib::{Request, Response};
|
||||
|
||||
const FILE_TO_EXCLUDE: [&str; 2] = ["sitemap.xml", "__root"];
|
||||
|
||||
@@ -14,11 +13,17 @@ const SITEMAP: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
|
||||
fn load_routes() -> Vec<String> {
|
||||
let mut paths: Vec<String> = vec![];
|
||||
|
||||
for entry in glob("./src/routes/**/*").expect("Failed to glob src/routes folder").flatten() {
|
||||
for entry in glob("./src/routes/**/*")
|
||||
.expect("Failed to glob src/routes folder")
|
||||
.flatten()
|
||||
{
|
||||
if !entry.is_dir() {
|
||||
let path = clean_path(format!("/{}", entry.to_string_lossy()));
|
||||
|
||||
if !FILE_TO_EXCLUDE.iter().any(|exclude| path.ends_with(exclude)) {
|
||||
if !FILE_TO_EXCLUDE
|
||||
.iter()
|
||||
.any(|exclude| path.ends_with(exclude))
|
||||
{
|
||||
paths.push(path)
|
||||
}
|
||||
}
|
||||
@@ -51,11 +56,16 @@ async fn generate_sitemap(_req: Request) -> Response {
|
||||
url.pop();
|
||||
}
|
||||
|
||||
sitemaps.push_str(
|
||||
&format!(r#"<url><loc>{}</loc><lastmod>{}</lastmod></url>"#,url, OffsetDateTime::now_utc().date())
|
||||
)
|
||||
sitemaps.push_str(&format!(
|
||||
r#"<url><loc>{}</loc><lastmod>{}</lastmod></url>"#,
|
||||
url,
|
||||
OffsetDateTime::now_utc().date()
|
||||
))
|
||||
}
|
||||
|
||||
Response::Custom((StatusCode::OK, headers, SITEMAP.replace("[PLACEHOLDER]", &sitemaps)))
|
||||
Response::Custom((
|
||||
StatusCode::OK,
|
||||
headers,
|
||||
SITEMAP.replace("[PLACEHOLDER]", &sitemaps),
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2021", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
// Typechecking
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
// Modules
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
|
||||
// Emit
|
||||
"noEmit": true,
|
||||
|
||||
// JavaScript Support
|
||||
"allowJs": true,
|
||||
|
||||
// Interop Constraints
|
||||
"isolatedModules": true,
|
||||
|
||||
// Language and Environment
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2021", "DOM", "DOM.Iterable"],
|
||||
"jsx": "react-jsx",
|
||||
|
||||
// Completeness
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"include": ["src", "tuono.config.ts", "postcss.config.js"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { TuonoConfig } from 'tuono/config'
|
||||
|
||||
const config: TuonoConfig = {
|
||||
vite: {
|
||||
alias: {
|
||||
'@': 'src',
|
||||
'@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "tuono"
|
||||
version = "0.14.5"
|
||||
version = "0.15.1"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "Superfast React fullstack framework"
|
||||
homepage = "https://tuono.dev"
|
||||
keywords = [ "react", "typescript", "fullstack", "web", "ssr"]
|
||||
repository = "https://github.com/Valerioageno/tuono"
|
||||
repository = "https://github.com/tuono-labs/tuono"
|
||||
readme = "../../README.md"
|
||||
license-file = "../../LICENSE.md"
|
||||
categories = ["web-programming"]
|
||||
@@ -33,3 +33,8 @@ reqwest = {version = "0.12.4", features =["blocking", "json"]}
|
||||
serde_json = "1.0"
|
||||
fs_extra = "1.3.0"
|
||||
http = "1.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.14.0"
|
||||
assert_cmd = "2.0.16"
|
||||
serial_test = "0.4.0"
|
||||
|
||||
@@ -21,11 +21,17 @@ const ROUTES_FOLDER_PATH: &str = "\\src\\routes";
|
||||
#[cfg(target_os = "windows")]
|
||||
const BUILD_JS_SCRIPT: &str = ".\\node_modules\\.bin\\tuono-build-prod.cmd";
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const BUILD_TUONO_CONFIG: &str = ".\\node_modules\\.bin\\tuono-build-config.cmd";
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const ROUTES_FOLDER_PATH: &str = "/src/routes";
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const BUILD_JS_SCRIPT: &str = "./node_modules/.bin/tuono-build-prod";
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const BUILD_TUONO_CONFIG: &str = "./node_modules/.bin/tuono-build-config";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct App {
|
||||
pub route_map: HashMap<String, Route>,
|
||||
@@ -147,6 +153,13 @@ impl App {
|
||||
.expect("Failed to run the rust server")
|
||||
}
|
||||
|
||||
pub fn build_tuono_config(&self) -> Result<std::process::Output, std::io::Error> {
|
||||
Command::new(BUILD_TUONO_CONFIG)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.output()
|
||||
}
|
||||
pub fn get_used_http_methods(&self) -> HashSet<Method> {
|
||||
let mut acc = HashSet::new();
|
||||
|
||||
|
||||
@@ -87,7 +87,9 @@ pub fn app() -> std::io::Result<()> {
|
||||
Actions::Dev => {
|
||||
check_ports(Mode::Dev);
|
||||
|
||||
let _ = init_tuono_folder(Mode::Dev)?;
|
||||
let app = init_tuono_folder(Mode::Dev)?;
|
||||
app.build_tuono_config()
|
||||
.expect("Failed to build tuono.config.ts");
|
||||
|
||||
watch::watch().unwrap();
|
||||
}
|
||||
@@ -105,6 +107,9 @@ pub fn app() -> std::io::Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
app.build_tuono_config()
|
||||
.expect("Failed to build tuono.config.ts");
|
||||
|
||||
app.build_react_prod();
|
||||
|
||||
if ssg {
|
||||
@@ -128,6 +133,8 @@ pub fn app() -> std::io::Result<()> {
|
||||
)
|
||||
.expect("Failed to clone assets into static output folder");
|
||||
|
||||
// the process is killed below so we don't really need to use wait() function
|
||||
#[allow(clippy::zombie_processes)]
|
||||
let mut rust_server = app.run_rust_server();
|
||||
|
||||
let reqwest = reqwest::blocking::Client::builder()
|
||||
@@ -139,7 +146,8 @@ pub fn app() -> std::io::Result<()> {
|
||||
let mut is_server_ready = false;
|
||||
|
||||
while !is_server_ready {
|
||||
if reqwest.get("http://localhost:3000").send().is_ok() {
|
||||
let server_url = format!("http://localhost:{}", TUONO_PORT);
|
||||
if reqwest.get(server_url).send().is_ok() {
|
||||
is_server_ready = true
|
||||
}
|
||||
// TODO: add maximum tries
|
||||
|
||||
@@ -7,9 +7,9 @@ use std::io::{self, prelude::*};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const GITHUB_TUONO_REPO_URL: &str =
|
||||
"https://api.github.com/repos/Valerioageno/tuono/git/trees/main?recursive=1";
|
||||
"https://api.github.com/repos/tuono-labs/tuono/git/trees/main?recursive=1";
|
||||
|
||||
const GITHUB_RAW_CONTENT_URL: &str = "https://raw.githubusercontent.com/Valerioageno/tuono/main/";
|
||||
const GITHUB_RAW_CONTENT_URL: &str = "https://raw.githubusercontent.com/tuono-labs/tuono/main/";
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
enum GithubFileType {
|
||||
@@ -64,7 +64,7 @@ pub fn create_new_project(folder_name: Option<String>, template: Option<String>)
|
||||
|
||||
if new_project_files.is_empty() {
|
||||
eprintln!("Error: Template '{template}' not found");
|
||||
println!("Hint: you can view the available templates at https://github.com/Valerioageno/tuono/tree/main/examples");
|
||||
println!("Hint: you can view the available templates at https://github.com/tuono-labs/tuono/tree/main/examples");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
mod utils;
|
||||
use assert_cmd::Command;
|
||||
use serial_test::serial;
|
||||
use std::fs;
|
||||
use utils::TempTuonoProject;
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn it_successfully_create_the_index_route() {
|
||||
let temp_tuono_project = TempTuonoProject::new();
|
||||
|
||||
temp_tuono_project.add_route("./src/routes/index.rs");
|
||||
|
||||
let mut test_tuono_build = Command::cargo_bin("tuono").unwrap();
|
||||
test_tuono_build
|
||||
.arg("build")
|
||||
.arg("--no-js-emit")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let temp_main_rs_path = temp_tuono_project.path().join(".tuono/main.rs");
|
||||
|
||||
let temp_main_rs_content =
|
||||
fs::read_to_string(&temp_main_rs_path).expect("Failed to read '.tuono/main.rs' content.");
|
||||
|
||||
assert!(temp_main_rs_content.contains(r#"#[path="../src/routes/index.rs"]"#));
|
||||
assert!(temp_main_rs_content.contains("mod index;"));
|
||||
|
||||
assert!(temp_main_rs_content.contains(
|
||||
r#".route("/", get(index::route)).route("/__tuono/data/data.json", get(index::api))"#
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use fs_extra::dir::create_all;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TempTuonoProject {
|
||||
original_dir: PathBuf,
|
||||
temp_dir: TempDir,
|
||||
}
|
||||
|
||||
impl TempTuonoProject {
|
||||
pub fn new() -> Self {
|
||||
let original_dir = env::current_dir().expect("Failed to read current_dir");
|
||||
let temp_dir = tempdir().expect("Failed to create temp_dir");
|
||||
|
||||
env::set_current_dir(temp_dir.path()).expect("Failed to change current dir into temp_dir");
|
||||
|
||||
TempTuonoProject {
|
||||
original_dir,
|
||||
temp_dir,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
self.temp_dir.path()
|
||||
}
|
||||
|
||||
pub fn add_route<'a>(&self, path: &'a str) {
|
||||
let path = PathBuf::from(path);
|
||||
create_all(
|
||||
path.parent().expect("Route path does not have any parent"),
|
||||
false,
|
||||
)
|
||||
.expect("Failed to create parent route directory");
|
||||
File::create(path).expect("Failed to create the route file");
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TempTuonoProject {
|
||||
fn drop(&mut self) {
|
||||
// Set back the current dir in the previous state
|
||||
env::set_current_dir(self.original_dir.to_owned())
|
||||
.expect("Failed to restore the original directory.");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "tuono_lib"
|
||||
version = "0.14.5"
|
||||
version = "0.15.1"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "Superfast React fullstack framework"
|
||||
homepage = "https://tuono.dev"
|
||||
keywords = [ "react", "typescript", "fullstack", "web", "ssr"]
|
||||
repository = "https://github.com/Valerioageno/tuono"
|
||||
repository = "https://github.com/tuono-labs/tuono"
|
||||
readme = "../../README.md"
|
||||
license-file = "../../LICENSE.md"
|
||||
categories = ["web-programming"]
|
||||
@@ -19,6 +19,7 @@ include = [
|
||||
[dependencies]
|
||||
ssr_rs = "0.7.0"
|
||||
axum = {version = "0.7.5", features = ["json", "ws"]}
|
||||
axum-extra = {version = "0.9.6", features = ["cookie"]}
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
erased-serde = "0.4.5"
|
||||
@@ -31,7 +32,7 @@ either = "1.13.0"
|
||||
tower-http = {version = "0.6.0", features = ["fs"]}
|
||||
colored = "2.1.0"
|
||||
|
||||
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.14.5"}
|
||||
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.15.1"}
|
||||
# Match the same version used by axum
|
||||
tokio-tungstenite = "0.24.0"
|
||||
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
|
||||
|
||||
@@ -19,4 +19,5 @@ pub use tuono_lib_macros::{api, handler};
|
||||
|
||||
// Re-exports
|
||||
pub use axum;
|
||||
pub use axum_extra::extract::cookie;
|
||||
pub use tokio;
|
||||
|
||||
@@ -3,11 +3,13 @@ use crate::{ssr::Js, Payload};
|
||||
use axum::http::{HeaderMap, StatusCode};
|
||||
use axum::response::{Html, IntoResponse, Redirect};
|
||||
use axum::Json;
|
||||
use axum_extra::extract::cookie::{Cookie, CookieJar};
|
||||
use erased_serde::Serialize;
|
||||
|
||||
pub struct Props {
|
||||
data: Box<dyn Serialize>,
|
||||
http_code: StatusCode,
|
||||
cookies: CookieJar,
|
||||
}
|
||||
|
||||
pub enum Response {
|
||||
@@ -57,26 +59,45 @@ impl Props {
|
||||
Props {
|
||||
data: Box::new(data),
|
||||
http_code: StatusCode::OK,
|
||||
cookies: CookieJar::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn status(&mut self, http_code: StatusCode) {
|
||||
self.http_code = http_code;
|
||||
}
|
||||
|
||||
pub fn new_with_status(data: impl Serialize + 'static, http_code: StatusCode) -> Self {
|
||||
Props {
|
||||
data: Box::new(data),
|
||||
http_code,
|
||||
cookies: CookieJar::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_cookie(&mut self, cookie: Cookie) {
|
||||
let jar = self.cookies.clone().add(cookie.into_owned());
|
||||
self.cookies = jar
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn render_to_string(&self, req: Request) -> impl IntoResponse {
|
||||
match self {
|
||||
Self::Props(Props { data, http_code }) => {
|
||||
let payload = Payload::new(&req, data).client_payload().unwrap();
|
||||
Self::Props(Props {
|
||||
data,
|
||||
http_code,
|
||||
cookies,
|
||||
}) => {
|
||||
let payload = Payload::new(&req, data.as_ref()).client_payload().unwrap();
|
||||
|
||||
match Js::render_to_string(Some(&payload)) {
|
||||
Ok(html) => (*http_code, Html(html)),
|
||||
Err(_) => (*http_code, Html("500 Internal server error".to_string())),
|
||||
Ok(html) => (*http_code, cookies.clone(), Html(html)),
|
||||
Err(_) => (
|
||||
*http_code,
|
||||
cookies.clone(),
|
||||
Html("500 Internal server error".to_string()),
|
||||
),
|
||||
}
|
||||
.into_response()
|
||||
}
|
||||
@@ -87,9 +108,16 @@ impl Response {
|
||||
|
||||
pub fn json(&self) -> impl IntoResponse {
|
||||
match self {
|
||||
Self::Props(Props { data, http_code }) => {
|
||||
(*http_code, Json(JsonResponse::new(data))).into_response()
|
||||
}
|
||||
Self::Props(Props {
|
||||
data,
|
||||
http_code,
|
||||
cookies,
|
||||
}) => (
|
||||
*http_code,
|
||||
cookies.clone(),
|
||||
Json(JsonResponse::new(data.as_ref())),
|
||||
)
|
||||
.into_response(),
|
||||
Self::Redirect(destination) => (
|
||||
StatusCode::PERMANENT_REDIRECT,
|
||||
Json(JsonResponse::new_redirect(destination.to_string())),
|
||||
@@ -101,3 +129,32 @@ impl Response {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_update_the_props_status_and_cookie() {
|
||||
let mut props = Props::new("{}");
|
||||
props.status(StatusCode::NOT_FOUND);
|
||||
props.add_cookie(Cookie::new("test", "cookie"));
|
||||
assert_eq!(props.http_code, StatusCode::NOT_FOUND);
|
||||
assert_eq!(
|
||||
props.cookies.get("test").unwrap(),
|
||||
&Cookie::new("test", "cookie")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_add_a_cookie_jar() {
|
||||
let mut props = Props::new("{}");
|
||||
props.status(StatusCode::NOT_FOUND);
|
||||
props.add_cookie(Cookie::new("test", "cookie"));
|
||||
assert_eq!(props.http_code, StatusCode::NOT_FOUND);
|
||||
assert_eq!(
|
||||
props.cookies.get("test").unwrap(),
|
||||
&Cookie::new("test", "cookie")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "tuono_lib_macros"
|
||||
version = "0.14.5"
|
||||
version = "0.15.1"
|
||||
edition = "2021"
|
||||
description = "Superfast React fullstack framework"
|
||||
homepage = "https://tuono.dev"
|
||||
keywords = [ "react", "typescript", "fullstack", "web", "ssr"]
|
||||
repository = "https://github.com/Valerioageno/tuono"
|
||||
repository = "https://github.com/tuono-labs/tuono"
|
||||
readme = "../../README.md"
|
||||
license-file = "../../LICENSE.md"
|
||||
categories = ["web-programming"]
|
||||
@@ -15,8 +15,7 @@ include = [
|
||||
]
|
||||
|
||||
[lib]
|
||||
crate_type = ["proc-macro"]
|
||||
proc-marco = true
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2.0.0", features = ["full"] }
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
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',
|
||||
'**/.tuono',
|
||||
'**/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',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['apps/documentation/**'],
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
typescript: 'apps/documentation/tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,9 +1,21 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
import { Head } from 'tuono'
|
||||
|
||||
interface RootRouteProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
return <main className="main">{children}</main>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<link
|
||||
rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"
|
||||
/>
|
||||
<title>Tuono app</title>
|
||||
</Head>
|
||||
<main className="main">{children}</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@ use tuono_lib::Request;
|
||||
use tuono_lib::axum::http::StatusCode;
|
||||
|
||||
#[tuono_lib::api(GET)]
|
||||
pub async fn my_get_request(_req: Request) -> StatusCode {
|
||||
pub async fn health_check(_req: Request) -> StatusCode {
|
||||
StatusCode::OK
|
||||
}
|
||||
|
||||
@@ -2,47 +2,47 @@ import type { JSX } from 'react'
|
||||
import type { TuonoProps } from 'tuono'
|
||||
|
||||
interface IndexProps {
|
||||
subtitle: string
|
||||
subtitle: string
|
||||
}
|
||||
|
||||
export default function IndexPage({
|
||||
data,
|
||||
isLoading,
|
||||
data,
|
||||
isLoading,
|
||||
}: TuonoProps<IndexProps>): JSX.Element {
|
||||
if (isLoading) {
|
||||
return <h1>Loading...</h1>
|
||||
}
|
||||
if (isLoading) {
|
||||
return <h1>Loading...</h1>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="header">
|
||||
<a href="https://crates.io/crates/tuono" target="_blank">
|
||||
Crates
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/tuono" target="_blank">
|
||||
Npm
|
||||
</a>
|
||||
</header>
|
||||
<div className="title-wrap">
|
||||
<h1 className="title">
|
||||
TU<span>O</span>NO
|
||||
</h1>
|
||||
<div className="logo">
|
||||
<img src="rust.svg" className="rust" />
|
||||
<img src="react.svg" className="react" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="subtitle-wrap">
|
||||
<p className="subtitle">{data?.subtitle}</p>
|
||||
<a
|
||||
href="https://github.com/Valerioageno/tuono"
|
||||
target="_blank"
|
||||
className="button"
|
||||
type="button"
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<header className="header">
|
||||
<a href="https://crates.io/crates/tuono" target="_blank">
|
||||
Crates
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/tuono" target="_blank">
|
||||
Npm
|
||||
</a>
|
||||
</header>
|
||||
<div className="title-wrap">
|
||||
<h1 className="title">
|
||||
TU<span>O</span>NO
|
||||
</h1>
|
||||
<div className="logo">
|
||||
<img src="rust.svg" className="rust" />
|
||||
<img src="react.svg" className="react" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="subtitle-wrap">
|
||||
<p className="subtitle">{data?.subtitle}</p>
|
||||
<a
|
||||
href="https://github.com/tuono-labs/tuono"
|
||||
target="_blank"
|
||||
className="button"
|
||||
type="button"
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"include": ["src", "tuono.config.ts"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { TuonoConfig } from 'tuono/config'
|
||||
|
||||
const config: TuonoConfig = {}
|
||||
|
||||
export default config
|
||||
|
Before Width: | Height: | Size: 39 KiB |
@@ -1,9 +1,21 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
import { Head } from 'tuono'
|
||||
|
||||
interface RootRouteProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
return <main className="main">{children}</main>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<link
|
||||
rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"
|
||||
/>
|
||||
<title>Tuono tutorial</title>
|
||||
</Head>
|
||||
<main className="main">{children}</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { JSX } from 'react'
|
||||
import { Head, type TuonoProps } from 'tuono'
|
||||
|
||||
import PokemonLink from '../components/PokemonLink'
|
||||
import PokemonLink from '@/components/PokemonLink'
|
||||
|
||||
interface Pokemon {
|
||||
name: string
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { JSX } from 'react'
|
||||
import { Head, type TuonoProps } from 'tuono'
|
||||
|
||||
import PokemonView from '../../components/PokemonView'
|
||||
import PokemonView from '@/components/PokemonView'
|
||||
|
||||
interface Pokemon {
|
||||
name: string
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"include": ["src", "tuono.config.ts"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { TuonoConfig } from 'tuono/config'
|
||||
|
||||
const config: TuonoConfig = {
|
||||
vite: {
|
||||
alias: {
|
||||
'@': 'src',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
|
Before Width: | Height: | Size: 39 KiB |
@@ -1,5 +1,6 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
import { MDXProvider } from '@mdx-js/react'
|
||||
import { Head } from 'tuono'
|
||||
|
||||
interface RootRouteProps {
|
||||
children: ReactNode
|
||||
@@ -7,8 +8,17 @@ interface RootRouteProps {
|
||||
|
||||
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
return (
|
||||
<main className="main">
|
||||
<MDXProvider components={{}}>{children}</MDXProvider>
|
||||
</main>
|
||||
<>
|
||||
<Head>
|
||||
<link
|
||||
rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"
|
||||
/>
|
||||
<title>Tuono - With MDX</title>
|
||||
</Head>
|
||||
<main className="main">
|
||||
<MDXProvider components={{}}>{children}</MDXProvider>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"include": ["src", "tuono.config.ts"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { TuonoConfig } from 'tuono/config'
|
||||
|
||||
const config: TuonoConfig = {}
|
||||
|
||||
export default config
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# tuono-fs-router-vite-plugin
|
||||
|
||||
This is a vite plugin for [tuono](https://github.com/Valerioageno/tuono).
|
||||
This is a vite plugin for [tuono](https://github.com/tuono-labs/tuono).
|
||||
|
||||
This package specifically handles the file system based routing.
|
||||
|
||||
Check [tuono](https://github.com/Valerioageno/tuono) for more.
|
||||
Check [tuono](https://github.com/tuono-labs/tuono) for more.
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
{
|
||||
"name": "tuono-fs-router-vite-plugin",
|
||||
"version": "0.14.5",
|
||||
"version": "0.15.1",
|
||||
"description": "Plugin for the tuono's file system router. Tuono is the react/rust fullstack framework",
|
||||
"homepage": "https://tuono.dev",
|
||||
"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",
|
||||
"test:watch": "vitest",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tuono-labs/tuono.git",
|
||||
"directory": "packages/fs-router-vite-plugin"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Valerio Ageno",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -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/**"]
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# tuono-lazy-fn-vite-plugin
|
||||
|
||||
This is a vite plugin for [tuono](https://github.com/Valerioageno/tuono).
|
||||
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/Valerioageno/tuono) for more.
|
||||
Check [tuono](https://github.com/tuono-labs/tuono) for more.
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
{
|
||||
"name": "tuono-lazy-fn-vite-plugin",
|
||||
"version": "0.14.5",
|
||||
"version": "0.15.1",
|
||||
"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 --ext .ts,.tsx ./src -c ../../.eslintrc",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown '**/*'",
|
||||
"format:check": "prettier --check --ignore-unknown '**/*'",
|
||||
"types": "tsc --noEmit",
|
||||
"test:watch": "vitest",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tuono-labs/tuono.git",
|
||||
"directory": "packages/lazy-fn-vite-plugin"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Valerio Ageno",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -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
|
||||
|
||||