mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 21:02:45 -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 {
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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