Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react is working #1

Merged
merged 4 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading