aaex-cli 1.4.1 → 2.0.1

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/.env ADDED
@@ -0,0 +1 @@
1
+ AAEX_SKIP_POSTINSTALL=true
package/README.md CHANGED
@@ -1,20 +1,27 @@
1
1
  # AaExJS
2
- ## V.1.0.0
2
+
3
+ ## V.2.0.1
4
+
5
+ Bug fix for css modules
6
+
3
7
  ## Description
8
+
4
9
  Light weight SSR framework for react with filebased page and api routing. Builds on Vitejs alreadt existing SSR functionality.
5
10
 
6
11
  ## Features
12
+
7
13
  - File routing using aaex-file-router (can be used seperatly)
8
14
  - API routing using hybrid solution only available in the full framework
9
15
  - SSR rendering using vites native functions + additional functionality
10
16
  - full typescript support (currently only typescript)
11
17
  - all vite plugins that work with ssr should work
12
18
 
19
+ ## Known issues:
20
+
21
+ - tailwindcss dosnt work as excpected
13
22
 
14
23
  ## Usage
24
+
15
25
  ```sh
16
26
  npx create-aaex-app <project-name>
17
- ```
18
-
19
- ## V1.4
20
- Added server side data loading
27
+ ```
@@ -3,51 +3,41 @@
3
3
  import fs from "fs-extra";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import inquirer from "inquirer";
7
+ import chalk from "chalk";
6
8
 
7
- // -------------------------
8
- // Helpers for ESM __dirname
9
- // -------------------------
9
+ // ESM __dirname
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
12
 
13
- // -------------------------
14
13
  // Parse CLI arguments
15
- // -------------------------
16
14
  const args = process.argv.slice(2);
17
15
  if (!args[0]) {
18
- console.error("Usage: create-aaex-app <project-name>");
16
+ console.error(chalk.red("Usage: create-aaex-app <project-name>"));
19
17
  process.exit(1);
20
18
  }
21
19
  const appName = args[0];
22
20
  const targetDir = path.resolve(process.cwd(), appName);
23
21
 
24
- // -------------------------
25
- // Paths inside the package
26
- // -------------------------
22
+ // Paths inside package
27
23
  const templateDir = path.resolve(__dirname, "template");
28
24
 
29
- // -------------------------
30
25
  // Copy template files
31
- // -------------------------
32
- async function copyTemplate() {
26
+ async function copyTemplate(database = "MongoDB") {
33
27
  try {
34
- console.log(`Creating new AAEx app in ${targetDir}...`);
35
-
28
+ console.log(chalk.blue(`\nCreating new AAEx app in ${targetDir}...\n`));
29
+ console.log(chalk.cyan(`With ${database} as DB driver`));
36
30
  await fs.copy(templateDir, targetDir, {
37
31
  overwrite: true,
38
32
  errorOnExist: false,
39
33
  });
40
-
41
- console.log("Template copied successfully.");
42
34
  } catch (err) {
43
- console.error("Error copying template:", err);
35
+ console.error(chalk.red("Error copying template:"), err);
44
36
  process.exit(1);
45
37
  }
46
38
  }
47
39
 
48
- // -------------------------
49
40
  // Create package.json
50
- // -------------------------
51
41
  async function createPackageJson() {
52
42
  const pkg = {
53
43
  name: appName,
@@ -73,11 +63,12 @@ async function createPackageJson() {
73
63
  express: "^5.1.0",
74
64
  compression: "^1.8.1",
75
65
  sirv: "^3.0.2",
76
- "aaex-file-router": "^1.5.0",
66
+ "aaex-file-router": "^2.0.0",
77
67
  jsonwebtoken: "^9.0.3",
78
68
  mongodb: "^7.0.0",
79
69
  bcrypt: "^6.0.0",
80
70
  dotenv: "^17.2.3",
71
+ "aaexjs": "^2.0.0"
81
72
  },
82
73
  devDependencies: {
83
74
  typescript: "~5.9.2",
@@ -96,27 +87,48 @@ async function createPackageJson() {
96
87
  await fs.writeJson(path.join(targetDir, "package.json"), pkg, {
97
88
  spaces: 2,
98
89
  });
99
- console.log("package.json created.");
100
90
  } catch (err) {
101
- console.error("Error creating package.json:", err);
91
+ console.error(chalk.red("Error creating package.json:"), err);
102
92
  process.exit(1);
103
93
  }
104
94
  }
105
95
 
106
- // -------------------------
107
- // Run
108
- // -------------------------
96
+ // Main
109
97
  async function main() {
110
98
  if (fs.existsSync(targetDir)) {
111
- console.error(`Folder ${appName} already exists. Aborting.`);
99
+ console.error(chalk.red(`Folder ${appName} already exists. Aborting.`));
112
100
  process.exit(1);
113
101
  }
114
102
 
115
- await copyTemplate();
103
+ // Interaktiv fråga
104
+ const answers = await inquirer.prompt([
105
+ {
106
+ type: "select",
107
+ name: "database",
108
+ message: "Which database do you want to use?",
109
+ choices: [
110
+ "MongoDB",
111
+ "MySQL - not implemented",
112
+ "PostgreSQL - not implemented",
113
+ ],
114
+ default: 0,
115
+ },
116
+ ]);
117
+
118
+ if (answers.database !== "MongoDB") {
119
+ console.log(
120
+ chalk.yellow(`Currently only MongoDB is supported. Aborting...`)
121
+ );
122
+ process.exit(0);
123
+ }
124
+
125
+ await copyTemplate(answers.database);
116
126
  await createPackageJson();
117
127
 
118
- console.log("\n AAEx app created successfully!");
119
- console.log(`\nNext steps:\n cd ${appName}\n npm install\n npm run dev`);
128
+ console.log(chalk.green.bold("\nAAEx app created successfully!"));
129
+ console.log(
130
+ chalk.blue(`\nNext steps:\n cd ${appName}\n npm install\n npm run dev\n`)
131
+ );
120
132
  }
121
133
 
122
134
  main();
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "aaex-cli",
3
- "version": "1.4.1",
3
+ "version": "2.0.1",
4
4
  "description": "Command line interface for creating aaexjs app",
5
5
  "license": "ISC",
6
6
  "author": "",
7
7
  "type": "module",
8
8
  "bin": {
9
- "create-aaex-app": "./create-aaex-app.js"
9
+ "create-aaex-app": "create-aaex-app.js"
10
10
  },
11
11
  "scripts": {
12
12
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -31,6 +31,11 @@
31
31
  "vite": "^7.2.6"
32
32
  },
33
33
  "dependencies": {
34
- "fs-extra": "^11.3.2"
34
+ "chalk": "^5.6.2",
35
+ "fs-extra": "^11.3.2",
36
+ "inquirer": "^13.1.0"
37
+ },
38
+ "peerDependencies": {
39
+ "aaexjs": "2.0.1"
35
40
  }
36
41
  }
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from "react";
2
- import { getCookie } from "../../.aaex/utils/cookies";
2
+ import { getCookie } from "aaexjs/cookies";
3
3
  import { CookieUser } from "../models/User";
4
4
 
5
5
  export function useAuth() {
@@ -1,5 +1,5 @@
1
1
  import { useState } from "react";
2
- import { setCookie } from "../../.aaex/utils/cookies";
2
+ import { setCookie } from "aaexjs/cookies";
3
3
  import { LoginUser } from "../models/User";
4
4
 
5
5
  export default function Login() {
@@ -13,8 +13,8 @@
13
13
  ".aaex/api",
14
14
  "src/api",
15
15
  ".aaex/utils",
16
- "src/server-routes.ts",
17
- "src/hooks"
16
+ "src/hooks",
17
+ "./vite-env.d.ts"
18
18
  ],
19
19
  "exclude": ["node_modules", "dist"]
20
20
  }
@@ -1,7 +1,7 @@
1
1
  import { defineConfig } from "vite";
2
2
  import react from "@vitejs/plugin-react";
3
3
  import { aaexServerRouter } from "aaex-file-router/plugin";
4
- import { pluginSsrDevFoucFix } from "./.aaex/utils/ServerLoadCssImports";
4
+ import { pluginSsrDevFoucFix } from "aaexjs-test";
5
5
 
6
6
  // https://vite.dev/config/
7
7
  export default defineConfig({
@@ -1,67 +0,0 @@
1
- import { FileScanner } from "aaex-file-router/core";
2
- import { match } from "path-to-regexp";
3
-
4
- // --- scan folders ---
5
- //wrapper for the FilesScanner and output data
6
- async function scanApiFolder(folder) {
7
- const scanner = new FileScanner(folder);
8
- return await scanner.get_file_data();
9
- }
10
-
11
- const userApiFolder = "src/api";
12
-
13
- const internalApiFolder = ".aaex/api";
14
-
15
- //collect file data as easily parsed arrays
16
- const [userFiles, internalFiles] = await Promise.all([
17
- scanApiFolder(userApiFolder),
18
- scanApiFolder(internalApiFolder),
19
- ]);
20
-
21
- // --- combine files ---
22
- const fileMap = new Map();
23
- internalFiles.forEach((f) => fileMap.set(f.relative_path, f));
24
- userFiles.forEach((f) => fileMap.set(f.relative_path, f)); //overrides internal api with user defined routes
25
- const combinedFiles = Array.from(fileMap.values());
26
-
27
- // --- build route list ---
28
- /**Builds route object from the scanned files */
29
- function buildApiRoutes(files) {
30
- const routes = [];
31
-
32
- function walk(node, currentPath) {
33
- //recursivly iterate over child routes
34
- if (node.isDirectory) {
35
- node.children?.forEach((c) => walk(c, currentPath + "/" + node.name));
36
- return;
37
- }
38
- const filePath = currentPath + "/" + node.name;
39
- //build route path from filePath
40
- let route = filePath
41
- .replace(/^.*(src\/api|api)/, "/api") //removed parent folder like src
42
- .replace(/\.ts|js$/, "") //removes file extension
43
- .replace(/\[(.+?)\]/g, ":$1") //converts [slug] to :slug
44
- .replace("/index", "");
45
-
46
- routes.push({ route, filePath: node.relative_path });
47
- }
48
-
49
- files.forEach((file) => walk(file, ""));
50
- return routes;
51
- }
52
-
53
- const routes = buildApiRoutes(combinedFiles);
54
-
55
- // --- match path to route ---
56
- /** Matches the given path to API routes generated from the api folder + the aaex/api folder*/
57
- function pathToRoute(pathname) {
58
- for (const r of routes) {
59
- const matcher = match(r.route, { decode: decodeURIComponent });
60
- const matched = matcher(pathname);
61
- if (matched) return { route: r, params: matched.params };
62
- }
63
- return null;
64
- }
65
-
66
- // --- export ---
67
- export { routes, pathToRoute };
@@ -1,57 +0,0 @@
1
- import { connectToDatabase } from "../../framework/database/mongodb";
2
- import type { Request, Response } from "express";
3
- import bcrypt from "bcrypt";
4
- import jwt from "jsonwebtoken";
5
- import { LoginUser } from "../../../src/models/User";
6
-
7
- export const POST = async (req: Request, res: Response) => {
8
- const { email, password }: LoginUser = req.body;
9
-
10
- if (!email || !password) {
11
- return res.status(400).json({ error: "Missing fields!" });
12
- }
13
-
14
- const { db } = await connectToDatabase();
15
-
16
- if (!process.env.JWT_SECRET) {
17
- console.error("Missing: JWT_SECRET from environment variables");
18
- return res
19
- .status(500)
20
- .json({ error: "Internal server error! Try again later" });
21
- }
22
-
23
- const normalizedEmail = email.trim().toLowerCase();
24
- const user = await db.collection("users").findOne({ email: normalizedEmail });
25
-
26
- if (!user) {
27
- return res.status(400).json({ error: "Invalid email or password" });
28
- }
29
-
30
- const compared = await bcrypt.compare(password, user.password);
31
-
32
- if (!compared) {
33
- return res.status(400).json({ error: "Invalid email or password" });
34
- }
35
-
36
- const expiration = process.env.JWT_EXP ?? "24h";
37
-
38
- const token = jwt.sign(
39
- {
40
- id: user._id.toString(),
41
- email: user.email,
42
- username: user.username,
43
- },
44
- process.env.JWT_SECRET as string,
45
- { expiresIn: expiration as any } //fixes stupid thing where it wont accept the sring variable because its not number | ms.stringvlue | undefined
46
- );
47
-
48
- return res.status(200).json({
49
- ok: true,
50
- user: {
51
- id: user._id.toString(),
52
- name: user.username,
53
- email: user.email,
54
- },
55
- token,
56
- });
57
- };
@@ -1,34 +0,0 @@
1
- import { Request, Response } from "express";
2
- import bcrypt from "bcrypt";
3
- import { connectToDatabase } from "../../framework/database/mongodb";
4
- import { CreateUser } from "../../../src/models/User";
5
- export const POST = async (req: Request, res: Response) => {
6
-
7
- const { email, username, password, confirmPass }: CreateUser = req.body;
8
-
9
- if (!username || !email || !password || !confirmPass)
10
- return res.status(400).json({ error: "Missing fields" });
11
-
12
- if (password !== confirmPass)
13
- return res.status(400).json({ error: "Passwords do not match" });
14
-
15
- const { db } = await connectToDatabase();
16
-
17
- const exists = await db.collection("users").findOne({ email });
18
- if (exists)
19
- return res
20
- .status(409)
21
- .json({ error: "User with that email already exists" });
22
-
23
- const salt = 10;
24
- const hashed = await bcrypt.hash(password, salt);
25
-
26
- await db.collection("users").insertOne({
27
- username,
28
- email,
29
- password: hashed,
30
- createdAt: new Date(),
31
- });
32
-
33
- return res.status(201).json({ ok: true });
34
- };
@@ -1,18 +0,0 @@
1
- import jwt from "jsonwebtoken";
2
- import type { Request, Response } from "express";
3
-
4
- export async function POST(req: Request, res: Response) {
5
- const { token } = req.body;
6
-
7
- if (!process.env.JWT_SECRET) {
8
- console.error("Missing: JWT_SECRET from environment");
9
- return res.status(500).json({error: "Internal server error!"});
10
- }
11
-
12
- try {
13
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
14
- return res.status(200).json({ valid: true, user: decoded });
15
- } catch (err) {
16
- return res.status(401).json({ valid: false });
17
- }
18
- }
@@ -1,29 +0,0 @@
1
- import { MongoClient, Db } from "mongodb";
2
-
3
- const MONGO_URI = process.env.MONGO_URI || "mongodb://localhost:27017";
4
- const DB_NAME = process.env.DB_NAME || "mydatabase";
5
-
6
- if (!MONGO_URI) {
7
- throw new Error("Please define the MONGO_URI environment variable inside .env");
8
- }
9
-
10
- let cachedClient: MongoClient | null = null;
11
- let cachedDb: Db | null = null;
12
-
13
- export async function connectToDatabase(): Promise<{ client: MongoClient; db: Db }> {
14
- // Return cached connection if it exists
15
- if (cachedClient && cachedDb) {
16
- return { client: cachedClient, db: cachedDb };
17
- }
18
-
19
- const client = new MongoClient(MONGO_URI);
20
- await client.connect();
21
- const db = client.db(DB_NAME);
22
-
23
- cachedClient = client;
24
- cachedDb = db;
25
-
26
- console.log("MongoDB connected:", DB_NAME);
27
-
28
- return { client, db };
29
- }
@@ -1,16 +0,0 @@
1
- import "../../src/index.css";
2
- import { StrictMode } from "react";
3
- import { hydrateRoot } from "react-dom/client";
4
- import App from "../../src/App";
5
- import { BrowserRouter } from "react-router";
6
-
7
- const initialData = (window as any).__INITIAL_DATA__;
8
-
9
- hydrateRoot(
10
- document.getElementById("root") as HTMLElement,
11
- <StrictMode>
12
- <BrowserRouter>
13
- <App initialData={initialData} />
14
- </BrowserRouter>
15
- </StrictMode>
16
- );
@@ -1,18 +0,0 @@
1
- import { StrictMode, Suspense } from "react";
2
- import { renderToString } from "react-dom/server";
3
- import { StaticRouter } from "react-router";
4
- import App from "../../src/App";
5
-
6
- export function render(_url: string, initialData= {}) {
7
- const url = `${_url}`;
8
-
9
-
10
- const html = renderToString(
11
- <StrictMode>
12
- <StaticRouter location={url}>
13
- <App initialData={initialData} />
14
- </StaticRouter>
15
- </StrictMode>
16
- );
17
- return { html };
18
- }
@@ -1,60 +0,0 @@
1
- export default function routeMatcher(routes, url) {
2
- const segments = url.split("/").filter(Boolean); // "test/hej" → ["test", "hej"]
3
-
4
- return matchLevel(routes, segments);
5
- }
6
-
7
- function matchLevel(routes, segments) {
8
- for (const route of routes) {
9
- const result = matchRoute(route, segments);
10
-
11
- if (result) return result;
12
- }
13
-
14
- return null;
15
- }
16
-
17
- function matchRoute(route, segments) {
18
- const isParam = /^:[a-zA-Z0-9_]+$/;
19
-
20
- const [current, ...rest] = segments;
21
-
22
- // Root index route
23
- if (route.path === "" && segments.length === 0) {
24
- return { route, params: {} };
25
- }
26
-
27
- // Static match
28
- if (route.path === current) {
29
- if (rest.length === 0) {
30
- return { route, params: {} };
31
- }
32
-
33
- // Has children → go deeper
34
- if (route.children) {
35
- return matchLevel(route.children, rest);
36
- }
37
- }
38
-
39
- // Dynamic match → :slug , :id osv
40
- if (isParam.test(route.path)) {
41
- const paramName = route.path.slice(1);
42
-
43
- if (rest.length === 0) {
44
- return { route, params: { [paramName]: current } };
45
- }
46
-
47
- // Has children → go deeper
48
- if (route.children) {
49
- const matchedChild = matchLevel(route.children, rest);
50
- if (matchedChild) {
51
- return {
52
- route: matchedChild.route,
53
- params: { [paramName]: current, ...matchedChild.params },
54
- };
55
- }
56
- }
57
- }
58
-
59
- return null;
60
- }
@@ -1,179 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import express from "express";
3
- import { pathToFileURL } from "node:url";
4
- import path from "node:path";
5
- import dotenv from "dotenv";
6
- dotenv.config();
7
-
8
- // server.js is now in .aaex/server/
9
- const projectRoot = path.resolve("."); // root of the project
10
- let serverRoutes;
11
- // Import BuildApiRoutes
12
- import * as BuildApiRoutes from "../BuildApiRoutes.js";
13
- import routeMatcher from "../matchServerRoutes.js";
14
-
15
- const apiRoutes = BuildApiRoutes.default; // default export
16
- const PathToRoute = BuildApiRoutes.pathToRoute; // named export
17
-
18
- // Constants
19
- const isProduction = process.env.NODE_ENV === "production";
20
- const port = process.env.PORT || 5173;
21
- const base = process.env.BASE || "/";
22
-
23
- // Cached production HTML
24
- const templateHtml = isProduction
25
- ? await fs.readFile(path.join(projectRoot, "dist/client/index.html"), "utf-8")
26
- : "";
27
-
28
- // Create HTTP server
29
- const app = express();
30
-
31
- /** @type {import('vite').ViteDevServer | undefined} */
32
- let vite;
33
- if (!isProduction) {
34
- const { createServer } = await import("vite");
35
- vite = await createServer({
36
- server: { middlewareMode: true },
37
- appType: "custom",
38
- root: projectRoot,
39
- base,
40
- });
41
- serverRoutes = (await vite.ssrLoadModule("/src/server-routes.ts")).default;
42
- app.use(vite.middlewares);
43
- } else {
44
- const compression = (await import("compression")).default;
45
- const sirv = (await import("sirv")).default;
46
- app.use(compression());
47
- app.use(
48
- base,
49
- sirv(path.join(projectRoot, "dist/client"), { extensions: [] })
50
- );
51
-
52
- const serverRoutesModule = await import(
53
- pathToFileURL(path.join(projectRoot, "dist/src/server-routes.js")).href
54
- );
55
-
56
- serverRoutes = serverRoutesModule.default;
57
- }
58
-
59
- // parse JSON bodies
60
- app.use(express.json());
61
-
62
- // parse URL-encoded bodies (optional, for form POSTs)
63
- app.use(express.urlencoded({ extended: true }));
64
-
65
- // API routing
66
- app.use("/api", async (req, res) => {
67
- const routeMatch = PathToRoute(req.path, apiRoutes);
68
-
69
- if (!routeMatch)
70
- return res.status(404).json({ error: "API route not found" });
71
-
72
- const { route, params } = routeMatch;
73
- let modulePath;
74
-
75
- if (!isProduction) {
76
- // DEV: Vite handles TS/JS loading
77
- if (route.filePath.split("/")[0] == ".aaex") {
78
- modulePath = `${route.filePath.replace(/^src\/api/, "")}`;
79
- } else {
80
- modulePath = `/src/api${route.filePath.replace(/^src\/api/, "")}`;
81
- }
82
- } else {
83
- // PROD: bundled JS
84
- modulePath = pathToFileURL(
85
- `./dist/server/api${route.filePath
86
- .replace(/^src\/api/, "")
87
- .replace(/\.ts$/, ".js")}`
88
- ).href;
89
- }
90
-
91
- try {
92
- const mod = !isProduction
93
- ? await vite.ssrLoadModule(modulePath)
94
- : await import(modulePath);
95
-
96
- const handler = mod[req.method]; // GET, POST, etc.
97
-
98
- if (typeof handler !== "function") {
99
- return res.status(405).json({ error: "Method not allowed" });
100
- }
101
-
102
- const result = await handler(req, res, params);
103
-
104
- if (!res.headersSent) res.json(result);
105
- } catch (err) {
106
- console.error("API load error:", err);
107
- res.status(500).json({ error: "Internal Server Error" });
108
- }
109
- });
110
-
111
- // SSR HTML
112
- app.use(/.*/, async (req, res) => {
113
- try {
114
- let url = req.originalUrl;
115
-
116
- const routeMatch = routeMatcher(serverRoutes, url);
117
-
118
- if (!routeMatch) {
119
- return res.status(404).send("Not found");
120
- }
121
-
122
- // Dynamicly import the file
123
- const mod = await vite.ssrLoadModule(routeMatch.route.modulePath);
124
-
125
- // Call load if it exist
126
- let initialData = {};
127
- if (mod.load) {
128
- initialData = await mod.load(routeMatch.params);
129
- }
130
-
131
- let template;
132
- let render;
133
- if (!isProduction) {
134
- template = await fs.readFile(
135
- path.join(projectRoot, "index.html"),
136
- "utf-8"
137
- );
138
- template = await vite.transformIndexHtml(url, template);
139
- render = (await vite.ssrLoadModule("/.aaex/framework/entry-server.tsx"))
140
- .render;
141
- } else {
142
- template = templateHtml;
143
- render = (
144
- await import(path.join(projectRoot, "dist/server/entry-server.js"))
145
- ).render;
146
- }
147
-
148
- const rendered = await render(url, initialData);
149
-
150
- function XSSPrevention(unsafeString) {
151
- return unsafeString.replace(/</g, "//u003c");
152
- // .replace(/>/g, "&gt")
153
- // .replace(/'/g, "&#39")
154
- // .replace(/"/g, "&#34");
155
- }
156
-
157
- const serializedData = JSON.stringify(initialData);
158
- const safeData = XSSPrevention(serializedData);
159
-
160
- const html = template
161
- .replace("<!--app-head-->", rendered.head ?? "")
162
- .replace("<!--app-html-->", rendered.html ?? "")
163
- .replace(
164
- "<!--initial-data-->",
165
- `<script>window.__INITIAL_DATA__ = ${safeData}</script>`
166
- );
167
-
168
- res.status(200).set({ "Content-Type": "text/html" }).send(html);
169
- } catch (e) {
170
- vite?.ssrFixStacktrace?.(e);
171
- console.error(e);
172
- res.status(500).send(e.stack);
173
- }
174
- });
175
-
176
- // Start server
177
- app.listen(port, () => {
178
- console.log(`Server started at http://localhost:${port}`);
179
- });
@@ -1,51 +0,0 @@
1
- //credit to https://github.com/vitejs/vite/issues/16515
2
-
3
- import type {Plugin, ViteDevServer} from 'vite';
4
-
5
- const virtualCssPath = '/@virtual:ssr-css.css';
6
-
7
- const collectedStyles = new Map<string, string>();
8
-
9
- export function pluginSsrDevFoucFix(): Plugin {
10
- let server: ViteDevServer;
11
-
12
- return {
13
- name: 'ssr-dev-FOUC-fix',
14
- apply: 'serve',
15
- transform(code: string, id: string) {
16
- if (id.includes('node_modules')) return null;
17
- if (id.includes('.css')) {
18
- collectedStyles.set(id, code);
19
- }
20
- return null;
21
- },
22
- configureServer(server_) {
23
- server = server_;
24
-
25
- server.middlewares.use((req, _res, next) => {
26
- if (req.url === virtualCssPath) {
27
- _res.setHeader('Content-Type', 'text/css');
28
- _res.write(Array.from(collectedStyles.values()).join('\n'));
29
- _res.end();
30
- return;
31
- }
32
- next();
33
- });
34
- },
35
-
36
- transformIndexHtml: {
37
- handler: async () => {
38
- return [
39
- {
40
- tag: 'link',
41
- injectTo: 'head',
42
- attrs: {
43
- rel: 'stylesheet',
44
- href: virtualCssPath,
45
- },
46
- },
47
- ];
48
- },
49
- },
50
- };
51
- }
@@ -1,63 +0,0 @@
1
- export function setCookie(
2
- name: string,
3
- value: string,
4
- days = 7,
5
- options: {
6
- path?: string;
7
- secure?: boolean;
8
- sameSite?: "Strict" | "Lax" | "None";
9
- domain?: string;
10
- } = {}
11
- ) {
12
- const maxAge = days * 24 * 60 * 60;
13
- const encoded = encodeURIComponent(value);
14
-
15
- let cookie = `${name}=${encoded}; max-age=${maxAge}; path=${
16
- options.path ?? "/"
17
- }`;
18
-
19
- if (options.secure) cookie += "; secure";
20
- if (options.sameSite) cookie += `; samesite=${options.sameSite}`;
21
- if (options.domain) cookie += `; domain=${options.domain}`;
22
-
23
- document.cookie = cookie;
24
- }
25
- export function getCookie(name: string) {
26
- const cookies = document.cookie.split("; ");
27
-
28
- for (const c of cookies) {
29
- const [key, ...rest] = c.split("=");
30
- if (key === name) {
31
- return decodeURIComponent(rest.join("="));
32
- }
33
- }
34
-
35
- return null;
36
- }
37
-
38
- function cookieToJSON(cookie: string) {
39
- const parts = cookie.split("; ");
40
- const result: Record<string, string> = {};
41
-
42
- for (const part of parts) {
43
- const [key, ...rest] = part.split("=");
44
- result[key] = rest.join("=");
45
- }
46
-
47
- return result;
48
- }
49
-
50
- export function getCookieAsJSON(name: string) {
51
- const raw = getCookie(name);
52
- if (!raw) return null;
53
- return cookieToJSON(raw);
54
- }
55
-
56
- export function deleteCookie(
57
- name: string,
58
- options: { path?: string; domain?: string } = {}
59
- ) {
60
- let cookie = `${name}=; max-age=0; path=${options.path ?? "/"}`;
61
- if (options.domain) cookie += `; domain=${options.domain}`;
62
- document.cookie = cookie;
63
- }
package/template/.env DELETED
@@ -1,5 +0,0 @@
1
- # edit to fit your needs
2
- MONGO_URI="mongodb://localhost:27018/"
3
- DB_NAME="mydatabase"
4
- JWT_SECRET="your-jwt-secret"
5
- JWT_EXP="24h"
@@ -1,3 +0,0 @@
1
- node_modules
2
- .env
3
- .aaex
@@ -1,33 +0,0 @@
1
- //* AUTO GENERATED: DO NOT EDIT
2
- import React from 'react';
3
- import Index from './pages/index.tsx';
4
- import Login from './pages/login.tsx';
5
- import Register from './pages/register.tsx';
6
- import Slug from './pages/test/[slug].tsx';
7
- import type { RouteObject } from 'react-router-dom';
8
-
9
- const routes: RouteObject[] = [
10
- {
11
- "path": "",
12
- "element": React.createElement(Index)
13
- },
14
- {
15
- "path": "login",
16
- "element": React.createElement(Login)
17
- },
18
- {
19
- "path": "register",
20
- "element": React.createElement(Register)
21
- },
22
- {
23
- "path": "test",
24
- "children": [
25
- {
26
- "path": ":slug",
27
- "element": React.createElement(Slug)
28
- }
29
- ]
30
- }
31
- ];
32
-
33
- export default routes;
@@ -1,7 +0,0 @@
1
- // AUTO-GENERATED: DO NOT EDIT
2
- export type FileRoutes =
3
- | "/"
4
- | "/login"
5
- | "/register"
6
- | "/test"
7
- | "/test/{string}";
@@ -1,37 +0,0 @@
1
- //* AUTO GENERATED: DO NOT EDIT
2
- import React from 'react';
3
- import Index from './pages/index.tsx';
4
- import Login from './pages/login.tsx';
5
- import Register from './pages/register.tsx';
6
- import Slug from './pages/test/[slug].tsx';
7
-
8
-
9
- const serverRoutes: any[] = [
10
- {
11
- "path": "",
12
- "element": Index,
13
- "modulePath": "C:/Users/tmraa/OneDrive/Dokument/AaExJS-documentation/test-app/src/pages/index.tsx"
14
- },
15
- {
16
- "path": "login",
17
- "element": Login,
18
- "modulePath": "C:/Users/tmraa/OneDrive/Dokument/AaExJS-documentation/test-app/src/pages/login.tsx"
19
- },
20
- {
21
- "path": "register",
22
- "element": Register,
23
- "modulePath": "C:/Users/tmraa/OneDrive/Dokument/AaExJS-documentation/test-app/src/pages/register.tsx"
24
- },
25
- {
26
- "path": "test",
27
- "children": [
28
- {
29
- "path": ":slug",
30
- "element": Slug,
31
- "modulePath": "C:/Users/tmraa/OneDrive/Dokument/AaExJS-documentation/test-app/src/pages/test/[slug].tsx"
32
- }
33
- ]
34
- }
35
- ];
36
-
37
- export default serverRoutes;
File without changes