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)
https://github.com/vercel/next.js/tree/canary/examples/with-docker
Docker 5
Add default /index.html. With links into different JS app areas.