# Vite plugin ssr
Like Next.js/Nuxt but as do-one-thing-do-it-well Vite plugin.
Use any UI framework (React, Vue, Svelte, Solid, ...) and any tool you want (any frontend library, web technology, deploy environment, Vite plugin, ...).
With vite-plugin-ssr
, you integrate tools manually and keep architectural control
.
Note
Vike replace the vite-plugin-ssr
package. Ts.ED provides @tsed/vite-ssr-plugin
and @tsed/vike
packages.
All new features will only embed to @tsed/vike
package.
To migrate @tsed/vite-ssr-plugin
, just replace @tsed/vite-ssr-plugin
by @tsed/vike
in your code and install vike
dependency instead of vite-plugin-ssr
.
TIP
You can read also this article over Ts.ED + Vite-plugin-ssr on Medium: https://romainlenzotti.medium.com/use-vite-and-ts-ed-to-build-your-website-84fb4c0d8079
# Features
- Use
@Vite
decorator to generate a page usingvite-plugin-ssr
- Render a page using any UI framework (React, Vue, Svelte, Solid, ...)
# Quick start
# Installation
npm install vite-plugin-ssr @tsed/vite-ssr-plugin vite@4 --save
Then edit your Server.ts
:
import {join} from "path";
import {Configuration, Inject} from "@tsed/di";
import {PlatformApplication} from "@tsed/common";
import "@tsed/platform-express"; // /!\ keep this import
import "@tsed/vite-ssr-plugin"; // add this
import "@tsed/ajv";
import "@tsed/swagger";
import {config} from "./config";
import * as rest from "./controllers/rest";
import * as pages from "./controllers/pages";
@Configuration({
vite: {
root: "../path/to/app/project"
}
})
export class Server {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
We recommend you to start your project with the starter project (opens new window).
The start project is a monorepo (Nx) with 2 projects:
packages/server
: the backend projectpackages/server/controllers/pages
: the controllers pages directorypackages/server/controllers/rest
: the controllers Rest directory
packages/app
: the frontend projectpackages/app/pages
: the pages directorypackages/app/renderer
: the app shell directory (header, footer, layout, etc...)
# Usage
import {Constant, Controller} from "@tsed/di";
import {HeaderParams} from "@tsed/platform-params";
import {Vite} from "@tsed/vite-ssr-plugin";
import {SwaggerSettings} from "@tsed/swagger";
import {Get, Hidden, Returns} from "@tsed/schema";
@Hidden()
@Controller("/")
export class IndexController {
@Constant("swagger")
private swagger: SwaggerSettings[];
@Get("/")
@Vite()
@Returns(200, String).ContentType("text/html")
get(@HeaderParams("x-forwarded-proto") protocol: string, @HeaderParams("host") host: string) {
const hostUrl = `${protocol || "http"}://${host}`;
return {
docs: this.swagger.map((conf) => {
return {
url: hostUrl + conf.path,
...conf
};
})
};
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
And his React component:
import React from "react";
import {PageContext} from "../../renderer/types";
import type {SwaggerSettings} from "@tsed/swagger"; // ! keep type import
export interface HomePageProps {
docs: ({url: string} & SwaggerSettings)[];
}
export function Page({docs}: PageContext & HomePageProps) {
return (
<>
<h1>Welcome,</h1>
<p>This page is built with Ts.ED and vite-plugin-ssr.</p>
<br />
<br />
<ul>
{docs.map((doc) => {
return (
<li>
<a href={doc.path}>
<span>OpenSpec {doc.specVersion}</span>
</a>
</li>
);
})}
</ul>
</>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Result:
# Add a controlled page
By default, vite-plugin-ssr does Filesystem Routing:
FILESYSTEM URL
pages/index.page.js /
pages/about.page.js /about
pages/faq/index.page.js /faq
pages/movies/@id/index.page.js /movies/1, /movies/2, /movies/3, ...
2
3
4
5
So if you want to expose a movies page with the following url /movies
url, create a new
file packages/app/pages/movies/index.page.tsx
:
import React from "react";
import {PageContext} from "../../renderer/types";
interface Movie {
id: string;
title: string;
}
export interface MoviesPageProps {
movies: Movie[];
}
export function Page({movies}: PageContext & MoviesPageProps) {
return (
<>
<h1>Movies,</h1>
<ul>
{movies.map((doc) => {
return (
<li>
<a href={"/movies/" + movies.id}>
<span>{movies.title}</span>
</a>
</li>
);
})}
</ul>
</>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
TIP
You can also define so-called "Route Strings" and "Route Functions".
// /pages/movies.page.route.js
// This file defines the route of `/pages/movies.page.js`
// Route String
export default "/movies/@movieId";
2
3
4
5
6
Then create a new Ts.ED controller MoviesController
under packages/server/src/controllers/pages
to handle all
request that match the "/movies" route:
import {Controller, Get} from "@tsed/common";
class Movie {
@Property()
id: string;
@Property()
title: string;
}
@Controller("/movies")
export class MoviesController {
@Get("/")
@Returns(200, Array).Of(Movie)
@Vite()
get() {
return [
{id: "1", title: "Movie 1"},
{id: "2", title: "Movie 2"},
{id: "3", title: "Movie 3"}
];
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Author
# Maintainers Help wanted
Last Updated: 10/5/2024, 7:24:49 PM
Other topics
- Session & cookies
- Passport.js
- Keycloak
- Prisma
- TypeORM
- MikroORM
- Mongoose
- GraphQL
- GraphQL WS
- Apollo
- TypeGraphQL
- GraphQL Nexus
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Serverless HTTP
- Seq
- OIDC
- Stripe
- Agenda
- Terminus
- Serverless
- Server-sent events
- IORedis
- Vike
- Jest
- Vitest
- Controllers
- Providers
- Model
- JsonMapper
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Exceptions
- Throw HTTP Exceptions
- Cache
- Command
- Response Filter
- Injection scopes
- Custom providers
- Lazy-loading provider
- Custom endpoint decorator
- Testing
- Customize 404