@jcannon98188/vite-plugin-node 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +3 -0
- package/dist/rollup-plugin-swc.d.ts +3 -0
- package/dist/rollup-plugin-swc.js +28 -0
- package/dist/server/express.d.ts +3 -0
- package/dist/server/express.js +3 -0
- package/dist/server/fastify.d.ts +3 -0
- package/dist/server/fastify.js +4 -0
- package/dist/server/index.d.ts +13 -0
- package/dist/server/index.js +71 -0
- package/dist/server/koa.d.ts +3 -0
- package/dist/server/koa.js +3 -0
- package/dist/server/marble.d.ts +9 -0
- package/dist/server/marble.js +4 -0
- package/dist/server/nest.d.ts +3 -0
- package/dist/server/nest.js +18 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +40 -0
- package/dist/vite-plugin-node.d.ts +3 -0
- package/dist/vite-plugin-node.js +75 -0
- package/package.json +64 -0
- package/readme.md +180 -0
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 Axe
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
2
|
+
import type { Options } from "@swc/core";
|
3
|
+
import type { Connect, UserConfig, ViteDevServer } from "vite";
|
4
|
+
export { RollupPluginSwc } from "./rollup-plugin-swc.js";
|
5
|
+
export { VitePluginNode } from "./vite-plugin-node.js";
|
6
|
+
export declare const PLUGIN_NAME = "@jcannon98188/vite-plugin-node";
|
7
|
+
export declare type SupportedFrameworks = "express" | "nest" | "koa" | "fastify" | "marble";
|
8
|
+
export declare interface RequestAdapterParams<App> {
|
9
|
+
app: App;
|
10
|
+
server: ViteDevServer;
|
11
|
+
req: IncomingMessage;
|
12
|
+
res: ServerResponse;
|
13
|
+
next: Connect.NextFunction;
|
14
|
+
}
|
15
|
+
export declare type RequestAdapter<App = any> = (params: RequestAdapterParams<App>) => void | Promise<void>;
|
16
|
+
export declare type RequestAdapterOption = SupportedFrameworks | RequestAdapter;
|
17
|
+
export declare type SupportedTSCompiler = "esbuild" | "swc";
|
18
|
+
export type InternalModuleFormat = "amd" | "cjs" | "es" | "iife" | "system" | "umd";
|
19
|
+
export type ModuleFormat = InternalModuleFormat | "commonjs" | "esm" | "module" | "systemjs";
|
20
|
+
export interface VitePluginNodeConfig {
|
21
|
+
appPath: string;
|
22
|
+
adapter: RequestAdapterOption;
|
23
|
+
appName?: string;
|
24
|
+
initAppOnBoot?: boolean;
|
25
|
+
exportName?: string;
|
26
|
+
tsCompiler?: SupportedTSCompiler;
|
27
|
+
swcOptions?: Options;
|
28
|
+
outputFormat?: ModuleFormat;
|
29
|
+
}
|
30
|
+
export declare interface ViteConfig extends UserConfig {
|
31
|
+
VitePluginNodeConfig: VitePluginNodeConfig;
|
32
|
+
}
|
package/dist/index.js
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
import { createFilter } from "@rollup/pluginutils";
|
2
|
+
import { cleanUrl } from "./utils.js";
|
3
|
+
export function RollupPluginSwc(options) {
|
4
|
+
let swc;
|
5
|
+
// todo: load swc/tsconfig from config files
|
6
|
+
const config = {
|
7
|
+
// options from swc config
|
8
|
+
...options,
|
9
|
+
};
|
10
|
+
const filter = createFilter(/\.(tsx?|jsx)$/, /\.js$/);
|
11
|
+
return {
|
12
|
+
name: "rollup-plugin-swc",
|
13
|
+
async transform(code, id) {
|
14
|
+
if (filter(id) || filter(cleanUrl(id))) {
|
15
|
+
if (!swc)
|
16
|
+
swc = await import("@swc/core").then(({ Compiler }) => new Compiler());
|
17
|
+
const result = await swc.transform(code, {
|
18
|
+
...config,
|
19
|
+
filename: id,
|
20
|
+
});
|
21
|
+
return {
|
22
|
+
code: result.code,
|
23
|
+
map: result.map,
|
24
|
+
};
|
25
|
+
}
|
26
|
+
},
|
27
|
+
};
|
28
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
2
|
+
import type { Connect, ViteDevServer } from "vite";
|
3
|
+
import type { RequestAdapter, VitePluginNodeConfig } from "../index.js";
|
4
|
+
export declare const debugServer: (msg: string, ...args: unknown[]) => void;
|
5
|
+
export declare const SUPPORTED_FRAMEWORKS: {
|
6
|
+
express: RequestAdapter<import("express").Application>;
|
7
|
+
nest: RequestAdapter<import("@nestjs/common").INestApplication>;
|
8
|
+
koa: RequestAdapter<import("koa")<import("koa").DefaultState, import("koa").DefaultContext>>;
|
9
|
+
fastify: RequestAdapter<import("fastify").FastifyInstance<import("fastify").RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, import("fastify").FastifyLoggerInstance>>;
|
10
|
+
marble: RequestAdapter<import("./marble.js").MarbleContext>;
|
11
|
+
};
|
12
|
+
export declare const getPluginConfig: (server: ViteDevServer) => Promise<VitePluginNodeConfig>;
|
13
|
+
export declare const createMiddleware: (server: ViteDevServer) => Promise<Connect.HandleFunction>;
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import { exit } from "node:process";
|
2
|
+
import chalk from "chalk";
|
3
|
+
import { PLUGIN_NAME } from "../index.js";
|
4
|
+
import { createDebugger } from "../utils.js";
|
5
|
+
import { ExpressHandler } from "./express.js";
|
6
|
+
import { FastifyHandler } from "./fastify.js";
|
7
|
+
import { KoaHandler } from "./koa.js";
|
8
|
+
import { MarbleHandler } from "./marble.js";
|
9
|
+
import { NestHandler } from "./nest.js";
|
10
|
+
export const debugServer = createDebugger("vite:node-plugin:server");
|
11
|
+
export const SUPPORTED_FRAMEWORKS = {
|
12
|
+
express: ExpressHandler,
|
13
|
+
nest: NestHandler,
|
14
|
+
koa: KoaHandler,
|
15
|
+
fastify: FastifyHandler,
|
16
|
+
marble: MarbleHandler,
|
17
|
+
};
|
18
|
+
const env = { command: "serve", mode: "" };
|
19
|
+
export const getPluginConfig = async (server) => {
|
20
|
+
const plugin = server.config.plugins.find((p) => p.name === PLUGIN_NAME);
|
21
|
+
let userConfig = null;
|
22
|
+
if (typeof plugin.config === "function")
|
23
|
+
userConfig = (await plugin.config({}, env)) ?? undefined;
|
24
|
+
if (userConfig)
|
25
|
+
return userConfig.VitePluginNodeConfig;
|
26
|
+
console.error("Please setup VitePluginNode in your vite.config.js first");
|
27
|
+
exit(1);
|
28
|
+
};
|
29
|
+
const getRequestHandler = (handler) => {
|
30
|
+
if (typeof handler === "function") {
|
31
|
+
debugServer(chalk.dim `using custom server handler`);
|
32
|
+
return handler;
|
33
|
+
}
|
34
|
+
debugServer(chalk.dim `creating ${handler} node server`);
|
35
|
+
return SUPPORTED_FRAMEWORKS[handler];
|
36
|
+
};
|
37
|
+
export const createMiddleware = async (server) => {
|
38
|
+
const config = await getPluginConfig(server);
|
39
|
+
const logger = server.config.logger;
|
40
|
+
const requestHandler = getRequestHandler(config.adapter);
|
41
|
+
async function _loadApp(config) {
|
42
|
+
const appModule = await server.ssrLoadModule(config.appPath);
|
43
|
+
if (!config.exportName) {
|
44
|
+
throw new Error("exportName is required in VitePluginNodeConfig");
|
45
|
+
}
|
46
|
+
let app = appModule[config.exportName];
|
47
|
+
if (!app) {
|
48
|
+
logger.error(`Failed to find a named export ${config.exportName} from ${config.appPath}`);
|
49
|
+
process.exit(1);
|
50
|
+
}
|
51
|
+
else {
|
52
|
+
// some app may be created with a function returning a promise
|
53
|
+
app = await app;
|
54
|
+
return app;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
if (!requestHandler) {
|
58
|
+
console.error("Failed to find a request handler");
|
59
|
+
process.exit(1);
|
60
|
+
}
|
61
|
+
if (config.initAppOnBoot) {
|
62
|
+
server.httpServer?.once("listening", async () => {
|
63
|
+
await _loadApp(config);
|
64
|
+
});
|
65
|
+
}
|
66
|
+
return async (req, res, next) => {
|
67
|
+
const app = await _loadApp(config);
|
68
|
+
if (app)
|
69
|
+
await requestHandler({ app, server, req, res, next });
|
70
|
+
};
|
71
|
+
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import type { Context, ServerIO } from "@marblejs/core";
|
2
|
+
import type { HttpListener, HttpServer } from "@marblejs/http";
|
3
|
+
import type { Reader } from "fp-ts/Reader";
|
4
|
+
import type { RequestAdapter } from "../index.js";
|
5
|
+
export interface MarbleContext {
|
6
|
+
server: Promise<ServerIO<HttpServer>>;
|
7
|
+
listener: Reader<Context, HttpListener>;
|
8
|
+
}
|
9
|
+
export declare const MarbleHandler: RequestAdapter<MarbleContext>;
|
@@ -0,0 +1,18 @@
|
|
1
|
+
let prevApp;
|
2
|
+
export const NestHandler = async ({ app, req, res, }) => {
|
3
|
+
// @ts-expect-error nest app typing error
|
4
|
+
if (!app.isInitialized) {
|
5
|
+
if (prevApp)
|
6
|
+
await prevApp.close();
|
7
|
+
await app.init();
|
8
|
+
prevApp = app;
|
9
|
+
}
|
10
|
+
const instance = app.getHttpAdapter().getInstance();
|
11
|
+
if (typeof instance === "function") {
|
12
|
+
instance(req, res);
|
13
|
+
}
|
14
|
+
else {
|
15
|
+
const fastifyApp = await instance.ready();
|
16
|
+
fastifyApp.routing(req, res);
|
17
|
+
}
|
18
|
+
};
|
package/dist/utils.d.ts
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
export declare function createDebugger(ns: string): (msg: string, ...args: unknown[]) => void;
|
2
|
+
export declare const queryRE: RegExp;
|
3
|
+
export declare const hashRE: RegExp;
|
4
|
+
export declare const cleanUrl: (url: string) => string;
|
5
|
+
export declare function isObject(item: any): item is object;
|
6
|
+
export default function mergeDeep(target: object, source: object): object;
|
package/dist/utils.js
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
/**
|
2
|
+
* modified from vitejs source code, just to make the console output looks vite-like
|
3
|
+
*/
|
4
|
+
import debug from "debug";
|
5
|
+
export function createDebugger(ns) {
|
6
|
+
const log = debug(ns);
|
7
|
+
return (msg, ...args) => {
|
8
|
+
log(msg, ...args);
|
9
|
+
};
|
10
|
+
}
|
11
|
+
export const queryRE = /\?.*$/;
|
12
|
+
export const hashRE = /#.*$/;
|
13
|
+
export const cleanUrl = (url) => url.replace(hashRE, "").replace(queryRE, "");
|
14
|
+
// biome-ignore lint/suspicious/noExplicitAny: Function is a typeguard.
|
15
|
+
export function isObject(item) {
|
16
|
+
return item && typeof item === "object" && !Array.isArray(item);
|
17
|
+
}
|
18
|
+
export default function mergeDeep(target, source) {
|
19
|
+
const output = Object.assign({}, target);
|
20
|
+
if (isObject(target) && isObject(source)) {
|
21
|
+
for (const key of Object.keys(source)) {
|
22
|
+
// @ts-expect-error access unknow property
|
23
|
+
if (isObject(source[key])) {
|
24
|
+
if (!(key in target)) {
|
25
|
+
// @ts-expect-error access unknow property
|
26
|
+
Object.assign(output, { [key]: source[key] });
|
27
|
+
}
|
28
|
+
else {
|
29
|
+
// @ts-expect-error access unknow property
|
30
|
+
output[key] = mergeDeep(target[key], source[key]);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
// @ts-expect-error access unknow property
|
35
|
+
Object.assign(output, { [key]: source[key] });
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
return output;
|
40
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { PLUGIN_NAME } from "./index.js";
|
2
|
+
import { RollupPluginSwc } from "./rollup-plugin-swc.js";
|
3
|
+
import { createMiddleware } from "./server/index.js";
|
4
|
+
import mergeDeep from "./utils.js";
|
5
|
+
export function VitePluginNode(cfg) {
|
6
|
+
const swcOptions = mergeDeep({
|
7
|
+
module: {
|
8
|
+
type: "es6",
|
9
|
+
},
|
10
|
+
jsc: {
|
11
|
+
target: "es2019",
|
12
|
+
parser: {
|
13
|
+
syntax: "typescript",
|
14
|
+
decorators: true,
|
15
|
+
},
|
16
|
+
transform: {
|
17
|
+
legacyDecorator: true,
|
18
|
+
decoratorMetadata: true,
|
19
|
+
},
|
20
|
+
},
|
21
|
+
}, cfg.swcOptions ?? {});
|
22
|
+
const config = {
|
23
|
+
appPath: cfg.appPath,
|
24
|
+
adapter: cfg.adapter,
|
25
|
+
appName: cfg.appName ?? "app",
|
26
|
+
tsCompiler: cfg.tsCompiler ?? "swc",
|
27
|
+
exportName: cfg.exportName ?? "viteNodeApp",
|
28
|
+
initAppOnBoot: cfg.initAppOnBoot ?? false,
|
29
|
+
outputFormat: cfg.outputFormat ?? "module",
|
30
|
+
swcOptions,
|
31
|
+
};
|
32
|
+
const plugins = [
|
33
|
+
{
|
34
|
+
name: PLUGIN_NAME,
|
35
|
+
config: () => {
|
36
|
+
const plugincConfig = {
|
37
|
+
build: {
|
38
|
+
ssr: config.appPath,
|
39
|
+
rollupOptions: {
|
40
|
+
input: config.appPath,
|
41
|
+
output: {
|
42
|
+
format: config.outputFormat,
|
43
|
+
},
|
44
|
+
},
|
45
|
+
},
|
46
|
+
server: {
|
47
|
+
hmr: false,
|
48
|
+
},
|
49
|
+
optimizeDeps: {
|
50
|
+
noDiscovery: true,
|
51
|
+
// Vite does not work well with optionnal dependencies,
|
52
|
+
// mark them as ignored for now
|
53
|
+
exclude: ["@swc/core"],
|
54
|
+
},
|
55
|
+
VitePluginNodeConfig: config,
|
56
|
+
};
|
57
|
+
if (config.tsCompiler === "swc")
|
58
|
+
plugincConfig.esbuild = false;
|
59
|
+
return plugincConfig;
|
60
|
+
},
|
61
|
+
configureServer: async (server) => {
|
62
|
+
server.middlewares.use(await createMiddleware(server));
|
63
|
+
},
|
64
|
+
},
|
65
|
+
];
|
66
|
+
if (config.tsCompiler === "swc") {
|
67
|
+
if (!config.swcOptions) {
|
68
|
+
throw new Error("swcOptions is required when using swc as tsCompiler");
|
69
|
+
}
|
70
|
+
plugins.push({
|
71
|
+
...RollupPluginSwc(config.swcOptions),
|
72
|
+
});
|
73
|
+
}
|
74
|
+
return plugins;
|
75
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
{
|
2
|
+
"name": "@jcannon98188/vite-plugin-node",
|
3
|
+
"version": "6.0.2",
|
4
|
+
"description": "Vite plugin to enable your node server HMR, forked and maintained by jcannon98188",
|
5
|
+
"author": "Axe, Fork by Jason Cannon",
|
6
|
+
"license": "MIT",
|
7
|
+
"type": "module",
|
8
|
+
"repository": {
|
9
|
+
"type": "git",
|
10
|
+
"url": "git+https://github.com/jcannon98188/vite-plugin-node.git"
|
11
|
+
},
|
12
|
+
"bugs": {
|
13
|
+
"url": "https://github.com/jcannon98188/vite-plugin-node/issues"
|
14
|
+
},
|
15
|
+
"homepage": "https://github.com/jcannon98188/vite-plugin-node#readme",
|
16
|
+
"keywords": ["vite", "vite-plugin", "node", "hmr"],
|
17
|
+
"main": "dist/index.js",
|
18
|
+
"files": ["dist", "readme.md"],
|
19
|
+
"scripts": {
|
20
|
+
"build-dist": "tsc",
|
21
|
+
"build": "run-s prebuild build-dist",
|
22
|
+
"dev": "tsc -w --incremental",
|
23
|
+
"lint": "npx @biomejs/biome lint --write .",
|
24
|
+
"format": "npx @biomesjs/biome format --write .",
|
25
|
+
"prebuild": "rimraf dist && npm run lint && cp ../../README.md ./readme.md"
|
26
|
+
},
|
27
|
+
"dependencies": {
|
28
|
+
"@rollup/pluginutils": "^5.1.4",
|
29
|
+
"chalk": "^4.1.2",
|
30
|
+
"debug": "^4.3.2"
|
31
|
+
},
|
32
|
+
"peerDependencies": {
|
33
|
+
"@swc/core": "^1.7.26",
|
34
|
+
"vite": "^6.0.0"
|
35
|
+
},
|
36
|
+
"peerDependenciesMeta": {
|
37
|
+
"@swc/core": {
|
38
|
+
"optional": true
|
39
|
+
}
|
40
|
+
},
|
41
|
+
"devDependencies": {
|
42
|
+
"@biomejs/biome": "1.9.4",
|
43
|
+
"@marblejs/core": "^4.0.2",
|
44
|
+
"@marblejs/http": "^4.0.2",
|
45
|
+
"@nestjs/common": "^8.0.9",
|
46
|
+
"@swc/core": "^1.7.26",
|
47
|
+
"@types/debug": "^4.1.7",
|
48
|
+
"@types/estree": "^0.0.50",
|
49
|
+
"@types/express": "^4.17.13",
|
50
|
+
"@types/koa": "^2.13.4",
|
51
|
+
"@types/node": "^18.19.55",
|
52
|
+
"@types/rx": "^4.1.2",
|
53
|
+
"express": "^4.17.1",
|
54
|
+
"fastify": "^3.22.0",
|
55
|
+
"fp-ts": "^2.8.2",
|
56
|
+
"koa": "^2.13.3",
|
57
|
+
"npm-run-all": "^4.1.5",
|
58
|
+
"reflect-metadata": "^0.1.13",
|
59
|
+
"rimraf": "^3.0.2",
|
60
|
+
"rxjs": "^7.5.5",
|
61
|
+
"typescript": "^5.7.3",
|
62
|
+
"vite": "^6.1.0"
|
63
|
+
}
|
64
|
+
}
|
package/readme.md
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="./node-vite.png" width="200px">
|
3
|
+
</p>
|
4
|
+
<p align="center">
|
5
|
+
<a href="https://www.npmjs.com/package/@jcannon98188/vite-plugin-node"><img src="https://img.shields.io/npm/v/@jcannon98188/vite-plugin-node.svg" alt="npm package"></a>
|
6
|
+
<a href="https://nodejs.org/en/about/releases/"><img src="https://img.shields.io/node/v/@jcannon98188/vite-plugin-node.svg" alt="node compatibility"></a>
|
7
|
+
</p>
|
8
|
+
|
9
|
+
# Vite Plugin Node
|
10
|
+
|
11
|
+
> A [vite](https://vitejs.dev/) plugin to allow you to use vite as node dev server.
|
12
|
+
|
13
|
+
## Features
|
14
|
+
|
15
|
+
- All the perks from Vite plus:
|
16
|
+
- Node server HMR! (hot module replacement)
|
17
|
+
- Support Express, Fastify, Koa and Nest out of the box
|
18
|
+
- Support Custom Request Adapter
|
19
|
+
- You can choose to use `esbuild` or `swc` to compile your typescript files
|
20
|
+
|
21
|
+
## Get started
|
22
|
+
|
23
|
+
---
|
24
|
+
|
25
|
+
1. Install vite and this plugin with your favorite package manager, here use npm as example:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
npm install vite @jcannon98188/vite-plugin-node -D
|
29
|
+
```
|
30
|
+
|
31
|
+
2. Create a `vite.config.ts` file in your project root to config vite to actually use this plugin:
|
32
|
+
|
33
|
+
```ts
|
34
|
+
import { defineConfig } from 'vite';
|
35
|
+
import { VitePluginNode } from '@jcannon98188/vite-plugin-node';
|
36
|
+
|
37
|
+
export default defineConfig({
|
38
|
+
// ...vite configures
|
39
|
+
server: {
|
40
|
+
// vite server configs, for details see [vite doc](https://vitejs.dev/config/#server-host)
|
41
|
+
port: 3000
|
42
|
+
},
|
43
|
+
plugins: [
|
44
|
+
...VitePluginNode({
|
45
|
+
// Nodejs native Request adapter
|
46
|
+
// currently this plugin support 'express', 'nest', 'koa' and 'fastify' out of box,
|
47
|
+
// you can also pass a function if you are using other frameworks, see Custom Adapter section
|
48
|
+
adapter: 'express',
|
49
|
+
|
50
|
+
// tell the plugin where is your project entry
|
51
|
+
appPath: './app.ts',
|
52
|
+
|
53
|
+
// Optional, default: 'viteNodeApp'
|
54
|
+
// the name of named export of you app from the appPath file
|
55
|
+
exportName: 'viteNodeApp',
|
56
|
+
|
57
|
+
// Optional, default: false
|
58
|
+
// if you want to init your app on boot, set this to true
|
59
|
+
initAppOnBoot: false,
|
60
|
+
|
61
|
+
// Optional, default: 'esbuild'
|
62
|
+
// The TypeScript compiler you want to use
|
63
|
+
// by default this plugin is using vite default ts compiler which is esbuild
|
64
|
+
// 'swc' compiler is supported to use as well for frameworks
|
65
|
+
// like Nestjs (esbuild dont support 'emitDecoratorMetadata' yet)
|
66
|
+
// you need to INSTALL `@swc/core` as dev dependency if you want to use swc
|
67
|
+
tsCompiler: 'esbuild',
|
68
|
+
|
69
|
+
// Optional, default: {
|
70
|
+
// jsc: {
|
71
|
+
// target: 'es2019',
|
72
|
+
// parser: {
|
73
|
+
// syntax: 'typescript',
|
74
|
+
// decorators: true
|
75
|
+
// },
|
76
|
+
// transform: {
|
77
|
+
// legacyDecorator: true,
|
78
|
+
// decoratorMetadata: true
|
79
|
+
// }
|
80
|
+
// }
|
81
|
+
// }
|
82
|
+
// swc configs, see [swc doc](https://swc.rs/docs/configuration/swcrc)
|
83
|
+
swcOptions: {}
|
84
|
+
})
|
85
|
+
],
|
86
|
+
});
|
87
|
+
```
|
88
|
+
|
89
|
+
3. Update your server entry to export your app named `viteNodeApp` or the name you configured.
|
90
|
+
|
91
|
+
### [ExpressJs](./examples/express/app.ts)
|
92
|
+
|
93
|
+
```ts
|
94
|
+
const app = express();
|
95
|
+
|
96
|
+
// your beautiful code...
|
97
|
+
|
98
|
+
if (import.meta.env.PROD)
|
99
|
+
app.listen(3000);
|
100
|
+
|
101
|
+
export const viteNodeApp = app;
|
102
|
+
```
|
103
|
+
#### More Examples:
|
104
|
+
- [KoaJs](./examples/koa/app.ts)
|
105
|
+
- [Cloud Functions](./examples/cloudfunction/app.ts)
|
106
|
+
- [Fastify](./examples/fastify/app.ts)
|
107
|
+
- [NestJs](./examples/nest/src/main.ts)
|
108
|
+
- [Apollo Server](./examples/apollo/app.ts)
|
109
|
+
|
110
|
+
4. Add a npm script to run the dev server:
|
111
|
+
|
112
|
+
```json
|
113
|
+
"scripts": {
|
114
|
+
"dev": "vite"
|
115
|
+
},
|
116
|
+
```
|
117
|
+
|
118
|
+
5. Run the script! `npm run dev`
|
119
|
+
|
120
|
+
## Custom Adapter
|
121
|
+
|
122
|
+
If your favorite framework not supported yet, you can either create an issue to request it or use the `adapter` option to tell the plugin how to pass down the request to your app. You can take a look how the supported frameworks implementations from the `./src/server` folder.
|
123
|
+
Example:
|
124
|
+
|
125
|
+
```ts
|
126
|
+
import { defineConfig } from 'vite';
|
127
|
+
import { VitePluginNode } from '@jcannon98188/vite-plugin-node';
|
128
|
+
|
129
|
+
export default defineConfig({
|
130
|
+
plugins: [
|
131
|
+
...VitePluginNode({
|
132
|
+
adapter({ app, server, req, res, next }) {
|
133
|
+
app(res, res);
|
134
|
+
},
|
135
|
+
appPath: './app.ts'
|
136
|
+
})
|
137
|
+
]
|
138
|
+
});
|
139
|
+
```
|
140
|
+
|
141
|
+
## Build
|
142
|
+
This plugin leverages Vite SSR mode to build your app. All you need to do is add a build script to your package.json:
|
143
|
+
|
144
|
+
```json
|
145
|
+
"scripts": {
|
146
|
+
"build": "vite build"
|
147
|
+
},
|
148
|
+
```
|
149
|
+
For more build config please check [vite doc](https://vitejs.dev/config/#build-target)
|
150
|
+
|
151
|
+
> Note: By default, starting from vite v3, the ssr buildle will be in esm format. if you want to build cjs, add `ssr: { format: 'cjs' }` to your vite config.
|
152
|
+
|
153
|
+
## Examples
|
154
|
+
|
155
|
+
See the examples folder.
|
156
|
+
|
157
|
+
## Why?
|
158
|
+
|
159
|
+
---
|
160
|
+
|
161
|
+
While frontend development tooling is evolving rapidly in recent years, backend DX is still like in stone age. No hot module replacement; Typescript recompiling slow as funk; Lack of plugin system etc. Thanks to Vite.js created by Evan You (A.K.A creator of vue.js; my biggest idol developer), makes all those dreams for backend development come true!
|
162
|
+
|
163
|
+
## How?
|
164
|
+
|
165
|
+
---
|
166
|
+
|
167
|
+
Vite by design has a middleware mode, which allows us to use it programmatically inside other modules. It's originally made for SSR, so that for each request, vite can load the renderer and render the latest changes you made to your app (<https://vitejs.dev/guide/ssr.html>). This plugin leverages this feature to load and execute your server app entry.
|
168
|
+
|
169
|
+
You may ask, isn't super slow, since it re-compiles/reloads the entire app? The answer is NO, because vite is smart. It has a builtin module graph as a cache layer, the graph is built up the first time your app loads. After that, when you update a file, vite will only invalidate that one and its parent modules, so that for next request, only those invalidated modules need to be re-compiled which is super fast thanks to esbuild or swc.
|
170
|
+
|
171
|
+
## To-Do
|
172
|
+
|
173
|
+
As this plugin just fresh developed, there are still lots ideas need to be implemented, including:
|
174
|
+
|
175
|
+
- [ ] Test with a large node project, I need y'all helps on this!
|
176
|
+
- [ ] Unit tests
|
177
|
+
|
178
|
+
## Bugs
|
179
|
+
|
180
|
+
Please create an issue if you found any bugs, to help me improve this project!
|