@swizzyweb/swizzy-frontend-template-web-service 0.2.0
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/Dockerfile +10 -0
- package/README.md +43 -0
- package/babel.config.cjs +7 -0
- package/dist/app.js +15 -0
- package/dist/app.js.map +1 -0
- package/dist/client/funny-joke-client.js +15 -0
- package/dist/client/funny-joke-client.js.map +1 -0
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -0
- package/dist/routers/ApiRouter/api-router.js +22 -0
- package/dist/routers/ApiRouter/api-router.js.map +1 -0
- package/dist/routers/ApiRouter/controllers/funny-joke-controller.js +33 -0
- package/dist/routers/ApiRouter/controllers/funny-joke-controller.js.map +1 -0
- package/dist/routers/PageRouter/page-router.js +29 -0
- package/dist/routers/PageRouter/page-router.js.map +1 -0
- package/dist/web-service.js +16 -0
- package/dist/web-service.js.map +1 -0
- package/docker-compose.yaml +8 -0
- package/entrypoint.sh +3 -0
- package/package.json +52 -0
- package/postcss.config.cjs +7 -0
- package/react/App.tsx +153 -0
- package/react/FunnyJokeTeller.tsx +44 -0
- package/react/index.css +4 -0
- package/react/index.html +15 -0
- package/react/index.tsx +19 -0
- package/src/app.ts +22 -0
- package/src/client/funny-joke-client.ts +29 -0
- package/src/client/index.ts +1 -0
- package/src/routers/ApiRouter/api-router.ts +49 -0
- package/src/routers/ApiRouter/controllers/funny-joke-controller.ts +59 -0
- package/src/routers/PageRouter/page-router.ts +52 -0
- package/src/web-service.ts +27 -0
- package/tailwind.config.js +25 -0
- package/tsconfig.json +26 -0
- package/webpack.config.cjs +111 -0
package/Dockerfile
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @swizzyweb/swizzy-frontend-template-web-service
|
|
2
|
+
|
|
3
|
+
Sample react and tailwind based swizzy frontend web service. The sample app has a react based frontend
|
|
4
|
+
and a swizzy web service backend. A sample implementation of an api can be found in the
|
|
5
|
+
routers/Api directory.
|
|
6
|
+
|
|
7
|
+
## Web service
|
|
8
|
+
|
|
9
|
+
The Swizzy web service logic can be found in the src directory.
|
|
10
|
+
|
|
11
|
+
## React
|
|
12
|
+
|
|
13
|
+
The react code is in the react directory.
|
|
14
|
+
|
|
15
|
+
## Running
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```npm
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Build and run immediately
|
|
24
|
+
|
|
25
|
+
```npm
|
|
26
|
+
npm run dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Only build
|
|
30
|
+
|
|
31
|
+
```npm
|
|
32
|
+
npm run build
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Running server after build
|
|
36
|
+
|
|
37
|
+
```npm
|
|
38
|
+
npm run server
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## With swerve
|
|
42
|
+
|
|
43
|
+
After build you can just run `swerve` in the root directory.
|
package/babel.config.cjs
ADDED
package/dist/app.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FunnyJokeClient } from "./client/index.js";
|
|
2
|
+
import { SampleFrontendWebService } from "./web-service.js";
|
|
3
|
+
export async function getWebservice(props) {
|
|
4
|
+
const state = {
|
|
5
|
+
funnyJokeClient: new FunnyJokeClient({
|
|
6
|
+
baseUrl: props.serviceArgs.funnyJokeBaseUrl,
|
|
7
|
+
}),
|
|
8
|
+
};
|
|
9
|
+
return new SampleFrontendWebService({
|
|
10
|
+
...props,
|
|
11
|
+
...props.serviceArgs,
|
|
12
|
+
state,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAO5D,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA6C;IAE7C,MAAM,KAAK,GAAG;QACZ,eAAe,EAAE,IAAI,eAAe,CAAC;YACnC,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB;SAC5C,CAAC;KACH,CAAC;IACF,OAAO,IAAI,wBAAwB,CAAC;QAClC,GAAG,KAAK;QACR,GAAG,KAAK,CAAC,WAAW;QACpB,KAAK;KACN,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = "https://official-joke-api.appspot.com";
|
|
2
|
+
export class FunnyJokeClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
constructor(props) {
|
|
5
|
+
this.baseUrl = props.baseUrl ?? DEFAULT_BASE_URL;
|
|
6
|
+
}
|
|
7
|
+
async getFunnyJoke(request) {
|
|
8
|
+
const response = await fetch(`${this.baseUrl}/jokes/random`, {
|
|
9
|
+
method: "get",
|
|
10
|
+
});
|
|
11
|
+
const joke = await response.json();
|
|
12
|
+
return joke;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=funny-joke-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"funny-joke-client.js","sourceRoot":"","sources":["../../src/client/funny-joke-client.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,uCAAuC,CAAC;AAgBjE,MAAM,OAAO,eAAe;IAClB,OAAO,CAAS;IACxB,YAAY,KAA2B;QACrC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACnD,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,OAAY;QAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,eAAe,EAAE;YAC3D,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RequestIdMiddleware, RequestLoggerMiddleware, SwizzyRequestMiddleware, WebRouter, } from "@swizzyweb/swizzy-web-service";
|
|
2
|
+
import { FunnyJokeController } from "./controllers/funny-joke-controller.js";
|
|
3
|
+
export class ApiWebRouter extends WebRouter {
|
|
4
|
+
constructor(props) {
|
|
5
|
+
super({
|
|
6
|
+
...props,
|
|
7
|
+
name: "ApiWebRouter",
|
|
8
|
+
path: "api",
|
|
9
|
+
stateConverter: ApiRouterStateConverter,
|
|
10
|
+
webControllerClasses: [FunnyJokeController],
|
|
11
|
+
middleware: [
|
|
12
|
+
SwizzyRequestMiddleware,
|
|
13
|
+
RequestIdMiddleware,
|
|
14
|
+
RequestLoggerMiddleware,
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const ApiRouterStateConverter = async function (props) {
|
|
20
|
+
return { ...props.state };
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=api-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-router.js","sourceRoot":"","sources":["../../../src/routers/ApiRouter/api-router.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,EACnB,uBAAuB,EAGvB,uBAAuB,EACvB,SAAS,GACV,MAAM,+BAA+B,CAAC;AAKvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAQ7E,MAAM,OAAO,YAAa,SAAQ,SAGjC;IACC,YAAY,KAAqB;QAC/B,KAAK,CAAC;YACJ,GAAG,KAAK;YACR,IAAI,EAAE,cAAc;YACpB,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,uBAAuB;YACvC,oBAAoB,EAAE,CAAC,mBAAmB,CAAC;YAC3C,UAAU,EAAE;gBACV,uBAAuB;gBACvB,mBAAmB;gBACnB,uBAAuB;aACxB;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,uBAAuB,GAGzB,KAAK,WACP,KAAyD;IAEzD,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DefaultStateExporter, RequestMethod, WebController, } from "@swizzyweb/swizzy-web-service";
|
|
2
|
+
export class FunnyJokeController extends WebController {
|
|
3
|
+
constructor(props) {
|
|
4
|
+
super({
|
|
5
|
+
...props,
|
|
6
|
+
name: "FunnyJokeController",
|
|
7
|
+
action: "funnyJoke",
|
|
8
|
+
method: RequestMethod.get,
|
|
9
|
+
stateConverter: DefaultStateExporter,
|
|
10
|
+
middleware: [],
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
async getInitializedController(props) {
|
|
14
|
+
const logger = this.logger;
|
|
15
|
+
const getState = this.getState.bind(this);
|
|
16
|
+
return async function (req, res) {
|
|
17
|
+
logger.info("We got a jokster lookin for jokes!");
|
|
18
|
+
try {
|
|
19
|
+
const { funnyJokeClient } = getState();
|
|
20
|
+
const joke = await funnyJokeClient.getFunnyJoke({});
|
|
21
|
+
res.json({
|
|
22
|
+
message: "Here's your funny joke",
|
|
23
|
+
joke,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
res.status(500);
|
|
28
|
+
res.json({ message: "Internal error occurred" });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=funny-joke-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"funny-joke-controller.js","sourceRoot":"","sources":["../../../../src/routers/ApiRouter/controllers/funny-joke-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EAGpB,aAAa,EACb,aAAa,GAEd,MAAM,+BAA+B,CAAC;AAcvC,MAAM,OAAO,mBAAoB,SAAQ,aAGxC;IACC,YAAY,KAA+B;QACzC,KAAK,CAAC;YACJ,GAAG,KAAK;YACR,IAAI,EAAE,qBAAqB;YAC3B,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,aAAa,CAAC,GAAG;YACzB,cAAc,EAAE,oBAAoB;YACpC,UAAU,EAAE,EAAE;SACf,CAAC,CAAC;IACL,CAAC;IAES,KAAK,CAAC,wBAAwB,CACtC,KAEC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,KAAK,WAAW,GAAY,EAAE,GAAa;YAChD,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,EAAE,eAAe,EAAE,GAAG,QAAQ,EAAG,CAAC;gBACxC,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,IAAI,CAAC;oBACP,OAAO,EAAE,wBAAwB;oBACjC,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RequestIdMiddleware, RequestLoggerMiddleware, SwizzyRequestMiddleware, WebRouter, } from "@swizzyweb/swizzy-web-service";
|
|
2
|
+
import path from "path";
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import express from "@swizzyweb/express";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
// This gives you the directory where *this* file is located
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
export class PageWebRouter extends WebRouter {
|
|
10
|
+
constructor(props) {
|
|
11
|
+
super({
|
|
12
|
+
...props,
|
|
13
|
+
name: "PageWebRouter",
|
|
14
|
+
path: "",
|
|
15
|
+
stateConverter: PageRouterStateConverter,
|
|
16
|
+
webControllerClasses: [],
|
|
17
|
+
middleware: [
|
|
18
|
+
SwizzyRequestMiddleware,
|
|
19
|
+
RequestIdMiddleware,
|
|
20
|
+
RequestLoggerMiddleware,
|
|
21
|
+
() => express.static(path.join(__dirname, "../../../bundle")),
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const PageRouterStateConverter = async function (props) {
|
|
27
|
+
return { ...props.state };
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=page-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-router.js","sourceRoot":"","sources":["../../../src/routers/PageRouter/page-router.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,EACnB,uBAAuB,EAGvB,uBAAuB,EACvB,SAAS,GACV,MAAM,+BAA+B,CAAC;AAEvC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,aAAa;AACb,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,4DAA4D;AAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAM3C,MAAM,OAAO,aAAc,SAAQ,SAGlC;IACC,YAAY,KAAsB;QAChC,KAAK,CAAC;YACJ,GAAG,KAAK;YACR,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,EAAE;YACR,cAAc,EAAE,wBAAwB;YACxC,oBAAoB,EAAE,EAAE;YACxB,UAAU,EAAE;gBACV,uBAAuB;gBACvB,mBAAmB;gBACnB,uBAAuB;gBACvB,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;aAC9D;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,wBAAwB,GAG1B,KAAK,WACP,KAAyD;IAEzD,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { WebService } from "@swizzyweb/swizzy-web-service";
|
|
2
|
+
import { PageWebRouter } from "./routers/PageRouter/page-router.js";
|
|
3
|
+
import { ApiWebRouter } from "./routers/ApiRouter/api-router.js";
|
|
4
|
+
export class SampleFrontendWebService extends WebService {
|
|
5
|
+
constructor(props) {
|
|
6
|
+
super({
|
|
7
|
+
...props,
|
|
8
|
+
name: "SampleFrontendWebService",
|
|
9
|
+
path: props.path ?? "",
|
|
10
|
+
packageName: "@swizzyweb/swizzy-frontend-template-web-service",
|
|
11
|
+
routerClasses: [PageWebRouter, ApiWebRouter],
|
|
12
|
+
middleware: [],
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=web-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-service.js","sourceRoot":"","sources":["../src/web-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAajE,MAAM,OAAO,wBAAyB,SAAQ,UAAyC;IACrF,YAAY,KAAoC;QAC9C,KAAK,CAAC;YACJ,GAAG,KAAK;YACR,IAAI,EAAE,0BAA0B;YAChC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,WAAW,EAAE,iDAAiD;YAC9D,aAAa,EAAE,CAAC,aAAa,EAAE,YAAY,CAAC;YAC5C,UAAU,EAAE,EAAE;SACf,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/entrypoint.sh
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@swizzyweb/swizzy-frontend-template-web-service",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Template for swizzyweb frontend web services",
|
|
5
|
+
"main": "dist/app.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"author": "Jason Gallagher",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "npm run build && npm run server",
|
|
10
|
+
"server": "swerve",
|
|
11
|
+
"build:service": "tsc",
|
|
12
|
+
"build": "npm run build:webpack && npm run build:service",
|
|
13
|
+
"start:webpack": "webpack serve --config webpack.config.cjs",
|
|
14
|
+
"build:webpack": "webpack --config webpack.config.cjs"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"webpack",
|
|
19
|
+
"tailwind",
|
|
20
|
+
"route-optimizer",
|
|
21
|
+
"typescript"
|
|
22
|
+
],
|
|
23
|
+
"license": "UNLICENSED",
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@babel/core": "^7.28.4",
|
|
26
|
+
"@babel/preset-env": "^7.28.3",
|
|
27
|
+
"@babel/preset-react": "^7.27.1",
|
|
28
|
+
"@babel/preset-typescript": "^7.27.1",
|
|
29
|
+
"@swizzyweb/swerve": "^0.5.6",
|
|
30
|
+
"@tailwindcss/postcss": "^4.1.13",
|
|
31
|
+
"autoprefixer": "^10.4.21",
|
|
32
|
+
"babel-loader": "^9.2.1",
|
|
33
|
+
"css-loader": "^7.1.2",
|
|
34
|
+
"html-webpack-plugin": "^5.6.4",
|
|
35
|
+
"mini-css-extract-plugin": "^2.9.4",
|
|
36
|
+
"postcss": "^8.5.6",
|
|
37
|
+
"postcss-loader": "^8.2.0",
|
|
38
|
+
"style-loader": "^4.0.0",
|
|
39
|
+
"tailwindcss": "^4.1.7",
|
|
40
|
+
"typescript": "^5.9.2",
|
|
41
|
+
"webpack": "^5.101.3",
|
|
42
|
+
"webpack-cli": "^5.1.4",
|
|
43
|
+
"webpack-dev-server": "^5.2.2"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@swizzyweb/express": "^4.19.2",
|
|
47
|
+
"@swizzyweb/swizzy-common": "^0.3.2",
|
|
48
|
+
"@swizzyweb/swizzy-web-service": "^0.5.4",
|
|
49
|
+
"react": "^18.3.1",
|
|
50
|
+
"react-dom": "^18.3.1"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/react/App.tsx
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React, { useState } from "react"; // Keep this as it's the actual library import
|
|
2
|
+
import { FunnyJokeTeller } from "./FunnyJokeTeller";
|
|
3
|
+
|
|
4
|
+
// Main App component
|
|
5
|
+
const App = () => {
|
|
6
|
+
return (
|
|
7
|
+
<div className="min-h-screen bg-gray-100 font-sans antialiased flex flex-col">
|
|
8
|
+
{/* Header Section */}
|
|
9
|
+
<header className="bg-gradient-to-r from-blue-600 to-purple-700 text-white p-6 shadow-lg rounded-b-xl">
|
|
10
|
+
<div className="container mx-auto flex justify-between items-center">
|
|
11
|
+
<h1 className="text-4xl font-extrabold tracking-tight">
|
|
12
|
+
My Awesome SwizzyWeb Site
|
|
13
|
+
</h1>
|
|
14
|
+
<nav>
|
|
15
|
+
<ul className="flex space-x-6">
|
|
16
|
+
<li>
|
|
17
|
+
<a
|
|
18
|
+
href="#"
|
|
19
|
+
className="text-white hover:text-blue-200 transition duration-300 text-lg font-medium"
|
|
20
|
+
>
|
|
21
|
+
Home
|
|
22
|
+
</a>
|
|
23
|
+
</li>
|
|
24
|
+
<li>
|
|
25
|
+
<a
|
|
26
|
+
href="#"
|
|
27
|
+
className="text-white hover:text-blue-200 transition duration-300 text-lg font-medium"
|
|
28
|
+
>
|
|
29
|
+
About
|
|
30
|
+
</a>
|
|
31
|
+
</li>
|
|
32
|
+
<li>
|
|
33
|
+
<a
|
|
34
|
+
href="#"
|
|
35
|
+
className="text-white hover:text-blue-200 transition duration-300 text-lg font-medium"
|
|
36
|
+
>
|
|
37
|
+
Services
|
|
38
|
+
</a>
|
|
39
|
+
</li>
|
|
40
|
+
<li>
|
|
41
|
+
<a
|
|
42
|
+
href="#"
|
|
43
|
+
className="text-white hover:text-blue-200 transition duration-300 text-lg font-medium"
|
|
44
|
+
>
|
|
45
|
+
Contact
|
|
46
|
+
</a>
|
|
47
|
+
</li>
|
|
48
|
+
</ul>
|
|
49
|
+
</nav>
|
|
50
|
+
</div>
|
|
51
|
+
</header>
|
|
52
|
+
|
|
53
|
+
{/* Main Content Section */}
|
|
54
|
+
<main className="flex-grow container mx-auto p-8 py-12">
|
|
55
|
+
<section className="bg-white p-8 rounded-xl shadow-lg mb-8">
|
|
56
|
+
<h2 className="text-3xl font-bold text-gray-800 mb-4">
|
|
57
|
+
Welcome to Our Site!
|
|
58
|
+
</h2>
|
|
59
|
+
<p className="text-gray-700 leading-relaxed text-lg">
|
|
60
|
+
This is a sample SwizzyWeb website built with the power and
|
|
61
|
+
flexibility of Tailwind CSS. Enjoy the clean design and responsive
|
|
62
|
+
layout that adapts beautifully to any screen size. We've focused on
|
|
63
|
+
creating a modern and user-friendly experience.
|
|
64
|
+
</p>
|
|
65
|
+
<div className="mt-6 flex space-x-4">
|
|
66
|
+
<button className="bg-blue-500 hover:bg-blue-600 text-white font-semibold py-3 px-6 rounded-lg shadow-md transition duration-300 transform hover:scale-105">
|
|
67
|
+
Learn More
|
|
68
|
+
</button>
|
|
69
|
+
<button className="bg-purple-500 hover:bg-purple-600 text-white font-semibold py-3 px-6 rounded-lg shadow-md transition duration-300 transform hover:scale-105">
|
|
70
|
+
Get Started
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</section>
|
|
74
|
+
|
|
75
|
+
<section className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
76
|
+
{/* Feature Card 1 */}
|
|
77
|
+
<div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 hover:shadow-xl transition duration-300">
|
|
78
|
+
<h3 className="text-2xl font-semibold text-gray-800 mb-3">
|
|
79
|
+
Responsive Design
|
|
80
|
+
</h3>
|
|
81
|
+
<p className="text-gray-600">
|
|
82
|
+
Our website looks great on desktops, tablets, and mobile phones,
|
|
83
|
+
ensuring a seamless experience for all users.
|
|
84
|
+
</p>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
{/* Feature Card 2 */}
|
|
88
|
+
<div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 hover:shadow-xl transition duration-300">
|
|
89
|
+
<h3 className="2xl font-semibold text-gray-800 mb-3">Modern UI</h3>
|
|
90
|
+
<p className="text-gray-600">
|
|
91
|
+
Leveraging Tailwind CSS, we've crafted a clean, modern, and
|
|
92
|
+
intuitive user interface.
|
|
93
|
+
</p>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
{/* Feature Card 3 */}
|
|
97
|
+
<div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 hover:shadow-xl transition duration-300">
|
|
98
|
+
<h3 className="2xl font-semibold text-gray-800 mb-3">
|
|
99
|
+
Easy to Customize
|
|
100
|
+
</h3>
|
|
101
|
+
<p className="text-gray-600">
|
|
102
|
+
The component-based structure makes it incredibly easy to extend
|
|
103
|
+
and customize.
|
|
104
|
+
</p>
|
|
105
|
+
</div>
|
|
106
|
+
{/* Feature Card 4 */}
|
|
107
|
+
<div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 hover:shadow-xl transition duration-300">
|
|
108
|
+
<h3 className="2xl font-semibold text-gray-800 mb-3">
|
|
109
|
+
Easy to add custom api's
|
|
110
|
+
</h3>
|
|
111
|
+
<p className="text-gray-600">
|
|
112
|
+
Adding api's is as simple as creating new controllers, checkout
|
|
113
|
+
our funny joke API by clicking the button below.
|
|
114
|
+
</p>
|
|
115
|
+
|
|
116
|
+
<FunnyJokeTeller />
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
</main>
|
|
120
|
+
|
|
121
|
+
{/* Footer Section */}
|
|
122
|
+
<footer className="bg-gray-800 text-white p-6 mt-8 rounded-t-xl shadow-inner">
|
|
123
|
+
<div className="container mx-auto text-center">
|
|
124
|
+
<p className="text-gray-400">
|
|
125
|
+
© {new Date().getFullYear()} My Awesome SwizzyWeb Site. All
|
|
126
|
+
rights reserved.
|
|
127
|
+
</p>
|
|
128
|
+
<p className="text-gray-400 mt-2">
|
|
129
|
+
Made with{" "}
|
|
130
|
+
<span className="font-semibold text-white">@swizzyweb</span>
|
|
131
|
+
</p>
|
|
132
|
+
<div className="flex justify-center space-x-4 mt-3">
|
|
133
|
+
<a
|
|
134
|
+
href="#"
|
|
135
|
+
className="text-gray-400 hover:text-white transition duration-300"
|
|
136
|
+
>
|
|
137
|
+
Privacy Policy
|
|
138
|
+
</a>
|
|
139
|
+
<span className="text-gray-500">|</span>
|
|
140
|
+
<a
|
|
141
|
+
href="#"
|
|
142
|
+
className="text-gray-400 hover:text-white transition duration-300"
|
|
143
|
+
>
|
|
144
|
+
Terms of Service
|
|
145
|
+
</a>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</footer>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default App;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
interface Joke {
|
|
4
|
+
id: number;
|
|
5
|
+
type: string;
|
|
6
|
+
setup: string;
|
|
7
|
+
punchline: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function FunnyJokeTeller(props: any) {
|
|
11
|
+
let [joke, setJoke] = useState<Joke>();
|
|
12
|
+
let [setupText, setSetupText] = useState("");
|
|
13
|
+
let [punchlineText, setPunchlineText] = useState("");
|
|
14
|
+
let [categoryText, setCategoryText] = useState("");
|
|
15
|
+
async function getFunnyJoke() {
|
|
16
|
+
const res = await fetch("/api/funnyJoke", {
|
|
17
|
+
method: "get",
|
|
18
|
+
});
|
|
19
|
+
const body = await res.json();
|
|
20
|
+
const newFunnyJoke = body.joke;
|
|
21
|
+
setJoke(newFunnyJoke);
|
|
22
|
+
setSetupText(newFunnyJoke.setup);
|
|
23
|
+
setPunchlineText(newFunnyJoke.punchline);
|
|
24
|
+
setCategoryText(newFunnyJoke.type);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<section id="funny-joke">
|
|
29
|
+
{" "}
|
|
30
|
+
<button
|
|
31
|
+
className="bg-blue-500 hover:bg-blue-600 text-white font-semibold py-3 px-6 rounded-lg shadow-md transition duration-300 transform hover:scale-105 mt-5 mb-5"
|
|
32
|
+
onClick={getFunnyJoke}
|
|
33
|
+
>
|
|
34
|
+
Get funny joke
|
|
35
|
+
</button>
|
|
36
|
+
{joke && (
|
|
37
|
+
<div>
|
|
38
|
+
<div>{setupText}</div>
|
|
39
|
+
<div>{punchlineText}</div>
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
</section>
|
|
43
|
+
);
|
|
44
|
+
}
|
package/react/index.css
ADDED
package/react/index.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>SwizzyWebSite</title>
|
|
7
|
+
<link
|
|
8
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap"
|
|
9
|
+
rel="stylesheet"
|
|
10
|
+
/>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/react/index.tsx
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// ./react/index.tsx
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ReactDOM from 'react-dom/client'; // Import from 'react-dom/client' for React 18+
|
|
4
|
+
import App from './App'; // Assuming your main component is in App.tsx
|
|
5
|
+
|
|
6
|
+
// Import your main CSS file (e.g., where Tailwind's output is imported)
|
|
7
|
+
import './index.css'; // Make sure this file exists and imports your Tailwind CSS
|
|
8
|
+
|
|
9
|
+
const rootElement = document.getElementById('root');
|
|
10
|
+
if (rootElement) {
|
|
11
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
12
|
+
root.render(
|
|
13
|
+
<React.StrictMode>
|
|
14
|
+
<App />
|
|
15
|
+
</React.StrictMode>
|
|
16
|
+
);
|
|
17
|
+
} else {
|
|
18
|
+
console.error('Root element with ID "root" not found in the document.');
|
|
19
|
+
}
|
package/src/app.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FunnyJokeClient } from "./client/index.js";
|
|
2
|
+
import { SampleFrontendWebService } from "./web-service.js";
|
|
3
|
+
|
|
4
|
+
export interface GetSampleFrontendWebserviceProps {
|
|
5
|
+
serviceArgs: {
|
|
6
|
+
funnyJokeBaseUrl?: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export async function getWebservice(
|
|
10
|
+
props: GetSampleFrontendWebserviceProps & any,
|
|
11
|
+
) {
|
|
12
|
+
const state = {
|
|
13
|
+
funnyJokeClient: new FunnyJokeClient({
|
|
14
|
+
baseUrl: props.serviceArgs.funnyJokeBaseUrl,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
return new SampleFrontendWebService({
|
|
18
|
+
...props,
|
|
19
|
+
...props.serviceArgs,
|
|
20
|
+
state,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = "https://official-joke-api.appspot.com";
|
|
2
|
+
|
|
3
|
+
export interface Joke {
|
|
4
|
+
id: number;
|
|
5
|
+
punchline: string;
|
|
6
|
+
setup: string;
|
|
7
|
+
type: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FunnyJokeClientProps {
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IFunnyJokeClient {
|
|
14
|
+
getFunnyJoke(request: any): Promise<Joke>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class FunnyJokeClient implements IFunnyJokeClient {
|
|
18
|
+
private baseUrl: string;
|
|
19
|
+
constructor(props: FunnyJokeClientProps) {
|
|
20
|
+
this.baseUrl = props.baseUrl ?? DEFAULT_BASE_URL;
|
|
21
|
+
}
|
|
22
|
+
async getFunnyJoke(request: any): Promise<Joke> {
|
|
23
|
+
const response = await fetch(`${this.baseUrl}/jokes/random`, {
|
|
24
|
+
method: "get",
|
|
25
|
+
});
|
|
26
|
+
const joke = await response.json();
|
|
27
|
+
return joke;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./funny-joke-client.js";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IWebRouterProps,
|
|
3
|
+
RequestIdMiddleware,
|
|
4
|
+
RequestLoggerMiddleware,
|
|
5
|
+
StateConverter,
|
|
6
|
+
StateConverterProps,
|
|
7
|
+
SwizzyRequestMiddleware,
|
|
8
|
+
WebRouter,
|
|
9
|
+
} from "@swizzyweb/swizzy-web-service";
|
|
10
|
+
import { SampleFrontendWebServiceState } from "../../web-service.js";
|
|
11
|
+
import path from "path";
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
import express from "@swizzyweb/express";
|
|
14
|
+
import { FunnyJokeController } from "./controllers/funny-joke-controller.js";
|
|
15
|
+
import { IFunnyJokeClient } from "../../client/index.js";
|
|
16
|
+
export interface ApiRouterState {
|
|
17
|
+
funnyJokeClient: IFunnyJokeClient;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ApiRouterProps
|
|
21
|
+
extends IWebRouterProps<SampleFrontendWebServiceState, ApiRouterState> {}
|
|
22
|
+
export class ApiWebRouter extends WebRouter<
|
|
23
|
+
SampleFrontendWebServiceState,
|
|
24
|
+
ApiRouterState
|
|
25
|
+
> {
|
|
26
|
+
constructor(props: ApiRouterProps) {
|
|
27
|
+
super({
|
|
28
|
+
...props,
|
|
29
|
+
name: "ApiWebRouter",
|
|
30
|
+
path: "api",
|
|
31
|
+
stateConverter: ApiRouterStateConverter,
|
|
32
|
+
webControllerClasses: [FunnyJokeController],
|
|
33
|
+
middleware: [
|
|
34
|
+
SwizzyRequestMiddleware,
|
|
35
|
+
RequestIdMiddleware,
|
|
36
|
+
RequestLoggerMiddleware,
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ApiRouterStateConverter: StateConverter<
|
|
43
|
+
SampleFrontendWebServiceState,
|
|
44
|
+
ApiRouterState
|
|
45
|
+
> = async function (
|
|
46
|
+
props: StateConverterProps<SampleFrontendWebServiceState>,
|
|
47
|
+
): Promise<ApiRouterState> {
|
|
48
|
+
return { ...props.state };
|
|
49
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DefaultStateExporter,
|
|
3
|
+
IWebControllerInitProps,
|
|
4
|
+
IWebControllerProps,
|
|
5
|
+
RequestMethod,
|
|
6
|
+
WebController,
|
|
7
|
+
WebControllerFunction,
|
|
8
|
+
} from "@swizzyweb/swizzy-web-service";
|
|
9
|
+
import { ApiRouterState, ApiWebRouter } from "../api-router.js";
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
import { Request, Response, json } from "@swizzyweb/express";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { IFunnyJokeClient } from "../../../client/index.js";
|
|
14
|
+
|
|
15
|
+
export interface FunnyJokeControllerState {
|
|
16
|
+
funnyJokeClient: IFunnyJokeClient;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FunnyJokeControllerProps
|
|
20
|
+
extends IWebControllerProps<ApiRouterState, FunnyJokeControllerState> {}
|
|
21
|
+
|
|
22
|
+
export class FunnyJokeController extends WebController<
|
|
23
|
+
ApiRouterState,
|
|
24
|
+
FunnyJokeControllerState
|
|
25
|
+
> {
|
|
26
|
+
constructor(props: FunnyJokeControllerProps) {
|
|
27
|
+
super({
|
|
28
|
+
...props,
|
|
29
|
+
name: "FunnyJokeController",
|
|
30
|
+
action: "funnyJoke",
|
|
31
|
+
method: RequestMethod.get,
|
|
32
|
+
stateConverter: DefaultStateExporter,
|
|
33
|
+
middleware: [],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected async getInitializedController(
|
|
38
|
+
props: IWebControllerInitProps<ApiRouterState> & {
|
|
39
|
+
state: FunnyJokeControllerState | undefined;
|
|
40
|
+
},
|
|
41
|
+
): Promise<WebControllerFunction> {
|
|
42
|
+
const logger = this.logger;
|
|
43
|
+
const getState = this.getState.bind(this);
|
|
44
|
+
return async function (req: Request, res: Response) {
|
|
45
|
+
logger.info("We got a jokster lookin for jokes!");
|
|
46
|
+
try {
|
|
47
|
+
const { funnyJokeClient } = getState()!;
|
|
48
|
+
const joke = await funnyJokeClient.getFunnyJoke({});
|
|
49
|
+
res.json({
|
|
50
|
+
message: "Here's your funny joke",
|
|
51
|
+
joke,
|
|
52
|
+
});
|
|
53
|
+
} catch (e: any) {
|
|
54
|
+
res.status(500);
|
|
55
|
+
res.json({ message: "Internal error occurred" });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IWebRouterProps,
|
|
3
|
+
RequestIdMiddleware,
|
|
4
|
+
RequestLoggerMiddleware,
|
|
5
|
+
StateConverter,
|
|
6
|
+
StateConverterProps,
|
|
7
|
+
SwizzyRequestMiddleware,
|
|
8
|
+
WebRouter,
|
|
9
|
+
} from "@swizzyweb/swizzy-web-service";
|
|
10
|
+
import { SampleFrontendWebServiceState } from "../../web-service.js";
|
|
11
|
+
import path from "path";
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
import express from "@swizzyweb/express";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
// This gives you the directory where *this* file is located
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = path.dirname(__filename);
|
|
19
|
+
|
|
20
|
+
export interface PageRouterState {}
|
|
21
|
+
|
|
22
|
+
export interface PageRouterProps
|
|
23
|
+
extends IWebRouterProps<SampleFrontendWebServiceState, PageRouterState> {}
|
|
24
|
+
export class PageWebRouter extends WebRouter<
|
|
25
|
+
SampleFrontendWebServiceState,
|
|
26
|
+
PageRouterState
|
|
27
|
+
> {
|
|
28
|
+
constructor(props: PageRouterProps) {
|
|
29
|
+
super({
|
|
30
|
+
...props,
|
|
31
|
+
name: "PageWebRouter",
|
|
32
|
+
path: "",
|
|
33
|
+
stateConverter: PageRouterStateConverter,
|
|
34
|
+
webControllerClasses: [],
|
|
35
|
+
middleware: [
|
|
36
|
+
SwizzyRequestMiddleware,
|
|
37
|
+
RequestIdMiddleware,
|
|
38
|
+
RequestLoggerMiddleware,
|
|
39
|
+
() => express.static(path.join(__dirname, "../../../bundle")),
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const PageRouterStateConverter: StateConverter<
|
|
46
|
+
SampleFrontendWebServiceState,
|
|
47
|
+
PageRouterState
|
|
48
|
+
> = async function (
|
|
49
|
+
props: StateConverterProps<SampleFrontendWebServiceState>,
|
|
50
|
+
): Promise<PageRouterState> {
|
|
51
|
+
return { ...props.state };
|
|
52
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { IWebServiceProps, WebService } from "@swizzyweb/swizzy-web-service";
|
|
2
|
+
import { PageWebRouter } from "./routers/PageRouter/page-router.js";
|
|
3
|
+
import { ApiWebRouter } from "./routers/ApiRouter/api-router.js";
|
|
4
|
+
import { FunnyJokeClient, IFunnyJokeClient } from "./client/index.js";
|
|
5
|
+
|
|
6
|
+
export interface SampleFrontendWebServiceState {
|
|
7
|
+
funnyJokeClient: IFunnyJokeClient;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SampleFrontendWebServiceProps
|
|
11
|
+
extends IWebServiceProps<SampleFrontendWebServiceState> {
|
|
12
|
+
port: number;
|
|
13
|
+
path?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class SampleFrontendWebService extends WebService<SampleFrontendWebServiceState> {
|
|
17
|
+
constructor(props: SampleFrontendWebServiceProps) {
|
|
18
|
+
super({
|
|
19
|
+
...props,
|
|
20
|
+
name: "SampleFrontendWebService",
|
|
21
|
+
path: props.path ?? "",
|
|
22
|
+
packageName: "@swizzyweb/swizzy-frontend-template-web-service",
|
|
23
|
+
routerClasses: [PageWebRouter, ApiWebRouter],
|
|
24
|
+
middleware: [],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// tailwind.config.js
|
|
2
|
+
/** @type {import('tailwindcss').Config} */
|
|
3
|
+
module.exports = {
|
|
4
|
+
// This 'content' array is CRUCIAL. It tells Tailwind where to look for
|
|
5
|
+
// all the utility classes you are using in your project.
|
|
6
|
+
content: [
|
|
7
|
+
// This glob pattern is designed to scan all JavaScript, JSX, TypeScript,
|
|
8
|
+
// and TSX files within your 'react' directory and any of its subdirectories.
|
|
9
|
+
// This is where your App.tsx and other React components reside.
|
|
10
|
+
"./react/**/*.{js,jsx,ts,tsx}",
|
|
11
|
+
// If your main index.html file (the template used by HtmlWebpackPlugin)
|
|
12
|
+
// also contains Tailwind classes (e.g., on the <body> tag), include it here.
|
|
13
|
+
"./react/index.html",
|
|
14
|
+
],
|
|
15
|
+
theme: {
|
|
16
|
+
extend: {
|
|
17
|
+
// Ensure your custom font 'Inter' is defined here if you're using it.
|
|
18
|
+
fontFamily: {
|
|
19
|
+
inter: ["Inter", "sans-serif"],
|
|
20
|
+
},
|
|
21
|
+
// Any other theme extensions (custom colors, spacing, etc.) would go here.
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
plugins: [], // Add any Tailwind CSS plugins here if you use them (e.g., @tailwindcss/forms)
|
|
25
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2024", // Or a more recent ECMAScript version (e.g., "es2020", "esnext") based on your Node.js environment
|
|
4
|
+
"module": "nodenext", // Or "esnext" if your service uses ES modules (and you have "type": "module" in package.json)
|
|
5
|
+
"outDir": "./dist", // Output directory for compiled JavaScript files from your service code
|
|
6
|
+
//"rootDir": "./", // Specifies the root directory of input files. Relative to this tsconfig.json.
|
|
7
|
+
"strict": true, // Enable all strict type-checking options for robust code
|
|
8
|
+
"esModuleInterop": true, // Allows default imports from modules with no default export
|
|
9
|
+
"skipLibCheck": true, // Skip type checking of all declaration files (*.d.ts)
|
|
10
|
+
"forceConsistentCasingInFileNames": true, // Ensure consistent casing for file paths
|
|
11
|
+
"resolveJsonModule": true, // Allows importing .json files in your service code
|
|
12
|
+
"sourceMap": true, // Generates source map files for debugging
|
|
13
|
+
"isolatedModules": true
|
|
14
|
+
},
|
|
15
|
+
"include": [
|
|
16
|
+
// Include all .ts files in the current directory (./src/) and its subdirectories
|
|
17
|
+
"src" // Include declaration files if any
|
|
18
|
+
//"react/home.tsx",
|
|
19
|
+
// "react/search.tsx"
|
|
20
|
+
],
|
|
21
|
+
"exclude": [
|
|
22
|
+
"node_modules", // Exclude the node_modules directory
|
|
23
|
+
"./react", // Explicitly exclude the React application's directory
|
|
24
|
+
"./bundle" // Exclude the webpack output directory
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
3
|
+
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // Import the CSS extraction plugin
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
// Set the mode to 'development' for easier debugging during development.
|
|
7
|
+
// Change to 'production' for optimized, minified output suitable for deployment.
|
|
8
|
+
mode: "development",
|
|
9
|
+
|
|
10
|
+
// The main entry point for your React application.
|
|
11
|
+
// Webpack starts building its dependency graph from this file.
|
|
12
|
+
// Ensure that 'index.tsx' exists inside your './react/' directory.
|
|
13
|
+
entry: "./react/index.tsx",
|
|
14
|
+
|
|
15
|
+
// Configuration for where Webpack should output the bundled files.
|
|
16
|
+
output: {
|
|
17
|
+
// The absolute path to the output directory.
|
|
18
|
+
// path.resolve(__dirname, 'bundle') creates a 'bundle' folder
|
|
19
|
+
// at the root of your project (where this webpack.config.js resides).
|
|
20
|
+
path: path.resolve(__dirname, "bundle"),
|
|
21
|
+
// The name of the main JavaScript bundle file.
|
|
22
|
+
filename: "js/bundle.js",
|
|
23
|
+
// This option cleans the output directory ('./bundle/') before each new build.
|
|
24
|
+
// This prevents old, unused files from accumulating.
|
|
25
|
+
clean: true,
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
// Rules define how different types of modules (files) are processed by Webpack.
|
|
29
|
+
module: {
|
|
30
|
+
rules: [
|
|
31
|
+
{
|
|
32
|
+
// This rule applies to files with .js, .jsx, .ts, or .tsx extensions.
|
|
33
|
+
test: /\.(js|jsx|ts|tsx)$/,
|
|
34
|
+
// Exclude files from the 'node_modules' directory to speed up compilation,
|
|
35
|
+
// as these are typically pre-compiled.
|
|
36
|
+
exclude: /node_modules/,
|
|
37
|
+
use: {
|
|
38
|
+
// 'babel-loader' is used to transpile (convert) modern JavaScript,
|
|
39
|
+
// JSX, and TypeScript code into a format compatible with older browsers.
|
|
40
|
+
loader: "babel-loader",
|
|
41
|
+
options: {
|
|
42
|
+
// Babel presets define sets of transformations.
|
|
43
|
+
presets: [
|
|
44
|
+
"@babel/preset-env", // Transpiles modern JavaScript (ES6+) to ES5.
|
|
45
|
+
"@babel/preset-react", // Transpiles JSX syntax into React.createElement calls.
|
|
46
|
+
"@babel/preset-typescript", // Transpiles TypeScript into JavaScript.
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
// This rule applies to CSS files.
|
|
53
|
+
test: /\.css$/,
|
|
54
|
+
// The 'use' array specifies the loaders to apply, in reverse order.
|
|
55
|
+
use: [
|
|
56
|
+
// 1. MiniCssExtractPlugin.loader: Extracts CSS into separate files.
|
|
57
|
+
// This is crucial for getting a physical 'styles.css' file in your bundle.
|
|
58
|
+
MiniCssExtractPlugin.loader,
|
|
59
|
+
// 2. 'css-loader': Interprets `@import` and `url()` like `import`/`require()`
|
|
60
|
+
// and resolves them. It turns CSS into CommonJS modules.
|
|
61
|
+
"css-loader",
|
|
62
|
+
// 3. 'postcss-loader': Processes CSS with PostCSS plugins.
|
|
63
|
+
// This is where Tailwind CSS and Autoprefixer are applied,
|
|
64
|
+
// using your 'postcss.config.js' configuration.
|
|
65
|
+
"postcss-loader",
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Configure how modules are resolved.
|
|
72
|
+
resolve: {
|
|
73
|
+
// This allows you to import modules without specifying their file extensions.
|
|
74
|
+
// For example, you can write `import App from './App'` instead of `import App from './App.tsx'`.
|
|
75
|
+
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Plugins extend Webpack's capabilities beyond simple module transformations.
|
|
79
|
+
plugins: [
|
|
80
|
+
// HtmlWebpackPlugin: Simplifies the creation of HTML files to serve your webpack bundles.
|
|
81
|
+
// It automatically injects your bundled JavaScript and CSS into the HTML.
|
|
82
|
+
new HtmlWebpackPlugin({
|
|
83
|
+
// The template HTML file to use. This file should be in your './react/' directory.
|
|
84
|
+
template: "./react/index.html",
|
|
85
|
+
// The name of the output HTML file that will be placed in the 'bundle' directory.
|
|
86
|
+
filename: "index.html",
|
|
87
|
+
}),
|
|
88
|
+
// MiniCssExtractPlugin: Extracts CSS into separate files.
|
|
89
|
+
// This plugin works in conjunction with its loader (defined in module.rules)
|
|
90
|
+
// to create a dedicated CSS file (e.g., 'styles.css').
|
|
91
|
+
new MiniCssExtractPlugin({
|
|
92
|
+
// The filename for the extracted CSS file.
|
|
93
|
+
filename: "css/styles.css", // You can customize this name if you wish
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
|
|
97
|
+
// Configuration for the Webpack Development Server (optional, for local development).
|
|
98
|
+
devServer: {
|
|
99
|
+
// Specifies the directory from which to serve static files.
|
|
100
|
+
// In this case, it serves files from your 'bundle' directory.
|
|
101
|
+
static: {
|
|
102
|
+
directory: path.join(__dirname, "bundle"),
|
|
103
|
+
},
|
|
104
|
+
// Enables GZIP compression for everything served by the development server.
|
|
105
|
+
compress: true,
|
|
106
|
+
// The port on which the development server will run.
|
|
107
|
+
port: 3000,
|
|
108
|
+
// Automatically opens your default web browser to the application when the server starts.
|
|
109
|
+
open: true,
|
|
110
|
+
},
|
|
111
|
+
};
|