mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-27 13:52:47 -07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bf77ed1794 | |||
| e34c10bc34 | |||
| 310579cf76 | |||
| 1ba94238ed |
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono"
|
||||
version = "0.17.9"
|
||||
version = "0.17.10"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "Superfast React fullstack framework"
|
||||
@@ -32,7 +32,7 @@ reqwest = { version = "0.12.4", features = ["blocking", "json"] }
|
||||
serde_json = "1.0"
|
||||
fs_extra = "1.3.0"
|
||||
http = "1.1.0"
|
||||
tuono_internal = {path = "../tuono_internal", version = "0.17.9"}
|
||||
tuono_internal = {path = "../tuono_internal", version = "0.17.10"}
|
||||
spinners = "4.1.1"
|
||||
console = "0.15.10"
|
||||
|
||||
|
||||
@@ -86,12 +86,18 @@ pub fn build(mut app: App, ssg: bool, no_js_emit: bool) {
|
||||
|
||||
while !is_server_ready {
|
||||
trace!("Checking server availability");
|
||||
let server_url = format!("http://{}:{}", config.server.host, config.server.port);
|
||||
|
||||
let server_url = match &config.server.origin {
|
||||
Some(origin) => origin.clone(),
|
||||
None => format!("http://{}:{}", config.server.host, config.server.port),
|
||||
};
|
||||
|
||||
if reqwest_client.get(&server_url).send().is_ok() {
|
||||
is_server_ready = true;
|
||||
} else {
|
||||
trace!("Server not ready yet. Sleeping for 1 second");
|
||||
}
|
||||
|
||||
sleep(Duration::from_secs(1));
|
||||
}
|
||||
|
||||
|
||||
+14
-10
@@ -180,11 +180,13 @@ impl Route {
|
||||
}
|
||||
};
|
||||
|
||||
if !parent_dir.is_dir() || create_all(parent_dir, false).is_err() {
|
||||
return Err(format!(
|
||||
"Failed to create the parent directory {:?}",
|
||||
parent_dir
|
||||
));
|
||||
if !parent_dir.is_dir() {
|
||||
if let Err(err) = create_all(parent_dir, false) {
|
||||
return Err(format!(
|
||||
"Failed to create the parent directory {:?}\nError: {err}",
|
||||
parent_dir
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
trace!("Saving the HTML file: {:?}", file_path);
|
||||
@@ -214,11 +216,13 @@ impl Route {
|
||||
}
|
||||
};
|
||||
|
||||
if !data_parent_dir.is_dir() && create_all(data_parent_dir, false).is_err() {
|
||||
return Err(format!(
|
||||
"Failed to create the parent directory {:?}",
|
||||
data_parent_dir
|
||||
));
|
||||
if !data_parent_dir.is_dir() {
|
||||
if let Err(err) = create_all(data_parent_dir, false) {
|
||||
return Err(format!(
|
||||
"Failed to create the parent directory {:?}\n Error: {err}",
|
||||
data_parent_dir
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let base = Url::parse("http://localhost:3000/__tuono/data").unwrap();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono_internal"
|
||||
version = "0.17.9"
|
||||
version = "0.17.10"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "Superfast React fullstack framework"
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::path::PathBuf;
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct ServerConfig {
|
||||
pub host: String,
|
||||
pub origin: Option<String>,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,30 @@ fn should_correctly_read_the_config_file() {
|
||||
|
||||
let config = config.unwrap();
|
||||
assert_eq!(config.server.host, "localhost");
|
||||
assert_eq!(config.server.origin, None);
|
||||
assert_eq!(config.server.port, 3000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn should_correctly_read_the_config_file_with_origin() {
|
||||
let folder = TempTuonoProject::new();
|
||||
|
||||
folder.add_file_with_content(
|
||||
"./.tuono/config/config.json",
|
||||
r#"{ "server": {"host": "localhost", "origin": "https://tuono.localhost", "port": 3000}}"#,
|
||||
);
|
||||
|
||||
let config = Config::get();
|
||||
|
||||
assert!(config.is_ok());
|
||||
|
||||
let config = config.unwrap();
|
||||
assert_eq!(config.server.host, "localhost".to_string());
|
||||
assert_eq!(
|
||||
config.server.origin,
|
||||
Some("https://tuono.localhost".to_string())
|
||||
);
|
||||
assert_eq!(config.server.port, 3000);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono_lib"
|
||||
version = "0.17.9"
|
||||
version = "0.17.10"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "Superfast React fullstack framework"
|
||||
@@ -32,8 +32,8 @@ 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.17.9"}
|
||||
tuono_internal = {path = "../tuono_internal", version = "0.17.9"}
|
||||
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.17.10"}
|
||||
tuono_internal = {path = "../tuono_internal", version = "0.17.10"}
|
||||
# Match the same version used by axum
|
||||
tokio-tungstenite = "0.26.0"
|
||||
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
|
||||
|
||||
@@ -25,9 +25,31 @@ pub struct Server {
|
||||
mode: Mode,
|
||||
pub listener: tokio::net::TcpListener,
|
||||
pub address: String,
|
||||
pub origin: Option<String>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
fn display_start_message(&self) {
|
||||
/*
|
||||
* Format the server address as a valid URL so that it becomes clickable in the CLI
|
||||
* @see https://github.com/tuono-labs/tuono/issues/460
|
||||
*/
|
||||
let server_base_url = format!("http://{}", self.address);
|
||||
|
||||
if self.mode == Mode::Dev {
|
||||
println!(" Ready at: {}\n", server_base_url.blue().bold());
|
||||
} else {
|
||||
println!(
|
||||
" Production server at: {}\n",
|
||||
server_base_url.blue().bold()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(origin) = &self.origin {
|
||||
println!(" Origin: {}\n", origin.blue().bold());
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init(router: Router, mode: Mode) -> Server {
|
||||
let config = Config::get().expect("[SERVER] Failed to load config");
|
||||
|
||||
@@ -44,6 +66,7 @@ impl Server {
|
||||
router,
|
||||
mode,
|
||||
address: server_address.clone(),
|
||||
origin: config.server.origin.clone(),
|
||||
listener: tokio::net::TcpListener::bind(&server_address)
|
||||
.await
|
||||
.expect("[SERVER] Failed to bind to address"),
|
||||
@@ -51,14 +74,9 @@ impl Server {
|
||||
}
|
||||
|
||||
pub async fn start(self) {
|
||||
/*
|
||||
* Format the server address as a valid URL so that it becomes clickable in the CLI
|
||||
* @see https://github.com/tuono-labs/tuono/issues/460
|
||||
*/
|
||||
let server_base_url = format!("http://{}", self.address);
|
||||
self.display_start_message();
|
||||
|
||||
if self.mode == Mode::Dev {
|
||||
println!(" Ready at: {}\n", server_base_url.blue().bold());
|
||||
let router = self
|
||||
.router
|
||||
.to_owned()
|
||||
@@ -74,10 +92,6 @@ impl Server {
|
||||
.await
|
||||
.expect("Failed to serve development server");
|
||||
} else {
|
||||
println!(
|
||||
" Production server at: {}\n",
|
||||
server_base_url.blue().bold()
|
||||
);
|
||||
let router = self
|
||||
.router
|
||||
.to_owned()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono_lib_macros"
|
||||
version = "0.17.9"
|
||||
version = "0.17.10"
|
||||
edition = "2021"
|
||||
description = "Superfast React fullstack framework"
|
||||
homepage = "https://tuono.dev"
|
||||
|
||||
@@ -46,7 +46,7 @@ export default function IndexPage({
|
||||
<PokemonLink name="GOAT" id={0} />
|
||||
|
||||
{data.results.map((pokemon, i) => (
|
||||
<PokemonLink key={i + 1} name={pokemon.name} id={i + 1} />
|
||||
<PokemonLink key={pokemon.name} name={pokemon.name} id={i + 1} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tuono-fs-router-vite-plugin",
|
||||
"version": "0.17.9",
|
||||
"version": "0.17.10",
|
||||
"description": "Plugin for the tuono's file system router. Tuono is the react/rust fullstack framework",
|
||||
"homepage": "https://tuono.dev",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tuono-router",
|
||||
"version": "0.17.9",
|
||||
"version": "0.17.10",
|
||||
"description": "React routing component for the framework tuono. Tuono is the react/rust fullstack framework",
|
||||
"homepage": "https://tuono.dev",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tuono",
|
||||
"version": "0.17.9",
|
||||
"version": "0.17.10",
|
||||
"description": "Superfast React fullstack framework",
|
||||
"homepage": "https://tuono.dev",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import fs from 'fs/promises'
|
||||
import fs from 'node:fs/promises'
|
||||
|
||||
import { beforeEach, describe, expect, it, vitest } from 'vitest'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
@@ -12,9 +12,9 @@ describe('createJsonConfig', () => {
|
||||
writeFileSpy.mockClear()
|
||||
})
|
||||
|
||||
const sampleConfig = { server: { host: 'h', port: 1 } }
|
||||
|
||||
it('should process config with only server property', async () => {
|
||||
const sampleConfig = { server: { host: 'h', origin: null, port: 1 } }
|
||||
|
||||
await createJsonConfig(sampleConfig)
|
||||
|
||||
expect(writeFileSpy).toHaveBeenCalledWith(
|
||||
@@ -25,6 +25,8 @@ describe('createJsonConfig', () => {
|
||||
})
|
||||
|
||||
it('should process config with plugins', async () => {
|
||||
const sampleConfig = { server: { host: 'h', origin: null, port: 1 } }
|
||||
|
||||
await createJsonConfig({ ...sampleConfig, vite: { plugins: [react()] } })
|
||||
|
||||
expect(writeFileSpy).toHaveBeenCalledWith(
|
||||
@@ -33,4 +35,16 @@ describe('createJsonConfig', () => {
|
||||
expect.any(String),
|
||||
)
|
||||
})
|
||||
|
||||
it('should process config with only server property including origin', async () => {
|
||||
const sampleConfig = { server: { host: 'h', origin: 'o', port: 1 } }
|
||||
|
||||
await createJsonConfig(sampleConfig)
|
||||
|
||||
expect(writeFileSpy).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.stringContaining(JSON.stringify(sampleConfig)),
|
||||
expect.any(String),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,7 +15,11 @@ describe('normalizeConfig', () => {
|
||||
const config: TuonoConfig = {}
|
||||
|
||||
expect(normalizeConfig(config)).toStrictEqual({
|
||||
server: { host: 'localhost', port: 3000 },
|
||||
server: {
|
||||
host: 'localhost',
|
||||
origin: null,
|
||||
port: 3000,
|
||||
},
|
||||
vite: {
|
||||
alias: undefined,
|
||||
css: undefined,
|
||||
@@ -28,7 +32,11 @@ describe('normalizeConfig', () => {
|
||||
it('should return an empty config if invalid values are provided', () => {
|
||||
// @ts-expect-error testing invalid config
|
||||
expect(normalizeConfig({ invalid: true })).toStrictEqual({
|
||||
server: { host: 'localhost', port: 3000 },
|
||||
server: {
|
||||
host: 'localhost',
|
||||
origin: null,
|
||||
port: 3000,
|
||||
},
|
||||
vite: {
|
||||
alias: undefined,
|
||||
css: undefined,
|
||||
@@ -55,6 +63,28 @@ describe('normalizeConfig', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('server - origin', () => {
|
||||
it('should assign the origin defined by the user', () => {
|
||||
const config: TuonoConfig = {
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
origin: 'https://tuono.localhost',
|
||||
port: 8080,
|
||||
},
|
||||
}
|
||||
|
||||
expect(normalizeConfig(config)).toStrictEqual(
|
||||
expect.objectContaining({
|
||||
server: expect.objectContaining({
|
||||
host: '0.0.0.0',
|
||||
origin: 'https://tuono.localhost',
|
||||
port: 8080,
|
||||
}) as unknown,
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('vite - alias', () => {
|
||||
it('should not modify alias pointing to packages', () => {
|
||||
const libraryName = '@tabler/icons-react'
|
||||
|
||||
@@ -71,6 +71,7 @@ export const normalizeConfig = (config: TuonoConfig): InternalTuonoConfig => {
|
||||
return {
|
||||
server: {
|
||||
host: config.server?.host ?? 'localhost',
|
||||
origin: config.server?.origin ?? null,
|
||||
port: config.server?.port ?? 3000,
|
||||
},
|
||||
vite: {
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
export interface TuonoConfig {
|
||||
server?: {
|
||||
host?: string
|
||||
origin?: string | null
|
||||
port?: number
|
||||
}
|
||||
vite?: {
|
||||
|
||||
@@ -3,13 +3,16 @@ import type { JSX } from 'react'
|
||||
import { useTuonoContextServerPayload } from './TuonoContext'
|
||||
|
||||
const VITE_PROXY_PATH = '/vite-server'
|
||||
const DEFAULT_SERVER_CONFIG = { host: 'localhost', port: 3000 }
|
||||
const DEFAULT_SERVER_CONFIG = { host: 'localhost', origin: null, port: 3000 }
|
||||
|
||||
export const DevResources = (): JSX.Element => {
|
||||
const { devServerConfig } = useTuonoContextServerPayload()
|
||||
const { host, port } = devServerConfig ?? DEFAULT_SERVER_CONFIG
|
||||
const { host, origin, port } = devServerConfig ?? DEFAULT_SERVER_CONFIG
|
||||
|
||||
const viteBaseUrl = `http://${host}:${port}${VITE_PROXY_PATH}`
|
||||
const viteBaseUrl =
|
||||
origin != null
|
||||
? `${origin}${VITE_PROXY_PATH}`
|
||||
: `http://${host}:${port}${VITE_PROXY_PATH}`
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ServerPayload<TData = unknown> {
|
||||
/** Available only on 'Dev' mode */
|
||||
devServerConfig?: {
|
||||
port: number
|
||||
origin: string | null
|
||||
host: string
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user