diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..d83d46e7c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,26 @@ +# build output +dist/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store +.idea/ +.eslintcache +.vercel +.puppeteer + +.astro +.gitignore diff --git a/.github/workflows/fly-deploy.yml b/.github/workflows/fly-deploy.yml new file mode 100644 index 000000000..b0c246ede --- /dev/null +++ b/.github/workflows/fly-deploy.yml @@ -0,0 +1,18 @@ +# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ + +name: Fly Deploy +on: + push: + branches: + - main +jobs: + deploy: + name: Deploy app + runs-on: ubuntu-latest + concurrency: deploy-group # optional: ensure only one action runs at a time + steps: + - uses: actions/checkout@v4 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --remote-only + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..61b03087e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +FROM node:20.11-slim as dependencies +WORKDIR /app + +# Install pnpm and build dependencies +RUN npm install -g pnpm@9.4.0 && \ + apt-get update -qq && \ + apt-get install -y python3 build-essential && \ + rm -rf /var/lib/apt/lists/* + +# Create the environments directory and env file FIRST +RUN mkdir -p src/environments && \ + echo "PLAYWRIGHT_BROWSERS_PATH=/app/pw-browsers" > src/environments/browser-path.env + +# Copy package files +COPY package.json pnpm-lock.yaml ./ + +# Install dependencies and extra packages needed for content generation +ENV PLAYWRIGHT_BROWSERS_PATH=/app/pw-browsers +ENV HUSKY=0 +RUN pnpm install && \ + pnpm add rehype-parse@9.0.0 html-escaper kleur && \ + pnpm playwright install chromium + +# Content generation stage +FROM dependencies as content-builder +WORKDIR /app + +# Copy source files +COPY . . + +# Copy over the node_modules and Playwright browsers +COPY --from=dependencies /app/node_modules ./node_modules +COPY --from=dependencies /app/pw-browsers ./pw-browsers +COPY --from=dependencies /app/src/environments/browser-path.env ./src/environments/browser-path.env + +# First generate the content +RUN pnpm run epub & pnpm run social-previews:build & wait + +# Run just the Astro build +RUN pnpm exec astro build --experimental-integrations || if [ -d "dist" ]; then \ + exit 0; \ + else \ + exit 1; \ + fi + +# Production stage for static files +FROM nginx:alpine +COPY --from=content-builder /app/dist /usr/share/nginx/html + +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/astro.config.ts b/astro.config.ts index 0d49c8b7a..792b93f7c 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -4,7 +4,6 @@ import sitemap from "@astrojs/sitemap"; import icon from "astro-icon"; import { EnumChangefreq as ChangeFreq } from "sitemap"; import { siteUrl } from "./src/constants/site-config"; -import vercel from "@astrojs/vercel"; import symlink from "symlink-dir"; import * as path from "path"; import { languages } from "./src/constants/index"; @@ -18,16 +17,15 @@ await symlink(path.resolve("content"), path.resolve("public/content")); export default defineConfig({ site: siteUrl, - adapter: vercel({ - // Uses Vercel's Image Optimization API: https://vercel.com/docs/image-optimization - imageService: true, - imagesConfig: { - sizes: SUPPORTED_IMAGE_SIZES, - domains: [], - formats: ["image/avif", "image/webp"], + output: "static", + image: { + service: { + entrypoint: "astro/assets/services/sharp", + config: { + limitInputPixels: false, + }, }, - devImageService: "sharp", - }), + }, integrations: [ icon(), preact({ compat: true }), diff --git a/fly.toml b/fly.toml new file mode 100644 index 000000000..322e20da7 --- /dev/null +++ b/fly.toml @@ -0,0 +1,22 @@ +# fly.toml app configuration file generated for playfulprogramming-bak on 2024-12-02T18:59:27-08:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = 'playfulprogramming-bak' +primary_region = 'sjc' + +[build] + dockerfile = 'Dockerfile' + +[http_service] + internal_port = 80 + force_https = true + auto_stop_machines = 'stop' + auto_start_machines = true + min_machines_running = 0 + +[[vm]] + memory = '1gb' + cpu_kind = 'shared' + cpus = 1 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 000000000..a07beb32e --- /dev/null +++ b/nginx.conf @@ -0,0 +1,17 @@ +server { + listen 80; + root /usr/share/nginx/html; + index index.html; + etag on; + + location / { + try_files $uri $uri/ /index.html; + add_header Cache-Control "no-cache"; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, no-transform"; + } +} \ No newline at end of file diff --git a/package.json b/package.json index ec2757b17..08e596175 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,7 @@ "dependencies": { "@oramacloud/client": "^1.3.18", "@tanstack/react-query": "^5.45.1", + "html-escaper": "^3.0.3", "medium-zoom": "^1.0.8", "preact": "10.23.2", "react-aria": "^3.31.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 64171e77f..cd72dec7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,6 +18,9 @@ importers: '@tanstack/react-query': specifier: ^5.45.1 version: 5.45.1(@preact/compat@17.1.2(preact@10.23.2)) + html-escaper: + specifier: ^3.0.3 + version: 3.0.3 medium-zoom: specifier: ^1.0.8 version: 1.1.0 diff --git a/src/components/image/picture.tsx b/src/components/image/picture.tsx index 0cb3f3197..302e1a5af 100644 --- a/src/components/image/picture.tsx +++ b/src/components/image/picture.tsx @@ -5,11 +5,10 @@ import { GetPictureUrls, } from "utils/get-picture"; import type { JSX } from "preact"; - interface PictureProps extends GetPictureOptions { urls?: GetPictureUrls; - alt: string; - class?: string; + alt: string; + class?: string; pictureAttrs?: JSX.HTMLAttributes & Record; imgAttrs?: JSX.HTMLAttributes & Record;