feat: generate main file from tuono dev cmd

This commit is contained in:
Valerio Ageno
2024-05-25 17:59:27 +02:00
parent 9550f8243c
commit 2348576fa4
7 changed files with 135 additions and 8 deletions
+10 -5
View File
@@ -1,6 +1,8 @@
use clap::{Parser, Subcommand};
use std::process::Command;
mod axum_source_builder;
mod source_builder;
use source_builder::{bundle_axum_source, create_client_entry_files};
mod watch;
#[derive(Subcommand, Debug)]
@@ -24,11 +26,14 @@ pub fn cli() {
let args = Args::parse();
match args.action.unwrap() {
Actions::Dev => watch::watch().unwrap(),
Actions::Dev => {
bundle_axum_source();
create_client_entry_files().unwrap();
watch::watch().unwrap();
}
Actions::Build => {
axum_source_builder::bundle_axum_source();
println!("Build JS source");
bundle_axum_source();
create_client_entry_files().unwrap();
let mut vite_build = Command::new("./node_modules/.bin/tuono-build-prod");
let _ = &vite_build.output().unwrap();
}
@@ -1,11 +1,30 @@
use glob::glob;
use std::collections::HashMap;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::path::PathBuf;
const ROOT_FOLDER: &'static str = "src/routes";
const DEV_FOLDER: &'static str = ".tuono";
const SERVER_ENTRY_DATA: &'static str = "// File automatically generated by tuono
import { routeTree } from './routeTree.gen'
import { serverSideRendering } from 'tuono/ssr'
export const renderFn = serverSideRendering(routeTree)
";
const CLIENT_ENTRY_DATA: &'static str = "// File automatically generated by tuono
import { hydrate } from 'tuono/hydration'
// Import the generated route tree
import { routeTree } from './routeTree.gen'
hydrate(routeTree)
";
enum Mode {
Prod,
@@ -159,3 +178,14 @@ pub fn bundle_axum_source() {
create_main_file(&base_path, &bundled_file);
}
pub fn create_client_entry_files() -> io::Result<()> {
let dev_folder = Path::new(DEV_FOLDER);
let mut server_entry = fs::File::create(&dev_folder.join("server-main.tsx"))?;
let mut client_entry = fs::File::create(&dev_folder.join("client-main.tsx"))?;
server_entry.write(SERVER_ENTRY_DATA.as_bytes())?;
client_entry.write(CLIENT_ENTRY_DATA.as_bytes())?;
Ok(())
}
+1 -2
View File
@@ -6,7 +6,7 @@ use watchexec::Watchexec;
use watchexec_signals::Signal;
use watchexec_supervisor::job::start_job;
use crate::axum_source_builder::bundle_axum_source;
use crate::source_builder::bundle_axum_source;
// What is the development pipeline?
//
@@ -22,7 +22,6 @@ use crate::axum_source_builder::bundle_axum_source;
#[tokio::main]
pub async fn watch() -> Result<()> {
bundle_axum_source();
let (watch_client, _) = start_job(Arc::new(Command {
program: Program::Exec {
prog: "node_modules/.bin/tuono-dev-watch".into(),
+21
View File
@@ -25,6 +25,26 @@
"default": "./dist/cjs/build/index.js"
}
},
"./ssr": {
"import": {
"types": "./dist/esm/ssr/index.d.ts",
"default": "./dist/esm/ssr/index.js"
},
"require": {
"types": "./dist/cjs/ssr/index.d.ts",
"default": "./dist/cjs/ssr/index.js"
}
},
"./hydration": {
"import": {
"types": "./dist/esm/hydration/index.d.ts",
"default": "./dist/esm/hydration/index.js"
},
"require": {
"types": "./dist/cjs/ssr/index.d.ts",
"default": "./dist/cjs/ssr/index.js"
}
},
".": {
"import": {
"types": "./dist/esm/index.d.ts",
@@ -65,6 +85,7 @@
"@types/babel__core": "^7.20.5",
"@types/node": "^20.12.7",
"@vitejs/plugin-react-swc": "^3.7.0",
"fast-text-encoding": "^1.0.6",
"prettier": "^3.2.4",
"vite": "^5.2.11",
"zustand": "4.4.7"
+19
View File
@@ -0,0 +1,19 @@
import 'vite/modulepreload-polyfill'
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider, createRouter } from '../router'
export function hydrate(routeTree: any) {
// Create a new router instance
const router = createRouter({ routeTree })
// Render the app
const rootElement = document.getElementById('__tuono')!
ReactDOM.hydrateRoot(
rootElement,
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
}
+48
View File
@@ -0,0 +1,48 @@
import 'fast-text-encoding' // Mandatory for React18
import * as React from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import { RouterProvider } from '../router'
import { createRouter } from '../router'
export function serverSideRendering(routeTree: any) {
return function render(payload: string | undefined): string {
const props = payload ? JSON.parse(payload) : {}
const router = createRouter({ routeTree }) // Render the app
const app = renderToString(
<RouterProvider router={router} serverProps={props} />,
)
const developmentScript = `<script type="module">
import RefreshRuntime from 'http://localhost:3001/@react-refresh'
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>
<script type="module" src="http://localhost:3001/@vite/client"></script>
<script type="module" src="http://localhost:3001/client-main.tsx"></script>`
return `<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Playground</title>
</head>
<body>
<div id="__tuono">${app}</div>
${renderToStaticMarkup(
<script
dangerouslySetInnerHTML={{
__html: `window.__TUONO_SSR_PROPS__=${payload}`,
}}
/>,
)}
${developmentScript}
</body>
</html>
`
}
}
+6 -1
View File
@@ -14,7 +14,12 @@ const config = defineConfig({
export default mergeConfig(
config,
tanstackBuildConfig({
entry: ['./src/index.ts', './src/build/index.ts'],
entry: [
'./src/index.ts',
'./src/build/index.ts',
'./src/ssr/index.tsx',
'./src/hydration/index.tsx',
],
srcDir: './src',
}),
)