Skip to content

Commit

Permalink
Merge pull request #1 from victorekpo/react
Browse files Browse the repository at this point in the history
react is working
  • Loading branch information
victorekpo authored Jul 13, 2024
2 parents af90862 + 69ef143 commit 959aec7
Show file tree
Hide file tree
Showing 22 changed files with 201 additions and 121 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Serverless Microapp
# Serverless React App
Domain: `cf.neweradesign.net`

## Client Hosted on Cloudflare Workers
- uses Wrangler for orchestration
- uses itty-router for Express-like routing
- uses handlebars for views engine
- uses React for client side framework
- uses custom webpack config for build
- 100,000 free requests per day

## Server Hosted on AWS Lambda
- uses AWS CDK for orchestration
- uses node engine
- best for database operations (i.e. working with MongoDB)
- 10,000 free requests per day
23 changes: 14 additions & 9 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@
"description": "tech tools hosted on cloudflare worker",
"main": "index.js",
"scripts": {
"build": "npm run compilehbs && npm run transpilehbs && rm src/*-original.js",
"compilehbs": "handlebars -e hbs -f src/pages-original.js src/views/pages/ && handlebars -e hbs -p -f src/partials-original.js src/views/partials/",
"build": "webpack",
"deploy": "wrangler deploy src/index.js",
"prepare": "husky",
"start": "wrangler dev src/index.js",
"test": "echo \"Error: no test specified\" && exit 1",
"transpilehbs": "hbs-import-transpile src/pages-original.js > assets/pages.js && hbs-import-transpile src/partials-original.js > assets/partials.js"
"start": "wrangler dev src/index.js"
},
"type": "module",
"author": "",
"license": "ISC",
"devDependencies": {
"hbs-import-transpile": "^1.0.4"
"@babel/core": "^7.24.8",
"@babel/preset-env": "^7.24.8",
"@babel/preset-react": "^7.24.7",
"babel-loader": "^9.1.3",
"css-loader": "^7.1.2",
"file-loader": "^6.2.0",
"style-loader": "^4.0.0",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@cloudflare/kv-asset-handler": "^0.3.4",
"buffer": "^6.0.3",
"handlebars": "^4.7.8",
"hbs-async-render": "^1.0.1",
"itty-router": "^2.6.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"serverless-cloudflare-workers": "^1.2.0"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useState } from 'react';
import logo from '../public/cloudflare.svg'
import { Header } from "./components/Header/Header";
import { Footer } from "./components/Footer/Footer";

export const App = () => {
const [count, setCount] = useState(0);
const tester = "Victor E";

return (
<div className="container">
<Header />
<div className="row">
<div className="col-12">
<div>
<div>
<img src={logo} width="300"/>
</div>
</div>
<h1>Hello, Cloudflare Workers!</h1>
<h3>This is a basic React page deployed on Cloudflare Workers.</h3>
<p>
<strong>Your name:</strong> { tester }
</p>
<pre>{ tester }</pre>

<p>Count: { count }</p>
<button type="button" onClick={ () => setCount(count + 1) }>Increase</button>
</div>
</div>
<Footer />
</div>
);
};
5 changes: 5 additions & 0 deletions client/src/components/Footer/Footer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const Footer = () => (
<footer style={{marginTop: "100px", padding: "30px"}} className='bg-light'>
Footer component.
</footer>
);
7 changes: 7 additions & 0 deletions client/src/components/Header/Header.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const Header = () => (
<nav className="navbar navbar-light bg-light mb-20">
<div className="container-fluid">
<span className="navbar-brand h1">Cloudflare React Worker</span>
</div>
</nav>
);
37 changes: 21 additions & 16 deletions client/src/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import { Router } from 'itty-router'
import { base64Handler, postHandler, rootHandler } from './routers'
import { registerHBHelper } from './utils/hbsAsyncHelper.js'
import '../assets/pages.js';
import '../assets/partials.js';
import { Router } from 'itty-router';
import * as routes from "./routers";

// Register HB
registerHBHelper();

// Create a new router
const router = Router();
router.get("/", rootHandler);

const { base64Handler, healthHandler, postHandler, rootHandler, routesAndAssetsHandler } = routes;

/** The rootHandler will serve the React app accordingly
* Other routes can be defined as neeeded
*/
router.get('/', rootHandler);
// Health route
router.get('/health', healthHandler);
// Test route
router.get("/base64/:text", base64Handler);
// Test post route
router.post("/post", postHandler);

/**
* This is the last route we define, it will match anything that hasn't hit a route we've defined
* above, therefore it's useful as a 404 (and avoids us hitting worker exceptions, so make sure
* to include it!).
*/
*/
router.all("*", () => new Response("404, not found!", { status: 404 }));

/**
* This snippet ties our worker to the router we defined above, all incoming requests
* are passed to the router where your routes are called and the response is sent.
*/
addEventListener('fetch', (e) => {
e.respondWith(router.handle(e.request))
* All incoming requests to the worker are passed to the router
* where your routes are called and the response is sent.
* routesAndAssetsHandler will map assets and routes accordingly
*/
addEventListener('fetch', event => {
event.respondWith(routesAndAssetsHandler(event, router));
});

6 changes: 6 additions & 0 deletions client/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { App } from './App';
import { createRoot } from 'react-dom/client';

// Render your React component instead
const root = createRoot(document.getElementById('root'));
root.render(<App />);
27 changes: 27 additions & 0 deletions client/src/routers/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getAssetFromKV } from "@cloudflare/kv-asset-handler";

export const routesAndAssetsHandler = async (event, router) => {
// Extract the request from the event
const request = event.request;

// Check if the request is for bundle.js
if (
request.url.endsWith('/bundle.js')
|| request.url.endsWith('/favicon.ico')
|| request.url.endsWith('.svg')
) {
// Serve the bundle.js file from KV storage
try {
// Pass the entire event object to getAssetFromKV
return await getAssetFromKV(event);
} catch (e) {
return new Response(`Bundle not found: ${e.message}`, {
status: 404,
statusText: 'Not Found',
});
}
}

// For any other requests, handle them with the router
return router.handle(request);
};
1 change: 1 addition & 0 deletions client/src/routers/health/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const healthHandler = () => new Response("success");
6 changes: 5 additions & 1 deletion client/src/routers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { base64Handler } from './encoding/base64/router.js';
import { healthHandler } from './health/router'
import { postHandler } from './post/router.js';
import { rootHandler } from './root/router.js';
import { routesAndAssetsHandler } from './handler';

export {
base64Handler,
healthHandler,
postHandler,
rootHandler
rootHandler,
routesAndAssetsHandler
}
6 changes: 0 additions & 6 deletions client/src/routers/root/html.js

This file was deleted.

35 changes: 23 additions & 12 deletions client/src/routers/root/router.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import Handlebars from 'handlebars/runtime.js';

import { hbsAsyncRender } from 'hbs-async-render'
// import { html } from './html';

export const rootHandler = async () => {
const output = await hbsAsyncRender(Handlebars, 'body', {name: "Victor E."});
return new Response(output, {headers: {'Content-Type': 'text/html'}});
// return new Response(html, {
// headers: {
// "Content-Type": "text/html"
// }
// })
// const html = ReactDOMServer.renderToString(<App />);
return new Response(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React App on Cloudflare Workers</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/css/bootstrap.min.css"/>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/js/bootstrap.min.js"></script>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
`, {
headers: {
'Content-Type': 'text/html',
},
});
};
20 changes: 0 additions & 20 deletions client/src/utils/hbsAsyncHelper.js

This file was deleted.

35 changes: 0 additions & 35 deletions client/src/views/pages/body.hbs

This file was deleted.

Empty file.
3 changes: 0 additions & 3 deletions client/src/views/partials/structure/footer.hbs

This file was deleted.

1 change: 0 additions & 1 deletion client/src/views/partials/structure/footerlibs.hbs

This file was deleted.

6 changes: 0 additions & 6 deletions client/src/views/partials/structure/header.hbs

This file was deleted.

2 changes: 0 additions & 2 deletions client/src/views/partials/structure/htmlhead.hbs

This file was deleted.

Loading

0 comments on commit 959aec7

Please sign in to comment.