Skip to content
Snippets Groups Projects
Commit 51d921a4 authored by Aaron Dötsch's avatar Aaron Dötsch
Browse files

Refactor static file handling to no longer need express

parent 6bd24928
No related branches found
No related tags found
No related merge requests found
...@@ -12,7 +12,6 @@ RUN npm i ...@@ -12,7 +12,6 @@ RUN npm i
COPY . . COPY . .
RUN npm run build && npm prune --omit=dev RUN npm run build && npm prune --omit=dev
RUN patch build/index.js < patch/index.js.patch
FROM node:22-alpine AS production FROM node:22-alpine AS production
......
This diff is collapsed.
*** build/index.js 2024-09-05 12:32:33.848369925 +0000
--- build/index2.js 2024-10-21 19:39:27.731467477 +0000
***************
*** 1,0 ****
--- 1,2 ----
+ import expressServer from 'express';
+ import nodePath from 'path';
***************
*** 258,264 ****
/** @type {NodeJS.Timeout | void} */
let idle_timeout_id;
! const server = polka().use(handler);
if (socket_activation) {
server.listen({ fd: SD_LISTEN_FDS_START }, () => {
--- 260,271 ----
/** @type {NodeJS.Timeout | void} */
let idle_timeout_id;
! const staticFilesDir = nodePath.join(env('DATA_DIR', '/app/data'), 'public');
!
! const server = polka()
! .get('/healthcheck', (req, res) => res.send('OK'))
! .use(expressServer.static(staticFilesDir, { dotfiles: "ignore" }))
! .use(handler);
if (socket_activation) {
server.listen({ fd: SD_LISTEN_FDS_START }, () => {
import { locales, type Locale, defaultLocale } from '$lib/i18n/i18n'; import { locales, type Locale, defaultLocale } from '$lib/i18n/i18n';
import { handle as handleAuthentication, handleAuthorization } from '$lib/server/auth'; import { handle as handleAuthentication, handleAuthorization } from '$lib/server/auth';
import { sendTrainingMails } from '$lib/server/mail'; import { sendTrainingMails } from '$lib/server/mail';
import type { Handle, RequestEvent } from '@sveltejs/kit'; import { publicPath } from '$lib/server/paths';
import { error, type Handle, type RequestEvent } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks'; import { sequence } from '@sveltejs/kit/hooks';
import mime from "mime-types";
import cron from "node-cron"; import cron from "node-cron";
import fs from "node:fs";
import path from "node:path";
cron.schedule("0 10 * * *", async ()=>{ cron.schedule("0 10 * * *", async ()=>{
await sendTrainingMails(); await sendTrainingMails();
...@@ -30,8 +34,29 @@ const handleLocale: Handle = ({event, resolve})=>{ ...@@ -30,8 +34,29 @@ const handleLocale: Handle = ({event, resolve})=>{
return resolve(event, { transformPageChunk: ({html})=>html.replace("%lang%", locale) }); return resolve(event, { transformPageChunk: ({html})=>html.replace("%lang%", locale) });
} }
const staticDirs = await fs.promises.readdir(publicPath);
const handleStaticFiles: Handle = async ({event, resolve})=>{
const reqPath = event.url.pathname.substring(1);
const firstDir = reqPath.substring(0, reqPath.indexOf("/"));
if(!staticDirs.includes(firstDir)) return resolve(event);
const filePath = path.join(publicPath, reqPath);
if(!filePath.startsWith(publicPath)) error(403, "Forbidden");
const pathParts = filePath.substring(publicPath.length).split("/");
if(pathParts.some(part => part.startsWith("."))) error(404, "Not Found"); // drop dotfiles
try {
const fileExists = await fs.promises.stat(filePath).then(stat => stat.isFile()).catch(()=>false);
if(!fileExists) error(404, "Not Found");
const file = fs.createReadStream(filePath);
const mimeType = mime.lookup(filePath) || "application/octet-stream";
return new Response(file as any, { status: 200, headers: { "Content-Type": mimeType } });
} catch(ex) {
error(404, "Not Found");
}
};
export const handle = sequence( export const handle = sequence(
handleAuthentication, handleAuthentication,
handleStaticFiles,
handleAuthorization, handleAuthorization,
handleLocale, handleLocale,
); );
...@@ -3,11 +3,12 @@ import path from "path"; ...@@ -3,11 +3,12 @@ import path from "path";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
const basePath = env.DATA_DIR ?? "/app/data"; const basePath = env.DATA_DIR ?? "/app/data";
export const publicPath = path.join(basePath, "public");
export const scheduleFontsPath = path.join(basePath, "fonts"); export const scheduleFontsPath = path.join(basePath, "fonts");
export const imagesPath = path.join(basePath, "public", "images"); export const imagesPath = path.join(publicPath, "images");
export const uploadsPath = path.join(basePath, "public", "uploads"); export const uploadsPath = path.join(publicPath, "uploads");
export const flyersPath = path.join(basePath, "public", "flyer"); export const flyersPath = path.join(publicPath, "flyer");
export const schedulesPath = path.join(basePath, "public", "stundenplaene"); export const schedulesPath = path.join(publicPath, "stundenplaene");
await Promise.all([scheduleFontsPath, imagesPath, uploadsPath, flyersPath, schedulesPath].map(path=>fs.mkdir(path, { recursive: true }))); await Promise.all([scheduleFontsPath, imagesPath, uploadsPath, flyersPath, schedulesPath].map(path=>fs.mkdir(path, { recursive: true })));
......
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig, type Plugin, type PreviewServer, type ViteDevServer } from 'vite'; import { defineConfig } from 'vite';
import express from 'express';
import path from 'path';
import dotenv from 'dotenv';
dotenv.config(); // Load .env file in dev, vite does not populate process.env and $env is only available in SvelteKit
const staticFiles = express.static(path.join(process.env.DATA_DIR ?? "/app/data", "/public"), { dotfiles: "ignore" });
const configureServerForStaticFiles = (server: ViteDevServer|PreviewServer)=>{
server.middlewares.use(staticFiles as any);
};
const staticFilePlugin: ()=>Plugin = ()=>({
name: "static-file-server",
configureServer: configureServerForStaticFiles,
configurePreviewServer: configureServerForStaticFiles,
});
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
sveltekit(), sveltekit(),
staticFilePlugin(),
], ],
}); });
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment