diff --git a/.changeset/early-pens-itch.md b/.changeset/early-pens-itch.md new file mode 100644 index 0000000..6a1fb6c --- /dev/null +++ b/.changeset/early-pens-itch.md @@ -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) diff --git a/Dockerfile.contracts b/Dockerfile.contracts new file mode 100644 index 0000000..a4034d5 --- /dev/null +++ b/Dockerfile.contracts @@ -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"] \ No newline at end of file diff --git a/Dockerfile.frontend b/Dockerfile.frontend new file mode 100644 index 0000000..ba8a909 --- /dev/null +++ b/Dockerfile.frontend @@ -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"] diff --git a/README.md b/README.md index 8fa849c..fc83511 100644 --- a/README.md +++ b/README.md @@ -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. - -
-All Supported Chain Constants - -| 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 | - -Source: https://github.com/scio-labs/use-inkathon/blob/main/src/chains.ts - -> [!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). -
+### 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`. @@ -222,6 +202,15 @@ All environment variables are imported from `process.env` in [`frontend/src/conf \*️⃣ Required +#### 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. diff --git a/docker-compose.contracts.yaml b/docker-compose.contracts.yaml new file mode 100644 index 0000000..57b80d6 --- /dev/null +++ b/docker-compose.contracts.yaml @@ -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" \ No newline at end of file diff --git a/docker-compose.frontend.yaml b/docker-compose.frontend.yaml new file mode 100644 index 0000000..9156986 --- /dev/null +++ b/docker-compose.frontend.yaml @@ -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 \ No newline at end of file diff --git a/frontend/next.config.js b/frontend/next.config.js index 933fb15..23d0d80 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -2,6 +2,8 @@ /* eslint-env node */ // @ts-check +const path = require('path') + /** * @type {import('next').NextConfig} **/ @@ -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