JS Deploy
Intro
- After your javascript app is built, it needs to be hosted by publicly accessible webserver
- Simplest solution – get some free hosting (even enos.itcollege.ee/~homefolder should be good enough for that)
- Don’t forget to setup your servers root/home path – otherwise script inclusion paths are wrong. Routing also gets confused.
- If you want to use full html5 history mode for url, server needs some configuration (/invoice/client/5 vs /#invoice/client/5)
Docker 1
- Modern solution – deploy to docker
-
Commonly nginx image is used as base for js apps
-
Two possible nginx baseimages to use
- nginx:latest
- nginx:alpine
-
Alpine – special ultra-lightweight linux based image. Has some compatibility problems (uses different libc) on some rare cases.
-
Alpine linux image is ca 5X smaller
Docker 2
-
Minimal Dockerfile
-
Baseimage nginx:latest
- Copy all files and folders from ./dist/ to images html content folder (build your JS app in production mode first)
-
Build the container
> docker build -t js-nginx:latest .
-
Start the container (map local port 8080 to containers port 80)
> docker run -d -p 8080:80 js-nginx:latest
-
List running containers
> docker ps
-
Stop container (with id tacken from docker ps)
> docker container stop 425d351d2f35
Dockerfile
FROM nginx:latest
COPY ./dist /usr/share/nginx/html
Docker 3
- Supporting html5 history mode
- JS routers typically have two modes – using full urls or hashtags
- Problem with full urls – when new session is started with full url, server will respond with 404 – page not found. Because we actually only have one single page /index.html
- Servers need some configuration to rewrite urls to host the same page regardless of specified url (when exact match is not found).
- Nginx configuration (partial)
http {
server {
location / {
try_files $uri $uri/ /index.html;
}
}
}
Docker 4
- Typically for testing we need to deploy several JS apps side-by-side
- This allows us to use only one container
- Configure base paths in JS apps correctly
- Copy every JS app into separate directory inside docker image
- Copy nginx.conf also into container
FROM nginx:latest
COPY ./vue-app/dist /usr/share/nginx/html/vue-app
COPY nginx.conf /etc/nginx/nginx.conf
Vue 3 in subdir
- Add .env.production
BASE_URL=/vue-app
- Modify vite.config.ts, configure
base
import { fileURLToPath, URL } from "node:url";
import { defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
return {
plugins: [vue()],
base: env.BASE_URL,
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
};
});
React in subdir (classical)
- Add .env.production
PUBLIC_URL=/react-app
- modify router
ReactDOM.render(
<Router basename={process.env.PUBLIC_URL}>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById("root")
);
nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location /react-app/ {
# nextjs config to resolve /foo => /foo.html
try_files $uri $uri.html /react-app/index.html =404;
}
location /vue-app/ {
try_files $uri $uri/ /vue-app/index.html;
}
}
}
next.js spa - no serverside
-
Add .env.production for
npm run build
BASE_URL=/react-app
- Add .env.development for local
npm run dev
BASE_URL=
or check in code - when you use process.env.BASE_URL
to handle undefined
correctly.
const BASE_URL = process.env.BASE_URL || "";
Modify next.config.mjs
/** @type {import('next').NextConfig} */
const base_path = process.env.BASE_URL;
const nextConfig = {
output: "export",
distDir: "dist",
basePath: base_path,
};
export default nextConfig;
When using the next/image component, you will need to add the basePath in front of src.
<Image
src={process.env.BASE_URL + "/next.svg"}
alt="Vercel Logo"
/>
next.js in docker - needs node.js (standalone, includes ssr)
Docker 5
Add default /index.html. With links into different JS app areas.
Enos
In order to upload your files to enos.itcollege.ee, you can use some FTP client e.g. FileZilla (MacOS Intel/Windows) or Cyberduck (MacOS Intel & apple silicon/Windows).
Choose SFTP (Secure FTP)
+ new connection
server: enos.itcollege.ee
port: 22
username: your_uni_id
password: your_uni_id_password
add to keychain (SFTP uses SSH for secure transfer)
you might be prompted to add new key to known hosts folder
Uploading your files
- Locate home folder
- Find folder with your uni_id name
- Find public_html folder.
- Add a new folder inside public_html indicating the course or project name. E.g. `
- Upload your files to this folder.
Viewing files on the web
The link to view your public files is: https://enos.itcollege.ee/~your_uni_id/
If you have an index.html
file somewhere in the folder then this will be displayed instead of the default folder file structure.
History mode
Add .htaccess
file to your subdir to enable html5 history mode (instead of 404 on non-existing file request is directed to /subdir/index.html).
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /subdirectoryName
RewriteRule ^subdirectoryName/index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdirectoryName/index.html [L]
</IfModule>
Enos itcollege wiki
Possibly outdated!
Read additionally official itcollege wiki on enos topic. In more detail and pictures.