@seip/blue-bird 0.2.7 → 0.3.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/backend/index.js +4 -3
- package/backend/routes/api.js +34 -0
- package/backend/routes/frontend.js +51 -0
- package/core/app.js +5 -5
- package/core/cli/init.js +3 -1
- package/core/cli/swagger.js +40 -0
- package/core/template.js +18 -13
- package/frontend/index.html +4 -1
- package/frontend/resources/js/App.jsx +42 -0
- package/frontend/resources/js/Main.jsx +18 -0
- package/frontend/resources/js/pages/About.jsx +16 -0
- package/frontend/resources/js/pages/Home.jsx +68 -0
- package/package.json +12 -4
- package/vite.config.js +22 -0
- package/backend/routes/app.js +0 -99
package/backend/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import App from "@seip/blue-bird/core/app.js";
|
|
2
|
-
import
|
|
2
|
+
import routerApiExample from "./routes/api.js";
|
|
3
|
+
import routerFrontendExample from "./routes/frontend.js";
|
|
3
4
|
|
|
4
5
|
const app = new App({
|
|
5
|
-
routes: [
|
|
6
|
+
routes: [routerApiExample, routerFrontendExample],
|
|
6
7
|
cors: [],
|
|
7
|
-
middlewares: [],
|
|
8
|
+
middlewares: [],
|
|
8
9
|
host: "http://localhost"
|
|
9
10
|
})
|
|
10
11
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Router from "@seip/blue-bird/core/router.js"
|
|
2
|
+
import Validator from "@seip/blue-bird/core/validate.js"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const routerApiExample = new Router("/")
|
|
6
|
+
|
|
7
|
+
routerApiExample.get("/users", (req, res) => {
|
|
8
|
+
const users = [
|
|
9
|
+
{
|
|
10
|
+
name: "John Doe",
|
|
11
|
+
email: "john.doe@example.com",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "Jane Doe2",
|
|
15
|
+
email: "jane.doe2@example.com",
|
|
16
|
+
},
|
|
17
|
+
]
|
|
18
|
+
res.json(users)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const loginSchema = {
|
|
22
|
+
email: { required: true, email: true },
|
|
23
|
+
password: { required: true, min: 6 }
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const loginValidator = new Validator(loginSchema, 'es');
|
|
27
|
+
|
|
28
|
+
routerApiExample.post('/login', loginValidator.middleware(), (req, res) => {
|
|
29
|
+
res.json({ message: 'Login successful' });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export default routerApiExample
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Router from "@seip/blue-bird/core/router.js"
|
|
2
|
+
import Template from "@seip/blue-bird/core/template.js"
|
|
3
|
+
|
|
4
|
+
const routerFrontendExample = new Router();
|
|
5
|
+
|
|
6
|
+
const routesFrontend = [
|
|
7
|
+
{
|
|
8
|
+
path: "/",
|
|
9
|
+
component: "Home",
|
|
10
|
+
meta: { titleMeta: "Home - Blue Bird", descriptionMeta: "Welcome to Blue Bird" },
|
|
11
|
+
props: { id: 1, name: "Name" }
|
|
12
|
+
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
path: "/about",
|
|
16
|
+
component: "About",
|
|
17
|
+
meta: { titleMeta: "About - Blue Bird", descriptionMeta: "About blue bird" },
|
|
18
|
+
props: { id: 2, name: "Name 2" }
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
];
|
|
22
|
+
routesFrontend.forEach(route_ => {
|
|
23
|
+
routerFrontendExample.get(route_.path, (req, res) => {
|
|
24
|
+
const dynamicProps = {
|
|
25
|
+
props: {
|
|
26
|
+
params: req.params,
|
|
27
|
+
query: req.query,
|
|
28
|
+
...route_.props ?? {}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return Template.renderReact(res, route_.component, dynamicProps, {
|
|
33
|
+
metaTags: route_.meta,
|
|
34
|
+
scriptsInBody: [{ src: "https://cdn.tailwindcss.com" }]
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
routerFrontendExample.get("*", (req, res) => {
|
|
41
|
+
const response = Template.renderReact(res, "App", { title: "404 - not found" },
|
|
42
|
+
{
|
|
43
|
+
scriptsInBody: [
|
|
44
|
+
{ "src": "https://cdn.tailwindcss.com" }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
return response;
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export default routerFrontendExample;
|
package/core/app.js
CHANGED
|
@@ -9,7 +9,7 @@ import helmet from "helmet"
|
|
|
9
9
|
import Config from "./config.js"
|
|
10
10
|
import Logger from "./logger.js"
|
|
11
11
|
import Debug from "./debug.js"
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
|
|
14
14
|
const __dirname = Config.dirname()
|
|
15
15
|
const props = Config.props()
|
|
@@ -35,7 +35,7 @@ class App {
|
|
|
35
35
|
* @param {boolean|Object} [options.rateLimit=false] - Enable global rate limiting.
|
|
36
36
|
* @param {boolean|Object} [options.helmet=true] - Enable Helmet security headers.
|
|
37
37
|
* @param {boolean} [options.xssClean=true] - Enable XSS body sanitization.
|
|
38
|
-
* @param {boolean|Object} [options.swagger=
|
|
38
|
+
* @param {boolean|Object} [options.swagger=false] - Enable swagger
|
|
39
39
|
* @example
|
|
40
40
|
* const app = new App({
|
|
41
41
|
* routes: [],
|
|
@@ -86,7 +86,7 @@ class App {
|
|
|
86
86
|
rateLimit: false,
|
|
87
87
|
helmet: false,
|
|
88
88
|
xssClean: true,
|
|
89
|
-
swagger:
|
|
89
|
+
swagger: false
|
|
90
90
|
|
|
91
91
|
}) {
|
|
92
92
|
this.app = express()
|
|
@@ -104,7 +104,7 @@ class App {
|
|
|
104
104
|
this.rateLimit = options.rateLimit ?? false
|
|
105
105
|
this.helmet = options.helmet ?? true
|
|
106
106
|
this.xssClean = options.xssClean ?? true
|
|
107
|
-
this.swagger = options.swagger ??
|
|
107
|
+
this.swagger = options.swagger ?? false
|
|
108
108
|
this.dispatch()
|
|
109
109
|
|
|
110
110
|
}
|
|
@@ -207,7 +207,7 @@ class App {
|
|
|
207
207
|
this.errorHandler();
|
|
208
208
|
|
|
209
209
|
if (this.swagger) {
|
|
210
|
-
|
|
210
|
+
const Swagger = import("./swagger.js")
|
|
211
211
|
const defaultSwaggerOptions = {
|
|
212
212
|
info: {
|
|
213
213
|
title: "Blue Bird API",
|
package/core/cli/init.js
CHANGED
|
@@ -68,7 +68,8 @@ class ProjectInit {
|
|
|
68
68
|
"react": "blue-bird react",
|
|
69
69
|
"init": "blue-bird",
|
|
70
70
|
"route": "blue-bird route",
|
|
71
|
-
"component": "blue-bird component"
|
|
71
|
+
"component": "blue-bird component",
|
|
72
|
+
"swagger-install": "blue-bird swagger-install"
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
let updated = false;
|
|
@@ -111,6 +112,7 @@ const command = args[0];
|
|
|
111
112
|
if (command === "react") import("./react.js");
|
|
112
113
|
else if (command === "route") import("./route.js")
|
|
113
114
|
else if (command === "component") import("./component.js")
|
|
115
|
+
else if (command === "swagger-install") import("./swagger.js")
|
|
114
116
|
else initializer.run();
|
|
115
117
|
|
|
116
118
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
class SwaggerCli {
|
|
4
|
+
install() {
|
|
5
|
+
const dependencies = this.checkDependencies();
|
|
6
|
+
if (dependencies.missingDependencies.length > 0) {
|
|
7
|
+
console.log("Installing dependencies...");
|
|
8
|
+
console.log(`Installing swagger-jsdoc...`);
|
|
9
|
+
execSync(`npm install swagger-jsdoc@6.2.8`, { stdio: "inherit" });
|
|
10
|
+
console.log(`Installing swagger-ui-express...`);
|
|
11
|
+
execSync(`npm install swagger-ui-express@5.0.1`, { stdio: "inherit" });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
checkDependencies() {
|
|
15
|
+
const dependencies = [
|
|
16
|
+
"swagger-jsdoc",
|
|
17
|
+
"swagger-ui-express"
|
|
18
|
+
];
|
|
19
|
+
const missingDependencies = [];
|
|
20
|
+
dependencies.forEach(dependency => {
|
|
21
|
+
if (!this.checkDependency(dependency)) {
|
|
22
|
+
missingDependencies.push(dependency);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
missingDependencies
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
checkDependency(dependency) {
|
|
30
|
+
try {
|
|
31
|
+
require.resolve(dependency);
|
|
32
|
+
return true;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const swaggerExecutor = new SwaggerCli();
|
|
40
|
+
swaggerExecutor.install();
|
package/core/template.js
CHANGED
|
@@ -127,7 +127,7 @@ class Template {
|
|
|
127
127
|
*/
|
|
128
128
|
static renderReact(res, component = "App", componentProps = {}, options = {}) {
|
|
129
129
|
try {
|
|
130
|
-
|
|
130
|
+
let {
|
|
131
131
|
langHtml = options.langHtml || props.langMeta || "en",
|
|
132
132
|
classBody = "body",
|
|
133
133
|
head = [],
|
|
@@ -135,20 +135,25 @@ class Template {
|
|
|
135
135
|
scriptsInHead = [],
|
|
136
136
|
scriptsInBody = [],
|
|
137
137
|
cache = true,
|
|
138
|
-
metaTags
|
|
139
|
-
titleMeta: options.metaTags?.titleMeta || props.titleMeta,
|
|
140
|
-
descriptionMeta: options.metaTags?.descriptionMeta || props.descriptionMeta,
|
|
141
|
-
keywordsMeta: options.metaTags?.keywordsMeta || props.keywordsMeta,
|
|
142
|
-
authorMeta: options.metaTags?.authorMeta || props.authorMeta,
|
|
143
|
-
langMeta: options.metaTags?.langMeta || props.langMeta,
|
|
144
|
-
},
|
|
138
|
+
metaTags
|
|
145
139
|
} = options;
|
|
140
|
+
const metaTagsDefault = {
|
|
141
|
+
titleMeta: props.titleMeta,
|
|
142
|
+
descriptionMeta: props.descriptionMeta,
|
|
143
|
+
keywordsMeta: props.keywordsMeta,
|
|
144
|
+
authorMeta: props.authorMeta,
|
|
145
|
+
langMeta: props.langMeta,
|
|
146
|
+
}
|
|
147
|
+
metaTags = {
|
|
148
|
+
...metaTagsDefault,
|
|
149
|
+
...metaTags
|
|
150
|
+
}
|
|
146
151
|
|
|
147
152
|
res.type("text/html");
|
|
148
153
|
res.status(200);
|
|
149
|
-
|
|
150
|
-
if (cache && CACHE_TEMPLATE[
|
|
151
|
-
return res.send(CACHE_TEMPLATE[
|
|
154
|
+
const cacheKey = `${component}_${metaTags.titleMeta}`;
|
|
155
|
+
if (cache && CACHE_TEMPLATE[cacheKey]) {
|
|
156
|
+
return res.send(CACHE_TEMPLATE[cacheKey]);
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
const title = this.escapeHtml(metaTags.titleMeta || "");
|
|
@@ -190,7 +195,7 @@ class Template {
|
|
|
190
195
|
.replace(/__SCRIPTS_BODY__/g, scriptsBodyTags);
|
|
191
196
|
|
|
192
197
|
html = this.minifyHtml(html);
|
|
193
|
-
CACHE_TEMPLATE[
|
|
198
|
+
CACHE_TEMPLATE[cacheKey] = html;
|
|
194
199
|
return res.send(html);
|
|
195
200
|
|
|
196
201
|
} catch (error) {
|
|
@@ -280,4 +285,4 @@ window.__vite_plugin_react_preamble_installed__ = true;
|
|
|
280
285
|
}
|
|
281
286
|
}
|
|
282
287
|
|
|
283
|
-
export default Template;
|
|
288
|
+
export default Template;
|
package/frontend/index.html
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="__LANG__">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
@@ -11,10 +12,12 @@
|
|
|
11
12
|
__HEAD_OPTIONS__
|
|
12
13
|
__LINK_STYLES__
|
|
13
14
|
__SCRIPTS_HEAD__
|
|
15
|
+
__VITE_ASSETS__
|
|
14
16
|
</head>
|
|
17
|
+
|
|
15
18
|
<body class="__CLASS_BODY__">
|
|
16
19
|
<div id="root" data-react-component="__COMPONENT__" data-props='__PROPS__'></div>
|
|
17
|
-
__VITE_ASSETS__
|
|
18
20
|
__SCRIPTS_BODY__
|
|
19
21
|
</body>
|
|
22
|
+
|
|
20
23
|
</html>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
|
|
3
|
+
import Home from './pages/Home';
|
|
4
|
+
import About from './pages/About';
|
|
5
|
+
|
|
6
|
+
export default function App(_props) {
|
|
7
|
+
const {
|
|
8
|
+
component,
|
|
9
|
+
props
|
|
10
|
+
} = _props;
|
|
11
|
+
|
|
12
|
+
console.log(`Check props and component `)
|
|
13
|
+
console.log(`Component: ${component}`)
|
|
14
|
+
console.log(props)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Router>
|
|
18
|
+
<div
|
|
19
|
+
className="bg-white text-gray-900"
|
|
20
|
+
>
|
|
21
|
+
<nav
|
|
22
|
+
className='bg-white text-gray-900 border border-gray-200 px-4 py-4 flex justify-between items-center gap-4 sticky top-0 z-10'
|
|
23
|
+
>
|
|
24
|
+
<div className='font-bold text-xl text-blue-600'>
|
|
25
|
+
Blue Bird
|
|
26
|
+
</div>
|
|
27
|
+
<div className='flex justify-between items-center gap-4'>
|
|
28
|
+
<Link to="/" className='text-gray-500 hover:text-gray-900'>Home</Link>
|
|
29
|
+
<Link to="/about" className='text-gray-500 hover:text-gray-900'>About</Link>
|
|
30
|
+
</div>
|
|
31
|
+
</nav>
|
|
32
|
+
<main className='max-w-7xl mx-auto'>
|
|
33
|
+
<Routes>
|
|
34
|
+
<Route path="/" element={<Home />} />
|
|
35
|
+
<Route path="/about" element={<About />} />
|
|
36
|
+
</Routes>
|
|
37
|
+
</main>
|
|
38
|
+
</div>
|
|
39
|
+
</Router>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import App from './App';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
7
|
+
document.querySelectorAll('[data-react-component]').forEach(el => {
|
|
8
|
+
const component = {
|
|
9
|
+
component:el.dataset.reactComponent
|
|
10
|
+
};
|
|
11
|
+
const props = JSON.parse(el.dataset.props || '{}');
|
|
12
|
+
const allProps={
|
|
13
|
+
...props,
|
|
14
|
+
...component
|
|
15
|
+
}
|
|
16
|
+
createRoot(el).render(<App {...allProps} />);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export default function About() {
|
|
4
|
+
return (
|
|
5
|
+
<div className='p-4'>
|
|
6
|
+
<h1 className='text-xl font-bold text-gray-900 mb-4'>About Blue Bird</h1>
|
|
7
|
+
<p className='text-gray-500 leading-1.6'>
|
|
8
|
+
Blue Bird is a modern framework designed to bridge the gap between backend routing and frontend interactivity.
|
|
9
|
+
It provides a seamless developer experience for building fast, reactive web applications.
|
|
10
|
+
</p>
|
|
11
|
+
<p className='text-red-500 text-xl mt-8 '>
|
|
12
|
+
Check your console JS
|
|
13
|
+
</p>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Home() {
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
// Example API call to the backend
|
|
6
|
+
fetch("http://localhost:3000/login", {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: {
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
},
|
|
11
|
+
body: JSON.stringify({
|
|
12
|
+
email: "example@example.com",
|
|
13
|
+
password: "myPassword123"
|
|
14
|
+
}),
|
|
15
|
+
})
|
|
16
|
+
.then((response) => response.json())
|
|
17
|
+
.then((data) => console.log('Backend response:', data))
|
|
18
|
+
.catch((error) => console.error('Error fetching from backend:', error));
|
|
19
|
+
}, []);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className='text-center p-4'>
|
|
23
|
+
<header className='mb-4'>
|
|
24
|
+
<h1 className='text-3xl font-bold bg-gradient-to-r from-blue-500 to-blue-600 bg-clip-text text-transparent mb-4'>
|
|
25
|
+
Welcome to Blue Bird
|
|
26
|
+
</h1>
|
|
27
|
+
<p className='text-gray-500 max-w-600px mx-auto'>
|
|
28
|
+
The elegant, fast, and weightless framework for modern web development.
|
|
29
|
+
</p>
|
|
30
|
+
</header>
|
|
31
|
+
|
|
32
|
+
<div className='flex gap-4 justify-center mb-8'>
|
|
33
|
+
<a
|
|
34
|
+
href="https://seip25.github.io/Blue-bird/en.html"
|
|
35
|
+
target="_blank"
|
|
36
|
+
rel="noopener noreferrer"
|
|
37
|
+
className='bg-blue-600 text-white px-4 py-2 rounded-lg font-semibold transition-colors hover:bg-blue-400'
|
|
38
|
+
>
|
|
39
|
+
Documentation (Eng)
|
|
40
|
+
</a>
|
|
41
|
+
<a
|
|
42
|
+
href="https://seip25.github.io/Blue-bird/"
|
|
43
|
+
target="_blank"
|
|
44
|
+
rel="noopener noreferrer"
|
|
45
|
+
className='bg-blue-50 text-blue-500 px-4 py-2 rounded-lg font-semibold transition-colors hover:bg-blue-100 '
|
|
46
|
+
>
|
|
47
|
+
Documentación (Esp)
|
|
48
|
+
|
|
49
|
+
</a>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div className='mt-8 grid grid-cols-1 md:grid-cols-3 gap-4 max-w-1000px mx-auto'>
|
|
53
|
+
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
54
|
+
<h3 className='text-blue-500 font-semibold text-xl mb-4'>Lightweight</h3>
|
|
55
|
+
<p>Built with performance and simplicity in mind.</p>
|
|
56
|
+
</div>
|
|
57
|
+
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
58
|
+
<h3 className='text-blue-500 font-semibold text-xl mb-4'>React Powered</h3>
|
|
59
|
+
<p>Full React + Vite integration .</p>
|
|
60
|
+
</div>
|
|
61
|
+
<div className='p-4 rounded-lg bg-gray-50 shadow-sm'>
|
|
62
|
+
<h3 className='text-blue-500 font-semibold text-xl mb-4'>Express Backend</h3>
|
|
63
|
+
<p>Robust and scalable backend architecture.</p>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seip/blue-bird",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Express + React opinionated framework with SPA or API architecture and built-in JWT auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
"react": "node core/cli/react.js",
|
|
30
30
|
"init": "node core/cli/init.js",
|
|
31
31
|
"route": "node core/cli/route.js",
|
|
32
|
-
"component": "node core/cli/component.js"
|
|
32
|
+
"component": "node core/cli/component.js",
|
|
33
|
+
"swagger-install": "node core/cli/swagger.js",
|
|
34
|
+
"vite:dev": "vite",
|
|
35
|
+
"vite:build": "vite build"
|
|
33
36
|
},
|
|
34
37
|
"dependencies": {
|
|
35
38
|
"chalk": "^5.6.2",
|
|
@@ -40,8 +43,13 @@
|
|
|
40
43
|
"helmet": "^8.1.0",
|
|
41
44
|
"jsonwebtoken": "^9.0.2",
|
|
42
45
|
"multer": "^2.0.2",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
46
|
+
"react": "^19.2.4",
|
|
47
|
+
"react-dom": "^19.2.4",
|
|
48
|
+
"react-router-dom": "7.13.1",
|
|
45
49
|
"xss": "^1.0.15"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@vitejs/plugin-react": "^4.2.0",
|
|
53
|
+
"vite": "7.3.1"
|
|
46
54
|
}
|
|
47
55
|
}
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
root: path.resolve(__dirname, 'frontend/resources/js'),
|
|
8
|
+
base: '/build/',
|
|
9
|
+
build: {
|
|
10
|
+
outDir: path.resolve(__dirname, 'frontend/public/build'),
|
|
11
|
+
emptyOutDir: true,
|
|
12
|
+
manifest: true,
|
|
13
|
+
rollupOptions: {
|
|
14
|
+
input: path.resolve(__dirname, 'frontend/resources/js/Main.jsx'),
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
server: {
|
|
18
|
+
origin: 'http://localhost:5173',
|
|
19
|
+
strictPort: true,
|
|
20
|
+
cors: true,
|
|
21
|
+
},
|
|
22
|
+
});
|
package/backend/routes/app.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import Router from "@seip/blue-bird/core/router.js"
|
|
2
|
-
import Validator from "@seip/blue-bird/core/validate.js"
|
|
3
|
-
import Template from "@seip/blue-bird/core/template.js"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const routerUsers = new Router("/")
|
|
7
|
-
|
|
8
|
-
//Example swagger docs
|
|
9
|
-
/**
|
|
10
|
-
* @swagger
|
|
11
|
-
* /users:
|
|
12
|
-
* get:
|
|
13
|
-
* summary: Get all users
|
|
14
|
-
* tags: [Users]
|
|
15
|
-
* responses:
|
|
16
|
-
* 200:
|
|
17
|
-
* description: List of users
|
|
18
|
-
*
|
|
19
|
-
*/
|
|
20
|
-
routerUsers.get("/users", (req, res) => {
|
|
21
|
-
const users = [
|
|
22
|
-
{
|
|
23
|
-
name: "John Doe",
|
|
24
|
-
email: "john.doe@example.com",
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: "Jane Doe2",
|
|
28
|
-
email: "jane.doe2@example.com",
|
|
29
|
-
},
|
|
30
|
-
]
|
|
31
|
-
res.json(users)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
const loginSchema = {
|
|
35
|
-
email: { required: true, email: true },
|
|
36
|
-
password: { required: true, min: 6 }
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const loginValidator = new Validator(loginSchema, 'es');
|
|
40
|
-
/**
|
|
41
|
-
* @swagger
|
|
42
|
-
* /login:
|
|
43
|
-
* post:
|
|
44
|
-
* summary: Login
|
|
45
|
-
* tags: [Users]
|
|
46
|
-
* description: Login with email and password
|
|
47
|
-
* requestBody:
|
|
48
|
-
* required: true
|
|
49
|
-
* content:
|
|
50
|
-
* application/json:
|
|
51
|
-
* schema:
|
|
52
|
-
* type: object
|
|
53
|
-
* required:
|
|
54
|
-
* - email
|
|
55
|
-
* - password
|
|
56
|
-
* properties:
|
|
57
|
-
* email:
|
|
58
|
-
* type: string
|
|
59
|
-
* format: email
|
|
60
|
-
* example: example@email.com
|
|
61
|
-
* password:
|
|
62
|
-
* type: string
|
|
63
|
-
* format: password
|
|
64
|
-
* example: 123456
|
|
65
|
-
* responses:
|
|
66
|
-
* 200:
|
|
67
|
-
* description: Login success
|
|
68
|
-
*
|
|
69
|
-
* 400:
|
|
70
|
-
* description: Error
|
|
71
|
-
* 401:
|
|
72
|
-
* description: Error in request
|
|
73
|
-
*/
|
|
74
|
-
|
|
75
|
-
routerUsers.post('/login', loginValidator.middleware(), (req, res) => {
|
|
76
|
-
res.json({ message: 'Login successful' });
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
//Example renderReact with customized meta Tags
|
|
80
|
-
routerUsers.get("/about", (req, res) => {
|
|
81
|
-
const response = Template.renderReact(res, "About", { title: "About Example title" }, {
|
|
82
|
-
metaTags: {
|
|
83
|
-
titleMeta: "About Title",
|
|
84
|
-
descriptionMeta: "About description",
|
|
85
|
-
keywordsMeta: "About,express, react, framework",
|
|
86
|
-
authorMeta: "Blue Bird",
|
|
87
|
-
langMeta: "es"
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
return response;
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
routerUsers.get("*", (req, res) => {
|
|
94
|
-
const response = Template.renderReact(res, "App", { title: "Example title" });
|
|
95
|
-
return response;
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
export default routerUsers
|