Tips for effectively deploying SvelteKit on a server without causing any disruptions to the user experience

After developing my information system using Sveltekit and setting up the server with Ubuntu 22.04 OS, PM2 as the process manager, and running the app on Node.js, I followed the Sveltekit documentation to deploy the app for a node adapter. Below is my svelte.config.js code:

import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/kit/vite';

import path from 'path';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    preprocess: vitePreprocess(),

    kit: {
        adapter: adapter({
            out: 'build',
            precompress: false,
            envPrefix: '',
            polyfill: true
        }),
        csrf: {
            checkOrigin: false,
        },
        alias: {
            '$src': path.resolve('./src')
        }
    },
    vitePlugin: {
        inspector: false
    }
};

export default config;

Once built, I simply run the command npm run preview to start the app. To integrate with PM2, I created an ecosystem.config.cjs file for easy management. Here's the configuration:

module.exports = {
    apps: [
        {
            name: "app_sistamu",
            script: "npm",
            args: "run preview -- --host --port 8080",
            watch: false,
            instances: "max",
            exec_mode: "cluster"
        },
        {
            name: "app_sistamu_DEV",
            script: "npm",
            args: "run dev -- --host --port 5173",
            out_file: "/dev/null",
            watch: false
        }
    ],
};

To finalize deployment, I merge changes from development to master branch with subsequent commands:

git merge -m "Merging branch development to master" development; npm install; npm run build; pm2 reload ecosystem.config.cjs --only app_sistamu

Although this process works well, rebuilding the app and reloading PM2 may briefly disrupt user interaction due to a 502 Bad Gateway error during the build phase. However, once completed, the app functions normally again.

This leads me to question how to streamline the deployment process without affecting user experience?

Answer №1

In order to transform my response into a solution:

When executing

git merge -m "Merging branch development to master" development; npm install; npm run build; pm2 reload ecosystem.config.cjs --only app_sistamu

If the application experiences disruptions during the building process, it is likely that npm run build is either clearing or deleting the dist directory that is being served by npm run preview.

To mitigate this issue, consider building into a separate directory and swiftly swapping them to minimize disruption:

# build into new directory
npm run build --outDir=dist-new
# move current dist out of the way
mkdir -p old-dist
mv dist old-dist/"$(date +%s)"
# move new directory into place
mv dist-new dist

Be sure to periodically clean up the old-dist directories to avoid clutter accumulation. :)

Answer №2

What is the best way to deploy an app without causing disruption to user interaction?

One common solution is:

  • Utilize Docker containers

In this scenario, a typical workflow involves separating the building and deployment of the application into two distinct parts.

Subsequently, on the production server:

  • Execute a Docker command to update the running container with a new image. Docker will seamlessly switch the container to use the new image, resulting in no interruptions.
docker pull frontend  # Pulls the new image to the local server cache
docker compose up -d frontend  # Switches to the new version 

This method is not exclusive to SvelteKit; it can be applied to any web server or web development project today.

The drawback of this approach is that one must acquire familiarity with Docker first, which can be overwhelming. Nonetheless, the knowledge of Docker is transferrable and beneficial for various deployment workflows across different tools and industries.

Answer №3

After multiple attempts, I believe I have finally cracked the code on solving this particular issue. Special thanks to auqust for sharing a helpful YouTube video that guided me through the process:

  1. Prior to starting the app development, ensure adapter-node is installed according to the documentation provided for your SvelteKit project. Once done, execute the build command to create the app - for instance, use npm run build in this scenario;
  2. Upon completion of building the app, you should see a directory named "build". I proceeded by moving all the files within this folder to a designated directory known as /var/www/production/. To transfer these files, simply initiate the command
    cp -a build/. /var/www/production/
    ;
  3. Access the specific directory. Initialize npm and include
    "type"="module"
    into the package.json file. Afterwards, install the express.js package by entering npm install -D express;
  4. Generate a new file titled server.js which will serve the application later on:
import express from "express";
import { handler } from "./handler.js";

const app  = express();
const port = 8080;

app.use(handler);

app.listen(port, () => {
    console.log(`The application is running on port ${port}`);
});
  1. Having opted to utilize PM2 for app execution, I designed an ecosystem.config.cjs file to operate PM2:
module.exports = {
    apps: [
        {
            name     : "app_sistamu",
            script   : "server.js",
            watch    : false,
            instances: "max",
            exec_mode: "cluster"
        }
    ],
};

To launch PM2, I utilized the command

pm2 start ecosystem.config.cjs --only app_sistamu
.

By following this procedure, future updates can be seamlessly applied by executing the build command, transferring the build files to the targeted directory, and reloading the PM2 instances. This method ensures zero downtime, resulting in no disruption for end users.

I trust this solution will be beneficial to others down the line. If there are any mistakes made or alternate solutions available, please share your thoughts below.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display toolbar title on small screens in separate lines

