mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
image build process improvements (#1045)
* auto-generate .env.production file * env placeholders congruity check * refactor yarn dev and docker tasks * [skip ci] pass git tag and commit sha to dev app * [skip ci] clean up
This commit is contained in:
+2
-1
@@ -3,4 +3,5 @@ SENTRY_CSP_REPORT_URI=xxx
|
||||
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=xxx
|
||||
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx
|
||||
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=UA-XXXXXX-X
|
||||
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN=xxx
|
||||
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN=xxx
|
||||
NEXT_PUBLIC_AUTH0_CLIENT_ID=xxx
|
||||
@@ -1,80 +0,0 @@
|
||||
# app config
|
||||
NEXT_PUBLIC_APP_ENV=__PLACEHOLDER_FOR_NEXT_PUBLIC_APP_ENV__
|
||||
NEXT_PUBLIC_APP_INSTANCE=__PLACEHOLDER_FOR_NEXT_PUBLIC_APP_INSTANCE__
|
||||
NEXT_PUBLIC_APP_PROTOCOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_APP_PROTOCOL__
|
||||
NEXT_PUBLIC_APP_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_APP_HOST__
|
||||
NEXT_PUBLIC_APP_PORT=__PLACEHOLDER_FOR_NEXT_PUBLIC_APP_PORT__
|
||||
NEXT_PUBLIC_AUTH_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_AUTH_URL__
|
||||
|
||||
# version config
|
||||
NEXT_PUBLIC_GIT_COMMIT_SHA=__PLACEHOLDER_FOR_NEXT_PUBLIC_GIT_COMMIT_SHA__
|
||||
NEXT_PUBLIC_GIT_TAG=__PLACEHOLDER_FOR_NEXT_PUBLIC_GIT_TAG__
|
||||
|
||||
# network config
|
||||
NEXT_PUBLIC_NETWORK_NAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_NAME__
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_SHORT_NAME__
|
||||
NEXT_PUBLIC_NETWORK_LOGO=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_LOGO__
|
||||
NEXT_PUBLIC_NETWORK_LOGO_DARK=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_LOGO_DARK__
|
||||
NEXT_PUBLIC_NETWORK_ICON=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ICON__
|
||||
NEXT_PUBLIC_NETWORK_ICON_DARK=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ICON_DARK__
|
||||
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME__
|
||||
NEXT_PUBLIC_NETWORK_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ID__
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY_NAME__
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL__
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS__
|
||||
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS__
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=__PLACEHOLDER_FOR_NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED__
|
||||
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE__
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_RPC_URL__
|
||||
NEXT_PUBLIC_IS_TESTNET=__PLACEHOLDER_FOR_NEXT_PUBLIC_IS_TESTNET__
|
||||
|
||||
# ui config
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=__PLACEHOLDER_FOR_NEXT_PUBLIC_FEATURED_NETWORKS__
|
||||
NEXT_PUBLIC_FOOTER_LINKS=__PLACEHOLDER_FOR_NEXT_PUBLIC_FOOTER_LINKS__
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_EXPLORERS__
|
||||
NEXT_PUBLIC_OTHER_LINKS=__PLACEHOLDER_FOR_NEXT_PUBLIC_OTHER_LINKS__
|
||||
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_MARKETPLACE_CONFIG_URL__
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=__PLACEHOLDER_FOR_NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM__
|
||||
NEXT_PUBLIC_LOGOUT_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_LOGOUT_URL__
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_CHARTS__
|
||||
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR__
|
||||
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND__
|
||||
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER__
|
||||
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME__
|
||||
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP__
|
||||
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE__
|
||||
NEXT_PUBLIC_AD_BANNER_PROVIDER=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_BANNER_PROVIDER__
|
||||
NEXT_PUBLIC_AD_TEXT_PROVIDER=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_TEXT_PROVIDER__
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=__PLACEHOLDER_FOR_NEXT_PUBLIC_GRAPHIQL_TRANSACTION__
|
||||
NEXT_PUBLIC_WEB3_DEFAULT_WALLET=__PLACEHOLDER_FOR_NEXT_PUBLIC_WEB3_DEFAULT_WALLET__
|
||||
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=__PLACEHOLDER_FOR_NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET__
|
||||
NEXT_PUBLIC_HIDE_INDEXING_ALERT=__PLACEHOLDER_FOR_NEXT_PUBLIC_HIDE_INDEXING_ALERT__
|
||||
|
||||
# api config
|
||||
NEXT_PUBLIC_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_HOST__
|
||||
NEXT_PUBLIC_API_BASE_PATH=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_BASE_PATH__
|
||||
NEXT_PUBLIC_API_PROTOCOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_PROTOCOL__
|
||||
NEXT_PUBLIC_API_PORT=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_PORT__
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL__
|
||||
NEXT_PUBLIC_STATS_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_STATS_API_HOST__
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_VISUALIZE_API_HOST__
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_CONTRACT_INFO_API_HOST__
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_ADMIN_SERVICE_API_HOST__
|
||||
NEXT_PUBLIC_API_SPEC_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_SPEC_URL__
|
||||
|
||||
# external services config
|
||||
NEXT_PUBLIC_SENTRY_DSN=__PLACEHOLDER_FOR_NEXT_PUBLIC_SENTRY_DSN__
|
||||
NEXT_PUBLIC_AUTH0_CLIENT_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_AUTH0_CLIENT_ID__
|
||||
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID__
|
||||
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=__PLACEHOLDER_FOR_NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY__
|
||||
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID__
|
||||
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN=__PLACEHOLDER_FOR_NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN__
|
||||
|
||||
# l2 config
|
||||
NEXT_PUBLIC_IS_L2_NETWORK=__PLACEHOLDER_FOR_NEXT_PUBLIC_IS_L2_NETWORKL__
|
||||
NEXT_PUBLIC_L1_BASE_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_L1_BASE_URL__
|
||||
NEXT_PUBLIC_L2_WITHDRAWAL_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_L2_WITHDRAWAL_URL__
|
||||
|
||||
# beacon chain config
|
||||
NEXT_PUBLIC_HAS_BEACON_CHAIN=__PLACEHOLDER_FOR_NEXT_PUBLIC_HAS_BEACON_CHAIN__
|
||||
NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL__
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
node_modules
|
||||
node_modules_linux
|
||||
|
||||
playwright/envs.js
|
||||
playwright/envs.js
|
||||
deploy/tools/envs-validator/index.js
|
||||
+1
-7
@@ -3,7 +3,6 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
/node_modules_linux
|
||||
/**/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
@@ -48,9 +47,4 @@ yarn-error.log*
|
||||
/playwright/.browser/
|
||||
/playwright/envs.js
|
||||
|
||||
**.dec**
|
||||
|
||||
# tools: envs-validator
|
||||
/deploy/tools/envs-validator/index.js
|
||||
/deploy/tools/envs-validator/envs.ts
|
||||
/deploy/tools/envs-validator/schema.ts
|
||||
**.dec**
|
||||
Vendored
+9
-9
@@ -6,7 +6,7 @@
|
||||
// DEV SERVER
|
||||
{
|
||||
"type": "shell",
|
||||
"command": "yarn dev:${input:devServerConfig}",
|
||||
"command": "yarn dev:preset ${input:dev_config_preset}",
|
||||
"problemMatcher": [],
|
||||
"label": "dev server",
|
||||
"detail": "start local dev server",
|
||||
@@ -243,11 +243,11 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start:docker:poa_core",
|
||||
"type": "shell",
|
||||
"command": "yarn start:docker:preset ${input:dev_config_preset}",
|
||||
"problemMatcher": [],
|
||||
"label": "docker: run poa",
|
||||
"detail": "run docker container for POA network",
|
||||
"label": "docker: run",
|
||||
"detail": "run docker container with env preset",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared",
|
||||
@@ -311,17 +311,17 @@
|
||||
},
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "devServerConfig",
|
||||
"description": "Choose dev server config:",
|
||||
"id": "dev_config_preset",
|
||||
"description": "Choose dev server config preset:",
|
||||
"options": [
|
||||
"main",
|
||||
"main:L2",
|
||||
"main.L2",
|
||||
"poa_core",
|
||||
"eth_goerli",
|
||||
"eth",
|
||||
"localhost",
|
||||
],
|
||||
"default": ""
|
||||
"default": "main"
|
||||
},
|
||||
],
|
||||
}
|
||||
+34
-23
@@ -5,58 +5,72 @@ FROM node:18-alpine AS deps
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk add --no-cache libc6-compat
|
||||
|
||||
# Install dependencies for App
|
||||
### APP
|
||||
# Install dependencies
|
||||
WORKDIR /app
|
||||
COPY package.json yarn.lock ./
|
||||
RUN apk add git
|
||||
RUN yarn --frozen-lockfile
|
||||
|
||||
# Install dependencies for ENVs checker
|
||||
### ENV VARIABLES CHECKER
|
||||
# Install dependencies
|
||||
WORKDIR /envs-validator
|
||||
COPY ./deploy/tools/envs-validator/package.json ./deploy/tools/envs-validator/yarn.lock ./
|
||||
RUN yarn --frozen-lockfile
|
||||
|
||||
|
||||
# *****************************
|
||||
# ****** STAGE 2: Build *******
|
||||
# *****************************
|
||||
FROM node:18-alpine AS builder
|
||||
RUN apk add --no-cache --upgrade libc6-compat bash
|
||||
|
||||
# Build app for production
|
||||
# pass commit sha and git tag to the app image
|
||||
ARG GIT_COMMIT_SHA
|
||||
ENV NEXT_PUBLIC_GIT_COMMIT_SHA=$GIT_COMMIT_SHA
|
||||
ARG GIT_TAG
|
||||
ENV NEXT_PUBLIC_GIT_TAG=$GIT_TAG
|
||||
|
||||
ENV NODE_ENV production
|
||||
|
||||
### APP
|
||||
# Copy dependencies and source code
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
COPY .env.template .env.production
|
||||
RUN rm -rf ./deploy/tools/envs-validator
|
||||
|
||||
# Generate .env.production with ENVs placeholders and save build args into .env file
|
||||
COPY --chmod=+x ./deploy/scripts/make_envs_template.sh ./
|
||||
RUN ./make_envs_template.sh ./docs/ENVS.md
|
||||
|
||||
# Next.js collects completely anonymous telemetry data about general usage.
|
||||
# Learn more here: https://nextjs.org/telemetry
|
||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
# Build app for production
|
||||
RUN yarn build
|
||||
|
||||
# Build ENVs checker
|
||||
|
||||
### ENV VARIABLES CHECKER
|
||||
# Copy dependencies and source code, then build
|
||||
WORKDIR /envs-validator
|
||||
COPY --from=deps /envs-validator/node_modules ./node_modules
|
||||
COPY ./deploy/tools/envs-validator .
|
||||
COPY ./types/envs.ts .
|
||||
RUN yarn build
|
||||
|
||||
|
||||
# *****************************
|
||||
# ******* STAGE 3: Run ********
|
||||
# *****************************
|
||||
# Production image, copy all the files and run next
|
||||
FROM node:18-alpine AS runner
|
||||
RUN apk add --no-cache --upgrade bash
|
||||
|
||||
### APP
|
||||
WORKDIR /app
|
||||
|
||||
# pass commit sha to the app (uses by sentry.io as release version)
|
||||
ARG GIT_COMMIT_SHA
|
||||
ENV NEXT_PUBLIC_GIT_COMMIT_SHA=$GIT_COMMIT_SHA
|
||||
|
||||
# pass git tag to the app (for the footer link)
|
||||
ARG GIT_TAG
|
||||
ENV NEXT_PUBLIC_GIT_TAG=$GIT_TAG
|
||||
|
||||
ENV NODE_ENV production
|
||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
@@ -68,20 +82,17 @@ COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
COPY --from=builder /envs-validator/index.js ./envs-validator.js
|
||||
|
||||
# Copy scripts and ENV templates file
|
||||
COPY ./deploy/scripts/entrypoint.sh .
|
||||
COPY ./deploy/scripts/replace_envs.sh .
|
||||
COPY .env.template .
|
||||
# Copy scripts and ENVs file
|
||||
COPY --chmod=+x ./deploy/scripts/entrypoint.sh .
|
||||
COPY --chmod=+x ./deploy/scripts/replace_envs.sh .
|
||||
COPY --from=builder /app/.env.production .
|
||||
COPY --from=builder /app/.env .
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
RUN apk add --no-cache --upgrade bash
|
||||
RUN ["chmod", "+x", "./entrypoint.sh"]
|
||||
RUN ["chmod", "+x", "./replace_envs.sh"]
|
||||
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
|
||||
USER nextjs
|
||||
|
||||
@@ -26,13 +26,14 @@ NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
|
||||
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli
|
||||
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
|
||||
NEXT_PUBLIC_IS_TESTNET=true
|
||||
NEXT_PUBLIC_HAS_BEACON_CHAIN=false
|
||||
|
||||
# api config
|
||||
NEXT_PUBLIC_API_HOST=eth-goerli.blockscout.com
|
||||
|
||||
@@ -26,13 +26,14 @@ NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
|
||||
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli
|
||||
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
|
||||
NEXT_PUBLIC_IS_TESTNET=true
|
||||
NEXT_PUBLIC_HAS_BEACON_CHAIN=false
|
||||
|
||||
# api config
|
||||
NEXT_PUBLIC_API_HOST=blockscout-main.k8s-dev.blockscout.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Check run-time ENVs values integrity
|
||||
node "$(dirname "$0")/envs-validator.js" "$input"
|
||||
if [ $? != 0 ]; then
|
||||
echo ENV integrity check failed. 1>&2 && exit 1
|
||||
echo 🛑 ENV integrity check failed. 1>&2 && exit 1
|
||||
fi
|
||||
|
||||
# Execute script for replace build-time ENVs placeholders with their values at runtime
|
||||
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if the number of arguments provided is correct
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <input_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
input_file="$1"
|
||||
prefix="NEXT_PUBLIC_"
|
||||
|
||||
# Function to make the environment variables template file
|
||||
# It will read the input file, extract all prefixed string and use them as variables names
|
||||
# This variables will have placeholders for their values at buildtime which will be replaced with actual values at runtime
|
||||
make_envs_template_file() {
|
||||
output_file=".env.production"
|
||||
|
||||
# Check if file already exists and empty its content if it does
|
||||
if [ -f "$output_file" ]; then
|
||||
> "$output_file"
|
||||
fi
|
||||
|
||||
grep -oE "${prefix}[[:alnum:]_]+" "$input_file" | sort -u | while IFS= read -r var_name; do
|
||||
echo "$var_name=__PLACEHOLDER_FOR_${var_name}__" >> "$output_file"
|
||||
done
|
||||
}
|
||||
|
||||
# Function to save build-time environment variables to .env file
|
||||
save_build-time_envs() {
|
||||
output_file=".env"
|
||||
|
||||
# Check if file already exists and empty its content if it does or create a new one
|
||||
if [ -f "$output_file" ]; then
|
||||
> "$output_file"
|
||||
else
|
||||
touch "$output_file"
|
||||
fi
|
||||
|
||||
env | grep "^${prefix}" | while IFS= read -r line; do
|
||||
echo "$line" >> "$output_file"
|
||||
done
|
||||
}
|
||||
|
||||
make_envs_template_file
|
||||
save_build-time_envs
|
||||
@@ -3,7 +3,7 @@
|
||||
set +x
|
||||
|
||||
# config
|
||||
envFilename='.env.template'
|
||||
envFilename='.env.production'
|
||||
nextFolder='./.next/'
|
||||
|
||||
# replacing build-stage ENVs with run-stage ENVs
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/node_modules
|
||||
.env
|
||||
.env.production
|
||||
index.js
|
||||
envs.ts
|
||||
schema.ts
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
cp ../../../types/envs.ts .
|
||||
export NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD)
|
||||
export NEXT_PUBLIC_GIT_TAG=$(git describe --tags --abbrev=0)
|
||||
../../scripts/make_envs_template.sh ../../../docs/ENVS.md
|
||||
yarn build
|
||||
dotenv -e ../../../configs/envs/.env.main -e ../../../configs/envs/.env.secrets yarn validate
|
||||
@@ -1,30 +1,100 @@
|
||||
/* eslint-disable no-console */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type { ZodError } from 'zod-validation-error';
|
||||
import { fromZodError } from 'zod-validation-error';
|
||||
|
||||
import { nextPublicEnvsSchema } from './schema';
|
||||
|
||||
try {
|
||||
const appEnvs = Object.entries(process.env)
|
||||
.filter(([ key ]) => key.startsWith('NEXT_PUBLIC_'))
|
||||
.reduce((result, [ key, value ]) => {
|
||||
result[key] = value || '';
|
||||
return result;
|
||||
}, {} as Record<string, string>);
|
||||
run();
|
||||
|
||||
console.log(`⏳ Validating environment variables schema...`);
|
||||
nextPublicEnvsSchema.parse(appEnvs);
|
||||
console.log('👍 All good!\n');
|
||||
} catch (error) {
|
||||
const validationError = fromZodError(
|
||||
error as ZodError,
|
||||
{
|
||||
prefix: '',
|
||||
prefixSeparator: '\n ',
|
||||
issueSeparator: ';\n ',
|
||||
},
|
||||
);
|
||||
console.log(validationError);
|
||||
console.log('🚨 ENV set is invalid\n');
|
||||
process.exit(1);
|
||||
async function run() {
|
||||
console.log();
|
||||
try {
|
||||
const appEnvs = Object.entries(process.env)
|
||||
.filter(([ key ]) => key.startsWith('NEXT_PUBLIC_'))
|
||||
.reduce((result, [ key, value ]) => {
|
||||
result[key] = value || '';
|
||||
return result;
|
||||
}, {} as Record<string, string>);
|
||||
|
||||
await validateEnvsSchema(appEnvs);
|
||||
await checkPlaceholdersCongruity(appEnvs);
|
||||
|
||||
} catch (error) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
async function validateEnvsSchema(appEnvs: Record<string, string>) {
|
||||
try {
|
||||
console.log(`⏳ Validating environment variables schema...`);
|
||||
nextPublicEnvsSchema.parse(appEnvs);
|
||||
console.log('👍 All good!\n');
|
||||
} catch (error) {
|
||||
const validationError = fromZodError(
|
||||
error as ZodError,
|
||||
{
|
||||
prefix: '',
|
||||
prefixSeparator: '\n ',
|
||||
issueSeparator: ';\n ',
|
||||
},
|
||||
);
|
||||
console.log(validationError);
|
||||
console.log('🚨 Environment variables set is invalid.\n');
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function checkPlaceholdersCongruity(runTimeEnvs: Record<string, string>) {
|
||||
try {
|
||||
console.log(`⏳ Checking environment variables and their placeholders congruity...`);
|
||||
|
||||
const placeholders = await getEnvsPlaceholders(path.resolve(__dirname, '.env.production'));
|
||||
const buildTimeEnvs = await getEnvsPlaceholders(path.resolve(__dirname, '.env'));
|
||||
const envs = Object.keys(runTimeEnvs).filter((env) => !buildTimeEnvs.includes(env));
|
||||
|
||||
const inconsistencies: Array<string> = [];
|
||||
for (const env of envs) {
|
||||
const hasPlaceholder = placeholders.includes(env);
|
||||
if (!hasPlaceholder) {
|
||||
inconsistencies.push(env);
|
||||
}
|
||||
}
|
||||
|
||||
if (inconsistencies.length > 0) {
|
||||
console.log(`🚸 For the following environment variables placeholders were not generated at build-time:`);
|
||||
inconsistencies.forEach((env) => {
|
||||
console.log(` ${ env }`);
|
||||
});
|
||||
console.log('They are either deprecated or running the app with them may lead to unexpected behavior. Please check the documentation for more details.');
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
console.log('👍 All good!\n');
|
||||
} catch (error) {
|
||||
console.log('🚨 Congruity check failed.\n');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function getEnvsPlaceholders(filePath: string): Promise<Array<string>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.log(`⛔ Unable to read placeholders file.`);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = data.split('\n');
|
||||
const variables = lines.map(line => {
|
||||
const variable = line.split('=')[0];
|
||||
return variable.trim();
|
||||
});
|
||||
|
||||
resolve(variables.filter(Boolean));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn ts-to-zod ./envs.ts ./schema.ts && yarn webpack-cli -c ./webpack.config.js",
|
||||
"validate": "node ./index.js",
|
||||
"dev": "cp ../../../types/envs.ts ./ && yarn build && yarn dotenv -e ../../../configs/envs/.env.poa_core yarn validate"
|
||||
"dev": "./dev.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"ts-loader": "^9.4.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"target": "es2016",
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const path = require('path');
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
target: 'node',
|
||||
entry: path.resolve(__dirname) + '/index.ts',
|
||||
module: {
|
||||
rules: [
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Build-time environment variables
|
||||
|
||||
These variables are passed to the app during the image build process. They cannot be re-defined during the run-time.
|
||||
|
||||
| Variable | Type | Description | Optional | Example value |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_GIT_COMMIT_SHA | `string` | SHA of the latest commit in the branch from which image is build | false | `29d0613e` |
|
||||
| NEXT_PUBLIC_GIT_TAG | `string` | Git tag on the latest commit in the branch from which image is build | true | `v1.0.0` |
|
||||
@@ -58,16 +58,15 @@ For all types of dependencies:
|
||||
*Note*, if the variable should be exposed to the browser don't forget to add prefix `NEXT_PUBLIC_` to its name.
|
||||
|
||||
These are the steps that you have to follow to make everything work:
|
||||
1. Register variable placeholder in file `.env.template`; this is the most important step, without this the app will not receive variable value at run-time
|
||||
2. Document variable in the [/docs/ENVS.md](./ENVS.md) file; provide short description, its expected type, requirement flag, default and example value
|
||||
3. Make sure that you have added a property to React app config (`/configs/app/config.ts`) that is associated with this variable; do not use ENV variable values directly in the application code
|
||||
4. For local development purposes add the variable with its appropriate values to pre-defined ENV configs `/configs/envs` where it is needed
|
||||
5. Add the variable to CI configs where it is needed
|
||||
1. First and foremost, document variable in the [/docs/ENVS.md](./ENVS.md) file; provide short description, its expected type, requirement flag, default and example value; **do not skip this step** otherwise the app will not receive variable value at run-time
|
||||
2. Make sure that you have added a property to React app config (`/configs/app/config.ts`) that is associated with this variable; do not use ENV variable values directly in the application code
|
||||
3. For local development purposes add the variable with its appropriate values to pre-defined ENV configs `/configs/envs` where it is needed
|
||||
4. Add the variable to CI configs where it is needed
|
||||
- `deploy/values/review/values.yaml.gotmpl` - review development environment
|
||||
- `deploy/values/main/values.yaml` - main development environment
|
||||
- `deploy/values/review-l2/values.yaml.gotmpl` - review development environment for L2 networks
|
||||
- `deploy/values/l2-optimism-goerli/values.yaml` - main development environment
|
||||
6. Don't forget to mention in the PR notes that new ENV variable were added
|
||||
5. Don't forget to mention in the PR notes that new ENV variable were added
|
||||
|
||||
## Writing & Running Tests
|
||||
|
||||
@@ -137,10 +136,10 @@ We have 3 pre-configured projects. You can run your test with the desired projec
|
||||
| --- | --- |
|
||||
| **Running and building** |
|
||||
| `yarn dev` | run local dev server with user's configuration |
|
||||
| `yarn dev:<config_name>` | run local dev server with predefined configuration |
|
||||
| `yarn dev:preset <config_preset_name>` | run local dev server with predefined configuration |
|
||||
| `yarn build:docker` | build a docker image locally |
|
||||
| `yarn start:docker:local` | start an application from previously built local docker image with user's configuration |
|
||||
| `yarn start:docker:poa_core` | start an application from previously built local docker image with predefined configuration for POA network explorer |
|
||||
| `yarn start:docker:preset <config_preset_name>` | start an application from previously built local docker image with predefined configuration |
|
||||
| **Linting and formatting** |
|
||||
| `yarn lint:eslint` | lint project files with ESLint |
|
||||
| `yarn lint:eslint:fix` | lint project files with ESLint and automatically fix problems |
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Environment variables
|
||||
# Run-time environment variables
|
||||
|
||||
The app instance could be customized by passing following variables to NodeJS environment at runtime. See their list below.
|
||||
|
||||
|
||||
+7
-12
@@ -9,22 +9,17 @@
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev:localhost": "./node_modules/.bin/dotenv -e ./configs/envs/.env.localhost -e ./configs/envs/.env.secrets -- bash -c 'next dev -- -p \"$NEXT_PUBLIC_APP_PORT\"' | ./node_modules/.bin/pino-pretty",
|
||||
"dev:main": "./node_modules/.bin/dotenv -e ./configs/envs/.env.main -e ./configs/envs/.env.secrets -- bash -c 'next dev -- -p \"$NEXT_PUBLIC_APP_PORT\"' | ./node_modules/.bin/pino-pretty",
|
||||
"dev:main:L2": "./node_modules/.bin/dotenv -e ./configs/envs/.env.main.L2 -e ./configs/envs/.env.secrets -- bash -c 'next dev -- -p \"$NEXT_PUBLIC_APP_PORT\"' | ./node_modules/.bin/pino-pretty",
|
||||
"dev:poa_core": "./node_modules/.bin/dotenv -e ./configs/envs/.env.poa_core -e ./configs/envs/.env.secrets -- bash -c 'next dev -- -p \"$NEXT_PUBLIC_APP_PORT\"' | ./node_modules/.bin/pino-pretty",
|
||||
"dev:eth_goerli": "./node_modules/.bin/dotenv -e ./configs/envs/.env.eth_goerli -e ./configs/envs/.env.secrets -- bash -c 'next dev -- -p \"$NEXT_PUBLIC_APP_PORT\"' | ./node_modules/.bin/pino-pretty",
|
||||
"dev:eth": "./node_modules/.bin/dotenv -e ./configs/envs/.env.eth -e ./configs/envs/.env.secrets -- bash -c 'next dev -- -p \"$NEXT_PUBLIC_APP_PORT\"' | ./node_modules/.bin/pino-pretty",
|
||||
"dev:preset": "./tools/scripts/dev.preset.sh",
|
||||
"build": "next build",
|
||||
"build:docker": "docker build --build-arg GIT_COMMIT_SHA=$(git rev-parse HEAD) -t blockscout-frontend ./",
|
||||
"build:docker": "docker build --build-arg GIT_COMMIT_SHA=$(git rev-parse --short HEAD) --build-arg GIT_TAG=$(git describe --tags --abbrev=0) -t blockscout-frontend ./",
|
||||
"start": "next start",
|
||||
"start:docker:local": "docker run -p 3000:3000 --env-file .env.local blockscout-frontend",
|
||||
"start:docker:poa_core": "docker run -p 3000:3000 --env-file ./configs/envs/.env.poa_core --env-file ./configs/envs/.env.secrets blockscout-frontend",
|
||||
"lint:eslint": "./node_modules/.bin/eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"lint:eslint:fix": "./node_modules/.bin/eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"lint:tsc": "./node_modules/.bin/tsc -p ./tsconfig.json",
|
||||
"start:docker:preset": "./tools/scripts/docker.preset.sh",
|
||||
"lint:eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"lint:eslint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"lint:tsc": "tsc -p ./tsconfig.json",
|
||||
"prepare": "husky install",
|
||||
"format-svg": "./node_modules/.bin/svgo -r ./icons",
|
||||
"format-svg": "svgo -r ./icons",
|
||||
"test:pw": "./playwright/make-envs-script.sh && NODE_OPTIONS=\"--max-old-space-size=4096\" ./node_modules/.bin/dotenv -e ./configs/envs/.env.pw -- playwright test -c playwright-ct.config.ts",
|
||||
"test:pw:local": "export NODE_PATH=$(pwd)/node_modules && rm -rf ./playwright/.cache && yarn test:pw",
|
||||
"test:pw:docker": "docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.35.1-focal ./playwright/run-tests.sh",
|
||||
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: yarn dev:preset <preset_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preset_name="$1"
|
||||
config_file="./configs/envs/.env.${preset_name}"
|
||||
secrets_file="./configs/envs/.env.secrets"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "Error: File '$config_file' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$secrets_file" ]; then
|
||||
echo "Error: File '$secrets_file' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dotenv \
|
||||
-v NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) \
|
||||
-v NEXT_PUBLIC_GIT_TAG=$(git describe --tags --abbrev=0) \
|
||||
-e $config_file \
|
||||
-e $secrets_file \
|
||||
-- bash -c 'next dev -- -p $NEXT_PUBLIC_APP_PORT' |
|
||||
pino-pretty
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: yarn start:docker:preset <preset_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preset_name="$1"
|
||||
config_file="./configs/envs/.env.${preset_name}"
|
||||
secrets_file="./configs/envs/.env.secrets"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "Error: File '$config_file' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$secrets_file" ]; then
|
||||
echo "Error: File '$secrets_file' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker run -p 3000:3000 --env-file $config_file --env-file $secrets_file blockscout-frontend | pino-pretty
|
||||
Reference in New Issue
Block a user