Skip to content

Commit

Permalink
Merge pull request #50 from scio-labs/feat/29-dockerfile-for-developm…
Browse files Browse the repository at this point in the history
…ent-and-optional-deployment

feat: Setup Dockerfile for frontend app build
  • Loading branch information
wottpal authored Feb 5, 2024
2 parents 4c1f1c5 + df36d02 commit f50f9d2
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 22 deletions.
7 changes: 7 additions & 0 deletions .changeset/early-pens-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@inkathon/frontend": minor
"@inkathon/contracts": minor
---

- Setup Docker workflow for local development of frontend (Next.js Startup & Watching) and production build (non-Vercel deployments)
- Setup Docker workflow for local development of contracts (Rust & Substrate Contracts Node Setup, Contract Deployment)
48 changes: 48 additions & 0 deletions Dockerfile.contracts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
FROM paritytech/ci-linux:production as builder

WORKDIR /app
COPY . .

# Switch from sh to bash
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

RUN apt update

RUN echo "**Getting Ubuntu and Rust dependencies**"
RUN apt install -y build-essential pkg-config git clang curl libssl-dev llvm libudev-dev

RUN echo "**Installing node.js, pnpm, and package dependencies**"
# Install nvm and node
RUN mkdir -p /usr/local/nvm
ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION v20.9.0
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
RUN /bin/bash -c "source $NVM_DIR/nvm.sh && nvm install $NODE_VERSION && nvm use --delete-prefix $NODE_VERSION"
ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION/bin
ENV PATH $NODE_PATH:$PATH
# Install pnpm
RUN npm i --global --no-update-notifier --no-fund pnpm@8
RUN yes Y | pnpm install

RUN echo "*** Instaling Rust environment for contracts node***"
RUN rm -rf /usr/local/rustup /usr/local/cargo
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly
ENV PATH="/root/.cargo/bin:${PATH}"
RUN rustup default stable
RUN rustup update
RUN rustup target add wasm32-unknown-unknown
RUN rustup update nightly
RUN rustup target add wasm32-unknown-unknown --toolchain nightly
RUN rustup show
RUN rustup +nightly show
RUN cargo install contracts-node

RUN echo "*** Installing cargo-contract ***"
RUN rustup component add rust-src
RUN cargo install --force --locked cargo-contract

# Set and expose the port that the app will run on
EXPOSE 9944

# RUN echo "*** Start Substrate node template ***"
CMD [ "/usr/local/cargo/bin/substrate-contracts-node", "--dev", "--rpc-cors=all"]
58 changes: 58 additions & 0 deletions Dockerfile.frontend
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Inspired by https://www.darraghoriordan.com/2023/04/13/running-next-js-docker-container
# STAGE 1: A container with pnpm and python3 is required
FROM node:18-alpine as pnpm_base

WORKDIR /app
# install pnpm
RUN npm i --global --no-update-notifier --no-fund pnpm@8 \
# install python3 and other deps
&& apk add --no-cache g++=~13.2.1_git20231014-r0 make=~4.4.1-r2 py3-pip libc6-compat bash=~5.2.21-r0


# STAGE 2: fetch deps into the pnpm store
# We run pnpm fetch in a separate step to avoid re-fetching deps on every code change
FROM pnpm_base as fetched_deps
WORKDIR /app
# setting env to production usually speeds up installations
ENV NODE_ENV=production
COPY pnpm-lock.yaml ./
# set the store dir to a folder that is not in the project
RUN pnpm config set store-dir /workdir/.pnpm-store \
&& pnpm fetch

# STAGE 3: Copy the application code and install all deps from cache into the application
FROM fetched_deps as with_all_deps
# Copy whole project since it's using monorepo
COPY . ./
# Install all the deps
RUN pnpm install --offline

# STAGE 4: Build the NextJS app
# Use pnpm filter to only build the frontend app
# Then use pnpm deploy command to prune the dependencies
FROM with_all_deps as builder
RUN pnpm --filter='*frontend' build \
&& pnpm --filter='*frontend' deploy pruned --prod

# STAGE 5: Create a clean production image - only take pruned assets
FROM node:18-alpine AS runner
WORKDIR /app
# We set the NODE_ENV to production to make sure that the app runs in production mode
ENV NODE_ENV=production
# We add a non-root user to run the app for security reasons
RUN addgroup --system --gid 1001 app \
&& adduser --system --uid 1001 app
USER app

# Copy the built app assets from the builder stage
# NextJS produces a backend server and a frontend app
COPY --chown=app:app --from=builder /app/frontend/.next/standalone src/
COPY --chown=app:app --from=builder /app/frontend/public src/frontend/public
COPY --chown=app:app --from=builder /app/frontend/.next/static src/frontend/.next/static

# Set and expose the port that the app will run on
ENV PORT 3000
EXPOSE 3000

