Newe
Newe

Reputation: 141

SvelteKit build (w/ adapter-node) 404 on newly created static files

Using @sveltejs/adapter-node: 1.0.0-next.61 and @sveltejs/kit: ^1.0.0-next.225

The following issue occurs only on the build version of the app, and not on the dev server, on which it doesn't occur.

When uploading a new file, my app keeps returning 404 regarding those newly created files as though the app is blind to those. Interestingly enough, said images are found when restarting the server.

The creation request succeeds: POST REQUEST 200

The file is correctly created on the filesystem and should be loaded by the page as seen in the json response which lists all files to be loaded on the page: file exists

However, when attempting to fetch the file, the server responds with a 404 although the path to it is correct: 404

Upvotes: 8

Views: 2293

Answers (4)

Luis Caparrós
Luis Caparrós

Reputation: 86

I got to sort it out by serving images in base64 format. So first at all I save the uploaded images out of static directory. Then I have an endpoint that returns the image, but that accept a parameter to apply for base64 format. Then in the html I add in the src of the image the base64 version of it.

My directory tree looks like:

src
├── app.html
├── images
├── lib
└── routes
    └── [imagePath]
        └── +server.js

Then +server.js looks like this:

import { error, json } from '@sveltejs/kit'
import fs from 'fs'

export async function GET({ url, params }) {
  const format = url.searchParams.get('format') ?? ''
  const { imagePath } = params
  const completeImagePath = `src/images/${imagePath}`
  if (fs.existsSync(completeImagePath)) {
    const image = fs.readFileSync(completeImagePath)
    if (format === 'base64') {
      const imageBase64 = fs.readFileSync(completeImagePath, { encoding: 'base64' })
      return json({ imageBase64 })
    } else {
      return new Response(image)
    }
  } else {
    error(404, {
      message: `Could not find ${params.imagePath}`
    })
  }
}

So now if we GET http://example.com/imageId.png, for example it will return the image, but if we add format parameter we can get the base64 code: http://example.com/imageId.png?format=base64

Then now in our .svelte files we can load this image on base64 format and pass it in the way below:

<img src={`data:image/png;base64, ${imageBase64}`} alt="image-alt" />

Where imageBase64 has been retrieved previously.

Upvotes: 0

Jacopo Pace
Jacopo Pace

Reputation: 492

Actually I found two solutions but both are just workarounds to this very annoying problem.

  • The import way: that's quite tricky to configure it properly (read also this) and, overall, it becomes a pain if you need to import dynamic paths (with variables inside the import path) as it was in my case.

  • The CDN way: use the static folder as a CDN by pointing there the webserver with a dedicated (sub)domain. This way you can link assets with success as they are "external" resources (e.g. https://cdn.mysite.com/file1.png, https://cdn.mysite.com/file2.jpg).

Bonus: if you choose the CDN workaround, can be a good idea to set handleFetch to bypass the external DNS resolution and keeping traffic internally.

Upvotes: 1

lazar
lazar

Reputation: 148

I fixed this problem by using an api endpoint to fetch my files. I also added some performance features. You can check the full article here: my medium article

Upvotes: 1

k1000
k1000

Reputation: 11

This problem can be solved by using a custom server with express to serve the static files. First run "npm run build" and add a server.js file into build path.

// server.js
import { handler } from './handler.js';
import express from 'express';

const app = express();

// add a route that lives separately from the SvelteKit app
app.get('/img/*', express.static('static'));

// let SvelteKit handle everything else, including serving prerendered pages and static assets
app.use(handler);

app.listen(3000, () => {
    console.log('listening on port 3000');
});

Then run "node server.js" instead of "node index.js"

Upvotes: 1

Related Questions