Hoosat Create is a full-stack server-side rendered (SSR) TypeScript React stack designed to provide a seamless development experience with a clear separation between the client and server. Developed by Hoosat Oy, this stack offers a robust set of features to accelerate web application development.
To create a new project using Hoosat Create, simply run the following command:
npx hoosat-create@latest
The npx script will prompt you with questions to configure your project, and it will generate the initial project structure for you.
Once the project is created, navigate to the project directory:
cd project_name
To start the development server, use the following command:
npm run dev
This command will concurrently build the development version of the client and server and run the server to serve both the client and API routes. The application will be accessible at https://localhost:8080
in your browser.
npm run dev
: Builds and runs the development version.
npm run dev:build:client
: Builds the client in development mode and watches for file changes.npm run dev:build:server
: Builds the server in development mode and watches for file changes.npm run dev:run
: Starts the server with Nodemon to automatically restart it on file changes.npm run build
: Builds the production version.
npm run build:client
: Builds the client in production mode.npm run build:server
: Builds the server in production mode.npm run start
: Runs the production version.
npm run test
: Runs test units with Jest.
src/client
: Contains client-side code (React components, styles, etc.).src/server
: Contains server-side code (Node HTTP/HTTPS routes, API routes, etc.).src/common
: Contains common code.public
: Contains public files for the project.build
: Contains build output of server and client, the public
folder is moved into here.File: ./src/server/index.tsx
import React from 'react';
import App from '../client/App';
import { StaticRouter } from 'react-router-dom/server';
import { HelmetProvider } from 'react-helmet-async';
import { I18nextProvider } from 'react-i18next';
import i18n from './core/i18n';
import { cors } from './core/cors';
import { createRouter, createServer, listen } from './core/server';
import { assets } from './core/assets';
import { upload } from './core/upload';
import { pingRouter } from './api-routes/ping';
import { renderer } from './core/renderer';
// Create a router
const router = createRouter();
router.UseRouter(pingRouter);
/**
* Middleware to handle CORS for allowed origins and HTTP methods.
* @function
* @param {string} origins - The allowed origins, separated by commas.
* @param {string} methods - The allowed HTTP methods, separated by commas.
*/
router.Middleware(cors(process.env.ORIGINS || "localhost:8080", 'GET, POST, PUT, DELETE'));
/**
* Middleware to serve static files from the "public" directory.
* @function
* @param {string} publicDir - The path to the "public" directory.
*/
router.Middleware(assets(process.env.PUBLIC! || "./build/public"));
/**
* Middleware to handle multipart/form-data file uploading.
* @function
* @param {string} publicDir - The path to the "public" directory for uploads.
*/
router.Middleware(upload(process.env.PUBLIC! || "./build/public/uploads"));
/**
* POST route to handle file uploads.
* @function
* @param {Object} req - The request object.
* @param {Object} res - The response object.
*/
router.Post('/upload', (req, res) => {
// Access the uploaded files through req.files
console.log(req.files);
// Since the file upload was handled globally by middleware send a response.
res.status(200).json({ result: "success", files: req.files });
});
/**
* GET route to handle all other requests.
* @function
* @param {Object} req - The request object.
* @param {Object} res - The response object.
*/
router.Get("*", async (req, res) => {
const helmetContext = {};
/**
* Represents the JSX element for the server-side rendering.
* @type {JSX.Element}
*/
const jsx =
<React.StrictMode>
<I18nextProvider i18n={i18n}>
<HelmetProvider context={helmetContext}>
<html lang="FI-fi">
<head>
<meta charSet="utf-8" />
<link rel="icon" href="/logo/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="/manifest.json" />
</head>
<body>
{/* Mounting the App component inside the StaticRouter */}
<div id="root">
<StaticRouter location={req.url!}>
<App />
</StaticRouter>
</div>
</body>
</html>
</HelmetProvider>
</I18nextProvider>
</React.StrictMode>;
renderer({
res: res,
jsx: jsx,
helmetContext: helmetContext,
extractCSS: true,
preloadTagFolder: './build/public',
headTags: {}
});
});
// Create the server
const server = createServer(router);
// Start listening on port 8080
const port = parseInt(process.env.PORT || "8080");
listen(server, port, () => {
console.log(`Server is running on port ${port}`);
});
This template is licensed under the MIT License. Feel free to use it for your own projects or as a starting point for your own templates.
Generated using TypeDoc