diff --git a/.github/workflows/deploy_test_web.yaml b/.github/workflows/deploy_test_web.yaml index 49a96458f9b14..f7d3339d77f41 100644 --- a/.github/workflows/deploy_test_web.yaml +++ b/.github/workflows/deploy_test_web.yaml @@ -62,7 +62,7 @@ jobs: with: SSH_PRIVATE_KEY: ${{ env.SSH_PRIVATE_KEY }} ARGS: "-rlgoDzvc -i" - SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key" + SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/server.cjs frontend/appflowy_web_app/start.sh frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key" REMOTE_HOST: ${{ env.REMOTE_HOST }} REMOTE_USER: ${{ env.REMOTE_USER }} EXCLUDE: "frontend/appflowy_web_app/dist/, frontend/appflowy_web_app/node_modules/" diff --git a/frontend/appflowy_web_app/Dockerfile b/frontend/appflowy_web_app/Dockerfile index e7094ffe145e6..97e3a85559177 100644 --- a/frontend/appflowy_web_app/Dockerfile +++ b/frontend/appflowy_web_app/Dockerfile @@ -1,8 +1,14 @@ -FROM node:latest +FROM oven/bun:latest + +WORKDIR /app RUN apt-get update && \ apt-get install -y nginx +RUN bun install cheerio pino axios pino-pretty + +COPY . . + RUN addgroup --system nginx && \ adduser --system --no-create-home --disabled-login --ingroup nginx nginx @@ -18,6 +24,11 @@ COPY nginx-signed.key /etc/ssl/private/nginx-signed.key RUN chown -R nginx:nginx /etc/ssl/certs/nginx-signed.crt /etc/ssl/private/nginx-signed.key +COPY start.sh /app/start.sh + +RUN chmod +x /app/start.sh + + EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"] +CMD ["/app/start.sh"] diff --git a/frontend/appflowy_web_app/index.html b/frontend/appflowy_web_app/index.html index 3d8bc89cd60b0..a71f082fc36b9 100644 --- a/frontend/appflowy_web_app/index.html +++ b/frontend/appflowy_web_app/index.html @@ -4,8 +4,28 @@ - AppFlowy + + + + + + + + + + +
diff --git a/frontend/appflowy_web_app/nginx.conf b/frontend/appflowy_web_app/nginx.conf index 56529cca1aecf..729255a7786ed 100644 --- a/frontend/appflowy_web_app/nginx.conf +++ b/frontend/appflowy_web_app/nginx.conf @@ -30,6 +30,10 @@ http { gzip_http_version 1.0; + gzip_comp_level 5; + + gzip_vary on; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/wasm; # Existing server block for HTTP @@ -61,15 +65,22 @@ http { ssl_prefer_server_ciphers on; location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri $uri/ /index.html; + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; } location /static/ { root /usr/share/nginx/html; expires 30d; access_log off; + location ~* \.wasm$ { + types { application/wasm wasm; } + default_type application/wasm; + } } location /appflowy.svg { diff --git a/frontend/appflowy_web_app/pnpm-lock.yaml b/frontend/appflowy_web_app/pnpm-lock.yaml index b3e7c8496aaa4..37a34b9470ce9 100644 --- a/frontend/appflowy_web_app/pnpm-lock.yaml +++ b/frontend/appflowy_web_app/pnpm-lock.yaml @@ -8862,7 +8862,7 @@ packages: /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: - safe-buffer: 5.1.2 + safe-buffer: 5.2.1 dev: true /react-beautiful-dnd@13.1.1(react-dom@18.2.0)(react@18.2.0): @@ -9604,6 +9604,10 @@ packages: /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + /safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} diff --git a/frontend/appflowy_web_app/server.cjs b/frontend/appflowy_web_app/server.cjs new file mode 100644 index 0000000000000..e13c337faa394 --- /dev/null +++ b/frontend/appflowy_web_app/server.cjs @@ -0,0 +1,114 @@ +const path = require('path'); +const fs = require('fs'); +const pino = require('pino'); +const cheerio = require('cheerio'); +const axios = require('axios'); + +const distDir = path.join(__dirname, 'dist'); +const indexPath = path.join(distDir, 'index.html'); + +const setOrUpdateMetaTag = ($, selector, attribute, content) => { + if ($(selector).length === 0) { + $('head').append(``); + } else { + $(selector).attr('content', content); + } +}; +// Create a new logger instance +const logger = pino({ + transport: { + target: 'pino-pretty', + level: 'info', + options: { + colorize: true, + translateTime: 'SYS:standard', + destination: `${__dirname}/pino-logger.log`, + }, + }, +}); + +const logRequestTimer = (req) => { + const start = Date.now(); + const pathname = new URL(req.url).pathname; + logger.info(`Incoming request: ${pathname}`); + return () => { + const duration = Date.now() - start; + logger.info(`Request for ${pathname} took ${duration}ms`); + }; +}; + +const fetchMetaData = async (url) => { + try { + const response = await axios.get(url); + return response.data; + } catch (error) { + logger.error('Error fetching meta data', error); + return null; + } +}; + +const createServer = async (req) => { + const timer = logRequestTimer(req); + + if (req.method === 'GET') { + const pageId = req.url.split('/').pop(); + let htmlData = fs.readFileSync(indexPath, 'utf8'); + const $ = cheerio.load(htmlData); + if (!pageId) { + timer(); + return new Response($.html(), { + headers: { 'Content-Type': 'text/html' }, + }); + } + + const description = 'Write, share, comment, react, and publish docs quickly and securely on AppFlowy.'; + let title = 'AppFlowy'; + const url = 'https://appflowy.com'; + let image = 'https://d3uafhn8yrvdfn.cloudfront.net/website/production/_next/static/media/og-image.e347bfb5.png'; + // Inject meta data into the HTML to support SEO and social sharing + // if (metaData) { + // title = metaData.title; + // image = metaData.image; + // } + + $('title').text(title); + setOrUpdateMetaTag($, 'meta[name="description"]', 'name', description); + setOrUpdateMetaTag($, 'meta[property="og:title"]', 'property', title); + setOrUpdateMetaTag($, 'meta[property="og:description"]', 'property', description); + setOrUpdateMetaTag($, 'meta[property="og:image"]', 'property', image); + setOrUpdateMetaTag($, 'meta[property="og:url"]', 'property', url); + setOrUpdateMetaTag($, 'meta[property="og:type"]', 'property', 'article'); + setOrUpdateMetaTag($, 'meta[name="twitter:card"]', 'name', 'summary_large_image'); + setOrUpdateMetaTag($, 'meta[name="twitter:title"]', 'name', title); + setOrUpdateMetaTag($, 'meta[name="twitter:description"]', 'name', description); + setOrUpdateMetaTag($, 'meta[name="twitter:image"]', 'name', image); + + timer(); + return new Response($.html(), { + headers: { 'Content-Type': 'text/html' }, + }); + } else { + timer(); + logger.error({ message: 'Method not allowed', method: req.method }); + return new Response('Method not allowed', { status: 405 }); + } +}; + +const start = () => { + try { + Bun.serve({ + port: 3000, + fetch: createServer, + error: (err) => { + logger.error(`Internal Server Error: ${err}`); + return new Response('Internal Server Error', { status: 500 }); + }, + }); + logger.info(`Server is running on port 3000`); + } catch (err) { + logger.error(err); + process.exit(1); + } +}; + +start(); diff --git a/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx b/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx index 8820296780a10..02a27f17ed0d0 100644 --- a/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx +++ b/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx @@ -30,6 +30,7 @@ function CollaborativeEditor({ doc }: { doc: Y.Doc }) { useEffect(() => { if (!editor) return; + editor.connect(); setIsConnected(true); diff --git a/frontend/appflowy_web_app/start.sh b/frontend/appflowy_web_app/start.sh new file mode 100644 index 0000000000000..b4691baa1ae79 --- /dev/null +++ b/frontend/appflowy_web_app/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Start the frontend server +bun run server.cjs & + +# Start the nginx server +service nginx start + +tail -f /dev/null +