mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
feat: add origin config option (#582)
Co-authored-by: Marco Pasqualetti <marco.pasqualetti@live.com>
This commit is contained in:
@@ -86,12 +86,18 @@ pub fn build(mut app: App, ssg: bool, no_js_emit: bool) {
|
|||||||
|
|
||||||
while !is_server_ready {
|
while !is_server_ready {
|
||||||
trace!("Checking server availability");
|
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() {
|
if reqwest_client.get(&server_url).send().is_ok() {
|
||||||
is_server_ready = true;
|
is_server_ready = true;
|
||||||
} else {
|
} else {
|
||||||
trace!("Server not ready yet. Sleeping for 1 second");
|
trace!("Server not ready yet. Sleeping for 1 second");
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(Duration::from_secs(1));
|
sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::path::PathBuf;
|
|||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
|
pub origin: Option<String>,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,30 @@ fn should_correctly_read_the_config_file() {
|
|||||||
|
|
||||||
let config = config.unwrap();
|
let config = config.unwrap();
|
||||||
assert_eq!(config.server.host, "localhost");
|
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);
|
assert_eq!(config.server.port, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,31 @@ pub struct Server {
|
|||||||
mode: Mode,
|
mode: Mode,
|
||||||
pub listener: tokio::net::TcpListener,
|
pub listener: tokio::net::TcpListener,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
|
pub origin: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
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 {
|
pub async fn init(router: Router, mode: Mode) -> Server {
|
||||||
let config = Config::get().expect("[SERVER] Failed to load config");
|
let config = Config::get().expect("[SERVER] Failed to load config");
|
||||||
|
|
||||||
@@ -44,6 +66,7 @@ impl Server {
|
|||||||
router,
|
router,
|
||||||
mode,
|
mode,
|
||||||
address: server_address.clone(),
|
address: server_address.clone(),
|
||||||
|
origin: config.server.origin.clone(),
|
||||||
listener: tokio::net::TcpListener::bind(&server_address)
|
listener: tokio::net::TcpListener::bind(&server_address)
|
||||||
.await
|
.await
|
||||||
.expect("[SERVER] Failed to bind to address"),
|
.expect("[SERVER] Failed to bind to address"),
|
||||||
@@ -51,14 +74,9 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(self) {
|
pub async fn start(self) {
|
||||||
/*
|
self.display_start_message();
|
||||||
* 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 {
|
if self.mode == Mode::Dev {
|
||||||
println!(" Ready at: {}\n", server_base_url.blue().bold());
|
|
||||||
let router = self
|
let router = self
|
||||||
.router
|
.router
|
||||||
.to_owned()
|
.to_owned()
|
||||||
@@ -74,10 +92,6 @@ impl Server {
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to serve development server");
|
.expect("Failed to serve development server");
|
||||||
} else {
|
} else {
|
||||||
println!(
|
|
||||||
" Production server at: {}\n",
|
|
||||||
server_base_url.blue().bold()
|
|
||||||
);
|
|
||||||
let router = self
|
let router = self
|
||||||
.router
|
.router
|
||||||
.to_owned()
|
.to_owned()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import fs from 'fs/promises'
|
import fs from 'node:fs/promises'
|
||||||
|
|
||||||
import { beforeEach, describe, expect, it, vitest } from 'vitest'
|
import { beforeEach, describe, expect, it, vitest } from 'vitest'
|
||||||
import react from '@vitejs/plugin-react-swc'
|
import react from '@vitejs/plugin-react-swc'
|
||||||
@@ -12,9 +12,9 @@ describe('createJsonConfig', () => {
|
|||||||
writeFileSpy.mockClear()
|
writeFileSpy.mockClear()
|
||||||
})
|
})
|
||||||
|
|
||||||
const sampleConfig = { server: { host: 'h', port: 1 } }
|
|
||||||
|
|
||||||
it('should process config with only server property', async () => {
|
it('should process config with only server property', async () => {
|
||||||
|
const sampleConfig = { server: { host: 'h', origin: null, port: 1 } }
|
||||||
|
|
||||||
await createJsonConfig(sampleConfig)
|
await createJsonConfig(sampleConfig)
|
||||||
|
|
||||||
expect(writeFileSpy).toHaveBeenCalledWith(
|
expect(writeFileSpy).toHaveBeenCalledWith(
|
||||||
@@ -25,6 +25,8 @@ describe('createJsonConfig', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should process config with plugins', async () => {
|
it('should process config with plugins', async () => {
|
||||||
|
const sampleConfig = { server: { host: 'h', origin: null, port: 1 } }
|
||||||
|
|
||||||
await createJsonConfig({ ...sampleConfig, vite: { plugins: [react()] } })
|
await createJsonConfig({ ...sampleConfig, vite: { plugins: [react()] } })
|
||||||
|
|
||||||
expect(writeFileSpy).toHaveBeenCalledWith(
|
expect(writeFileSpy).toHaveBeenCalledWith(
|
||||||
@@ -33,4 +35,16 @@ describe('createJsonConfig', () => {
|
|||||||
expect.any(String),
|
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 = {}
|
const config: TuonoConfig = {}
|
||||||
|
|
||||||
expect(normalizeConfig(config)).toStrictEqual({
|
expect(normalizeConfig(config)).toStrictEqual({
|
||||||
server: { host: 'localhost', port: 3000 },
|
server: {
|
||||||
|
host: 'localhost',
|
||||||
|
origin: null,
|
||||||
|
port: 3000,
|
||||||
|
},
|
||||||
vite: {
|
vite: {
|
||||||
alias: undefined,
|
alias: undefined,
|
||||||
css: undefined,
|
css: undefined,
|
||||||
@@ -28,7 +32,11 @@ describe('normalizeConfig', () => {
|
|||||||
it('should return an empty config if invalid values are provided', () => {
|
it('should return an empty config if invalid values are provided', () => {
|
||||||
// @ts-expect-error testing invalid config
|
// @ts-expect-error testing invalid config
|
||||||
expect(normalizeConfig({ invalid: true })).toStrictEqual({
|
expect(normalizeConfig({ invalid: true })).toStrictEqual({
|
||||||
server: { host: 'localhost', port: 3000 },
|
server: {
|
||||||
|
host: 'localhost',
|
||||||
|
origin: null,
|
||||||
|
port: 3000,
|
||||||
|
},
|
||||||
vite: {
|
vite: {
|
||||||
alias: undefined,
|
alias: undefined,
|
||||||
css: 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', () => {
|
describe('vite - alias', () => {
|
||||||
it('should not modify alias pointing to packages', () => {
|
it('should not modify alias pointing to packages', () => {
|
||||||
const libraryName = '@tabler/icons-react'
|
const libraryName = '@tabler/icons-react'
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ export const normalizeConfig = (config: TuonoConfig): InternalTuonoConfig => {
|
|||||||
return {
|
return {
|
||||||
server: {
|
server: {
|
||||||
host: config.server?.host ?? 'localhost',
|
host: config.server?.host ?? 'localhost',
|
||||||
|
origin: config.server?.origin ?? null,
|
||||||
port: config.server?.port ?? 3000,
|
port: config.server?.port ?? 3000,
|
||||||
},
|
},
|
||||||
vite: {
|
vite: {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type {
|
|||||||
export interface TuonoConfig {
|
export interface TuonoConfig {
|
||||||
server?: {
|
server?: {
|
||||||
host?: string
|
host?: string
|
||||||
|
origin?: string | null
|
||||||
port?: number
|
port?: number
|
||||||
}
|
}
|
||||||
vite?: {
|
vite?: {
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ import type { JSX } from 'react'
|
|||||||
import { useTuonoContextServerPayload } from './TuonoContext'
|
import { useTuonoContextServerPayload } from './TuonoContext'
|
||||||
|
|
||||||
const VITE_PROXY_PATH = '/vite-server'
|
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 => {
|
export const DevResources = (): JSX.Element => {
|
||||||
const { devServerConfig } = useTuonoContextServerPayload()
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface ServerPayload<TData = unknown> {
|
|||||||
/** Available only on 'Dev' mode */
|
/** Available only on 'Dev' mode */
|
||||||
devServerConfig?: {
|
devServerConfig?: {
|
||||||
port: number
|
port: number
|
||||||
|
origin: string | null
|
||||||
host: string
|
host: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user