# Run the app
CMD ["node", "src/frontend/server.js"]
33 changes: 11 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,29 +187,9 @@ Spinning up a deployment via Vercel is pretty straightforward as the necessary s

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fhello-world&env=NEXT_PUBLIC_DEFAULT_CHAIN&envDescription=Insert%20%60alephzero-testnet%60%20or%20%60shibuya%60&envLink=https%3A%2F%2Fgithub.com%2Fscio-labs%2Finkathon%23environment-variables&project-name=inkathon&repository-name=inkathon&redirect-url=https%3A%2F%2Fgithub.com%2Fscio-labs%2Finkathon&demo-url=https%3A%2F%2Finkathon.xyz)

### Environment Variables

One key element making this boilerplate so flexible is the usage of environment variables to configure the active network in the frontend. This is done by setting the `NEXT_PUBLIC_DEFAULT_CHAIN` variable in the `frontend/.env.local` file, or in the Vercel deployment settings respectively.

<details>
<summary><strong>All Supported Chain Constants</strong></summary>

| Network Identifier | Name | Type |
| ------------------- | ----------------------- | ------- |
| `development` | ️Local Development Node | Testnet |
| `alephzero-testnet` | Aleph Zero Testnet | Testnet |
| `rococo` | Rococo | Testnet |
| `shibuya` | Shibuya Testnet | Testnet |
| `shiden` | Shiden | Mainnet |
| `alephzero` | Aleph Zero | Mainnet |
| `astar` | Astar | Mainnet |

<small>Source: https://github.com/scio-labs/use-inkathon/blob/main/src/chains.ts</small>

> [!NOTE]
> Chains can also be supplied manually by creating a [`SubstrateChain`](https://github.com/scio-labs/use-inkathon/blob/main/src/chains.ts#L4) object. If you think a chain is missing, please open an issue or PR.
Alternatively, you can also use the provided Dockerfiles to deploy to any hosting provider of your choice. Read more [here](https://github.com/scio-labs/inkathon/pull/50#issue-2041934251).

</details>
### Environment Variables

All environment variables are imported from `process.env` in [`frontend/src/config/environment.ts`](https://github.com/scio-labs/inkathon/blob/main/frontend/src/config/environment.ts) and re-exported from there. For improved type safety, Always only import environment variables from `@/config/environment` and never directly from `process.env`.

Expand All @@ -222,6 +202,15 @@ All environment variables are imported from `process.env` in [`frontend/src/conf

<small>\*️⃣ Required </small>

#### Supported Chains

One key element making this boilerplate so flexible is the usage of environment variables to configure the active network in the frontend. This is done by setting the `NEXT_PUBLIC_DEFAULT_CHAIN` variable in the `frontend/.env.local` file, or in the deployment settings respectively.

If your network is not provided by the `use-inkathon` library, you can add it manually by creating a new [`SubstrateChain`](https://github.com/scio-labs/use-inkathon/blob/main/src/chains.ts#L4) object. If you think a chain is missing, please open an issue or PR.

> [!IMPORTANT]
> All supported chain constants [can be found here](https://github.com/scio-labs/use-inkathon/blob/main/src/chains.ts) in the `scio-labs/use-inkathon` repository.
### Contract Deployment

In the [Getting Started](#getting-started) section above, we've already deployed the sample `Greeter` contract on a local node. To target a live network, we can use the `CHAIN` environment variable when running the `deploy` script.
Expand Down
11 changes: 11 additions & 0 deletions docker-compose.contracts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: '1.0'

services:
substrate-contracts-node:
build:
context: .
dockerfile: Dockerfile.contracts
image: contracts-node:latest
container_name: substrate-contracts-node
ports:
- "9944:9944"
29 changes: 29 additions & 0 deletions docker-compose.frontend.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
version: '1.0'
services:
frontend-dev:
container_name: inkathon-frontend-dev
build:
context: .
dockerfile: Dockerfile.frontend
target: with_all_deps
restart: always
command: pnpm run dev
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true
- WATCHPACK_POLLING=true
volumes:
- .:/app
- /app/node_modules
- /app/.next
ports:
- 3000:3000
frontend-prod:
container_name: inkathon-frontend-prod
build:
context: .
dockerfile: Dockerfile.frontend
args:
- NODE_ENV=production
ports:
- 3001:3000
3 changes: 3 additions & 0 deletions frontend/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/* eslint-env node */
// @ts-check

const path = require('path')

/**
* @type {import('next').NextConfig}
**/
Expand All @@ -10,6 +12,7 @@ const nextConfig = {
// Fix for warnings about cjs/esm package duplication
// See: https://github.com/polkadot-js/api/issues/5636
transpilePackages: ['@polkadot/.*'],
output: 'standalone',
}

module.exports = nextConfig

0 comments on commit f50f9d2

Please sign in to comment.