mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-26 02:23:21 +03:00
Add streaming text example
Signed-off-by: Mihovil Ilakovac <mihovil@ilakovac.com>
This commit is contained in:
parent
20eb9e007a
commit
5a33d3c91b
11
examples/streaming/.gitignore
vendored
Normal file
11
examples/streaming/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/.wasp/
|
||||
|
||||
# We ignore env files recognized and used by Wasp.
|
||||
.env.server
|
||||
.env.client
|
||||
|
||||
# To be extra safe, we by default ignore any files with `.env` extension in them.
|
||||
# If this is too agressive for you, consider allowing specific files with `!` operator,
|
||||
# or modify/delete these two lines.
|
||||
*.env
|
||||
*.env.*
|
1
examples/streaming/.wasproot
Normal file
1
examples/streaming/.wasproot
Normal file
@ -0,0 +1 @@
|
||||
File marking the root of Wasp project.
|
21
examples/streaming/main.wasp
Normal file
21
examples/streaming/main.wasp
Normal file
@ -0,0 +1,21 @@
|
||||
app streaming {
|
||||
wasp: {
|
||||
version: "^0.11.5"
|
||||
},
|
||||
title: "streaming"
|
||||
}
|
||||
|
||||
route RootRoute { path: "/", to: MainPage }
|
||||
page MainPage {
|
||||
component: import Main from "@client/MainPage.jsx"
|
||||
}
|
||||
|
||||
api streamingText {
|
||||
httpRoute: (GET, "/api/streaming-test"),
|
||||
fn: import { getText } from "@server/streaming.js",
|
||||
}
|
||||
|
||||
apiNamespace defaultMiddleware {
|
||||
path: "/api",
|
||||
middlewareConfigFn: import { getMiddlewareConfig } from "@server/streaming.js",
|
||||
}
|
3
examples/streaming/src/.waspignore
Normal file
3
examples/streaming/src/.waspignore
Normal file
@ -0,0 +1,3 @@
|
||||
# Ignore editor tmp files
|
||||
**/*~
|
||||
**/#*#
|
89
examples/streaming/src/client/Main.css
Normal file
89
examples/streaming/src/client/Main.css
Normal file
@ -0,0 +1,89 @@
|
||||
* {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 5rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main p {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.welcome-subtitle {
|
||||
font-weight: 400;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.buttons .button:not(:last-child) {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: 3px;
|
||||
font-size: 1.2rem;
|
||||
padding: 1rem 2rem;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-filled {
|
||||
border: 2px solid #bf9900;
|
||||
background-color: #bf9900;
|
||||
color: #f4f4f4;
|
||||
}
|
||||
|
||||
.button-outline {
|
||||
border: 2px solid #8a9cff;
|
||||
color: #8a9cff;
|
||||
background-color: none;
|
||||
}
|
||||
|
||||
code {
|
||||
border-radius: 5px;
|
||||
padding: 0.2rem;
|
||||
background: #efefef;
|
||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
||||
}
|
57
examples/streaming/src/client/MainPage.jsx
Normal file
57
examples/streaming/src/client/MainPage.jsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import config from "@wasp/config";
|
||||
import "./Main.css";
|
||||
|
||||
const MainPage = () => {
|
||||
const { response } = useTextStream("/api/streaming-test");
|
||||
return (
|
||||
<div className="container">
|
||||
<main>
|
||||
<h1>Streaming Demo</h1>
|
||||
<p
|
||||
style={{
|
||||
maxWidth: "600px",
|
||||
}}
|
||||
>
|
||||
{response}
|
||||
</p>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default MainPage;
|
||||
|
||||
function useTextStream(path) {
|
||||
const [response, setResponse] = useState("");
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
fetchStream(
|
||||
path,
|
||||
(chunk) => {
|
||||
setResponse((prev) => prev + chunk);
|
||||
},
|
||||
controller
|
||||
);
|
||||
return () => {
|
||||
controller.abort();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
response,
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchStream(path, onData, controller) {
|
||||
const response = await fetch(config.apiUrl + path, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
onData(value.toString());
|
||||
}
|
||||
}
|
55
examples/streaming/src/client/tsconfig.json
Normal file
55
examples/streaming/src/client/tsconfig.json
Normal file
@ -0,0 +1,55 @@
|
||||
// =============================== IMPORTANT =================================
|
||||
//
|
||||
// This file is only used for Wasp IDE support. You can change it to configure
|
||||
// your IDE checks, but none of these options will affect the TypeScript
|
||||
// compiler. Proper TS compiler configuration in Wasp is coming soon :)
|
||||
{
|
||||
"compilerOptions": {
|
||||
// JSX support
|
||||
"jsx": "preserve",
|
||||
"strict": true,
|
||||
// Allow default imports.
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
// Wasp needs the following settings enable IDE support in your source
|
||||
// files. Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/web-app/",
|
||||
"paths": {
|
||||
// Resolve all "@wasp" imports to the generated source code.
|
||||
"@wasp/*": [
|
||||
"src/*"
|
||||
],
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
},
|
||||
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
|
||||
"typeRoots": [
|
||||
"../../.wasp/out/web-app/node_modules/@types"
|
||||
],
|
||||
// Since this TS config is used only for IDE support and not for
|
||||
// compilation, the following directory doesn't exist. We need to specify
|
||||
// it to prevent this error:
|
||||
// https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file
|
||||
"outDir": "phantom"
|
||||
},
|
||||
"exclude": [
|
||||
"phantom"
|
||||
],
|
||||
}
|
1
examples/streaming/src/client/vite-env.d.ts
vendored
Normal file
1
examples/streaming/src/client/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="../../.wasp/out/web-app/node_modules/vite/client" />
|
BIN
examples/streaming/src/client/waspLogo.png
Normal file
BIN
examples/streaming/src/client/waspLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
29
examples/streaming/src/server/streaming.ts
Normal file
29
examples/streaming/src/server/streaming.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { StreamingText } from "@wasp/apis/types";
|
||||
import { MiddlewareConfigFn } from "@wasp/middleware";
|
||||
|
||||
// Custom API endpoint that returns a streaming text.
|
||||
export const getText: StreamingText = async (req, res, context) => {
|
||||
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
||||
res.setHeader("Transfer-Encoding", "chunked");
|
||||
|
||||
let counter = 1;
|
||||
res.write("Hm, let me see...\n");
|
||||
while (counter <= 10) {
|
||||
// Send a chunk of data.
|
||||
if (counter === 10) {
|
||||
res.write(`and finally about ${counter}.`);
|
||||
} else {
|
||||
res.write(`let's talk about number ${counter} and `);
|
||||
}
|
||||
counter++;
|
||||
// Wait for 1 second.
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
// End the response.
|
||||
res.end();
|
||||
};
|
||||
|
||||
// Returning the default config.
|
||||
export const getMiddlewareConfig: MiddlewareConfigFn = (config) => {
|
||||
return config;
|
||||
};
|
48
examples/streaming/src/server/tsconfig.json
Normal file
48
examples/streaming/src/server/tsconfig.json
Normal file
@ -0,0 +1,48 @@
|
||||
// =============================== IMPORTANT =================================
|
||||
//
|
||||
// This file is only used for Wasp IDE support. You can change it to configure
|
||||
// your IDE checks, but none of these options will affect the TypeScript
|
||||
// compiler. Proper TS compiler configuration in Wasp is coming soon :)
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Allows default imports.
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
// Wasp needs the following settings enable IDE support in your source
|
||||
// files. Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/server/",
|
||||
"paths": {
|
||||
// Resolve all "@wasp" imports to the generated source code.
|
||||
"@wasp/*": [
|
||||
"src/*"
|
||||
],
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
},
|
||||
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
|
||||
"typeRoots": [
|
||||
"../../.wasp/out/server/node_modules/@types"
|
||||
],
|
||||
// Since this TS config is used only for IDE support and not for
|
||||
// compilation, the following directory doesn't exist. We need to specify
|
||||
// it to prevent this error:
|
||||
// https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file
|
||||
"outDir": "phantom",
|
||||
},
|
||||
"exclude": [
|
||||
"phantom"
|
||||
],
|
||||
}
|
28
examples/streaming/src/shared/tsconfig.json
Normal file
28
examples/streaming/src/shared/tsconfig.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Enable default imports in TypeScript.
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
// The following settings enable IDE support in user-provided source files.
|
||||
// Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/server/",
|
||||
"paths": {
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
},
|
||||
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
|
||||
"typeRoots": ["../../.wasp/out/server/node_modules/@types"]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user