Recently, I encountered an issue while using v-toolbar in my vue app. Despite my efforts, I couldn't find a way to split the title into multiple lines on small screens. Currently, it displays as "Secti...." on smaller devices. Can anyone assist me wit ...

Steps to store a string with all characters in a JavaScript variable

I am faced with a situation where I need to pass variables that are considered Javascript objects, in a format similar to the following: var pageVars= [ { origin:'page', property:'name', value:'whatever' }, { origin:& ...

Locating the body tag within an AJAX HTML response

I have been experimenting with making an ajax call to retrieve content and then appending it in a certain way. Here is the code I am working with: $(function(){ var site = $('input').val(); $.get('file.php', { site:site }, func ...

Using React.JS: Display Object Map in rendering

I have an object with family information that looks like this: Family: Parent0: BirthPlace: "dsa" Birthday: "2021-01-04" Relationship: "dsa" SurnameAndName: "dasdsa" Parent1: BirthPlace: & ...

What is the best way to append characters to the end of a value if it is already present?

I have a functionality in place where clicking the post button inserts a random value into the database. It also displays an error if the same value already exists in the database, which is working fine. Now, I want to further enhance this by adding 2/3 c ...

Performing an AJAX request to validate a username when it loses

Hey everyone, I'm currently working on a script that checks the availability of a username in a MySQL database using an onblur event with AJAX. Here's the AJAX script: document.getElementById("r_username").onblur = function(){ var http ...

Tips for eliminating the backslash introduced by JQuery

Switching back from framework 4.5 to 4.0 caused several issues that needed fixing. One significant change I noticed was that jQuery started escaping double quotes. Is there a way to stop this behavior? I attempted datatest = datatest.replace("\\ ...

Is it possible to simultaneously execute an animate and a fade out effect?

Is there a way to simultaneously move "app1" to the left and fade it out? Currently, the functions are executing one after the other. I want them to occur simultaneously, without the left movement happening before the fade out. Thank you! <!DOCTYPE h ...

Jquery ajax failing to fetch data

There is a problem with Ajax not returning any data. http://jsfiddle.net/w67C4/ $.ajax({ dataType:'jsonp', url: url, async:false, success: function(data){ getUsername = data.user.id; }, }); The data being returned i ...

I'm puzzled as to why my Vuex modules are not functioning properly. I keep receiving the error message: "[vuex]

I've been searching for hours and can't figure out why I keep getting this error message: [vuex] unknown mutation type: groceryStore/getStoreApple on all of the commits to the mutations in the groceryStore-module. I believe I'm following the ...

Losing focus after typing just one letter

Having issues with a component containing multiple inputs; every time I try to type in one of the fields, it triggers a re-render and causes the input field to lose focus. export default function EventModal({ data, show, setShown }: Props) { const [sav ...

In React, ensure a component's state is preserved when the browser history changes

I recently developed a React application that features a classic layout with a left-side menu, title, footer, and main content section. The side menu includes navigation links structured using components such as <List>, <ListItem>, etc. from th ...

Struggling to get the Ant design button to launch an external link in a new tab using React and NextJS

I have an Ant button set up like this: <Button style={{ borderRadius: '0.5rem' }} type="default" target="_blank" ...

The attribute 'loaded' is not found in the 'HttpSentEvent' data type

Currently, I have implemented an Angular HTTP post request with the following parameters: this.http .post<{ body: any }>(environment.api.file.upload, reqBody, { reportProgress: true, observe: 'events', }) .subscribe((ev: HttpE ...

What is the best way to include a swf video in a list of hyperlinks?

My current code displays an image inside a box, and I am looking to replace the image with either a swf video or .AVI video. I have the object video code to play a swf video, but I need the video to be played within the box where the image is currently l ...

Struggling with making the Angular directive compatible with ng-container

Below is the code snippet where the ng-if condition is not behaving as anticipated If the value of displayGroup is D, it should display the first and second blocks. Can you spot any error in my logic? <div *ngIf="(bookTravelInfo.displayGroup | upp ...

What is the process for including additional properties with the JS spread operator?

Is there a more efficient way to achieve this task other than adding patientId and insuranceId to the spread operator in the code below? main.js const Response = await getData(re); const patientId = "AW364747"; const insuranceId = "0000786622"; logger( ...

Include an extra "array" in the complete AJAX POST data when submitting through x-editable

Struggling to include an array of objects in the post data for a group of bootstrap x-editable on my JSP page. The data is retrieved from a table and an array of objects is constructed. This array needs to be appended to the list of other values posted by ...

Angular 4 and the process of HTML encoding

Looking for assistance with html encoding in angular 4. I have product records stored in a database, with the fullDescription field in this particular format: &lt;div align="justify"&gt;&lt;span&gt; When using <div *ngIf="product" [inn ...

Add a class to a button in an Angular btn-group if a specific string is found within an

I am currently working on a project where I have multiple buttons that need to toggle an active class when selected in order to change their color. Below is a snippet of what I have: In the array called 'selected', I have: this.selected = [&ap ...