wasp-lang / wasp

The fastest way to develop full-stack web apps with React & Node.js.
https://wasp-lang.dev
MIT License
13.76k stars 1.18k forks source link

Support one-line deployments to Railway, fully featured #1232

Open Martinsos opened 1 year ago

Martinsos commented 1 year ago

Discussed in https://github.com/wasp-lang/wasp/discussions/1155

Originally posted by **OlegGulevskyy** April 20, 2023 As subject suggests, I think there is nice area for improvement - allow users to deploy Wasp to Railway in a matter of few commands (lesser - the better). Docs are already covering this topic, on [how to deploy to Railway](https://github.com/wasp-lang/wasp/issues/1153), but there is more to it than suggested in docs, and covering this in docs is cumbersome and just too much to ask devs to do it all the time manually. The main process described in the docs is the same (meaning, commands to navigate between dirs and deploy do not change). Currently the issue with Railway deployments is that Railway does not support SPAs routing. You can deploy a SPA with one single route just fine, but, if you use something like `react-router`, then your routes will be broken by displaying `404` on each of them. As described [here](https://discord.com/channels/713503345364697088/1019596063079944273/1019596063079944273), what seems to be the issue is `nginx` does not resolve correctly requested path, so its configuration has to be overwritten to redirect requests to `/index.html`, where react-router handles requests itself. I am not an expert on the subject and have very limited understanding on why and how this exactly works, but with X hours spent on trying to go around it, here is what worked for me. The idea here is that the entire app is deployed inside Docker container and it takes some `nginx` configuration file with it to the server, therefore few files additionally have to be created by Wasp during deployment. 1. Ensure `wasp` project is built by running `wasp build` in the project dir 2. Go to `/.wasp/build/web-app` and create 2 files: - Dockerfile. (note, it's important to use `FROM nginx:1.19.10-alpine` specific version, as using anything other than that threw a lot of exceptions on the server :\ ) ```dockerfile FROM node:18-alpine AS builder # Examples of any ENV variables that build requires for react app to have ARG PORT ARG WASP_WEB_CLIENT_URL ARG REACT_APP_API_URL ARG API_URL ENV REACT_APP_PORT=$PORT ENV REACT_APP_WASP_WEB_CLIENT_URL=$WASP_WEB_CLIENT_URL ENV REACT_APP_API_URL=$REACT_APP_API_URL # Add a work directory WORKDIR /app COPY package.json . RUN npm install COPY . /app/ RUN npm run build FROM nginx:1.19.10-alpine # Set working directory to nginx asset directory WORKDIR /usr/share/nginx/html # Remove default nginx static assets RUN rm -rf ./* COPY --from=builder /app/build . COPY .nginx/nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 3000 ENTRYPOINT ["nginx", "-g", "daemon off;"] ``` - .dockerignore ``` node_modules ``` 3. Create directory `/.nginx` inside the `web-app` dir. 4. Create file `nginx.conf` inside `/.nginx` dir with content ``` server { listen 8080; server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } } ``` 5. Make sure that `client` service in Railway has env variable `PORT` set to `8080` 6. Optionally (during the POC) I also disable `tsc` in `web-app/package.json` file, in `build` command as it was failing Docker to deploy things due to typing issues. But this should be handled in a different way (by making sure stuff inside Docker is aware of types) ``` "scripts": { "start": "npm run validate-env && vite", "build": "npm run validate-env && vite build", "validate-env": "node -r dotenv/config ./scripts/validate-env.mjs" }, ``` 7. Deploy with `railway up` The issue I see is that railway up is running in interactive mode if there are multiple services available, which potentially might be unexpected and I think it's best if it is possible to target a specific service without interactive mode (for CI/CD, for example?) I am enquiring if it's possible to do exactly that. Let me know your thoughts and I'd be hyped to see this available as one-liner! I'd be also happy to implement this logic myself, but haskell is a show stopper for me at the moment
Martinsos commented 1 year ago

This is being addressed by this PR: https://github.com/wasp-lang/wasp/pull/1157 .