
1.引言
前端容器化是一種將前端應(yīng)用程序打包成容器的技術(shù),使其可以在不同的環(huán)境中快速、高效地部署和運(yùn)行。
2.背景
前后端分離的趨勢(shì)已形成現(xiàn)狀,前端工程復(fù)雜度疊加增長(zhǎng),新、老項(xiàng)目部署依賴(lài)的環(huán)境和Node.js版本會(huì)存在差異,生產(chǎn)環(huán)境下構(gòu)建混淆后的腳本、靜態(tài)資源文件依賴(lài)環(huán)境部署服務(wù)進(jìn)行訪問(wèn),前端工程未能形成"單體工件"部署,容器的出現(xiàn)大大簡(jiǎn)化了部署流程。
前端容器化可以方便的管理前端環(huán)境變量注入、運(yùn)行環(huán)境(不同項(xiàng)目依賴(lài)不同的node環(huán)境,node的版本兼容是個(gè)很大的問(wèn)題)、節(jié)約服務(wù)器成本、更快捷方便的版本回滾、多架構(gòu)部署、CI/CD自動(dòng)化集成部署、DevOps等等,好處只有多到你想不到(此處手動(dòng)偷笑)。
本文基于React項(xiàng)目結(jié)合Docker,分享在前端引入容器技術(shù)帶來(lái)的變革。
3.容器化在Github的運(yùn)用
github推出了github-action來(lái)做容器化的ci/cd,我下面展示用github-action做一個(gè)npm自動(dòng)化發(fā)包的示例:
- 在項(xiàng)目根目錄下新建.github/workflows/ci.yml文件
- 去npm官網(wǎng)申請(qǐng)一個(gè)token(具體怎么去申請(qǐng),請(qǐng)自己去搜索解決)
- 將這段代碼貼入ci.yml文件
- push代碼到master分支,就會(huì)自動(dòng)走ci/cd進(jìn)行部署啦!
name: CI
on:
push:
branches:
- master
jobs:
build:
# 指定操作系統(tǒng)
runs-on: ubuntu-latest
steps:
# 將代碼拉到虛擬機(jī)
- name: Checkout repository
uses: actions/checkout@v2
# 指定node版本
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '16.x'
registry-url: 'https://registry.npmjs.org'
# 依賴(lài)緩存策略
- name: Cache
id: cache-dependencies
uses: actions/cache@v3
with:
path: |
**/node_modules
key: ${{runner.OS}}-${{hashFiles('**/pnpm-lock.yaml')}}
- name: Install pnpm
run: npm install -g [email protected]
# 依賴(lài)下載
- name: Installing Dependencies
if: steps.cache-dependencies.outputs.cache-hit != 'true'
run: pnpm install
# 打包
- name: Running Build
run: pnpm run build
# 測(cè)試
- name: Running Test
run: pnpm run test-unit
# 發(fā)布
- name: Running Publish
run: npm publish
env:
# NPM_TOKEN is access token
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
4.基于docker構(gòu)建前端鏡像
在學(xué)習(xí)前端項(xiàng)目ci/cd構(gòu)建之前,讓我們先學(xué)習(xí)下前端鏡像怎么構(gòu)建
4.1 安裝docker
點(diǎn)此處坐飛機(jī)去安裝docker安裝完成后執(zhí)行以下命令查看docker版本,盡量帶buildx的版本
docker -v
Docker version 24.0.2, build cb74dfc
4.2 編寫(xiě)Dockerfile
這里先需要普及一個(gè)前端工程知識(shí),我們都知道一個(gè)基于npm的項(xiàng)目,需要一個(gè)package.json文件,然后執(zhí)行npm run install下載包,npm run build打包,打包出來(lái)的文件其實(shí)是不能直接運(yùn)行的,需要啟動(dòng)一個(gè)node服務(wù)運(yùn)行,所以我們就寫(xiě)一個(gè)最基本的基于node和Nginx的鏡像,示例如下
在項(xiàng)目根目錄下添加nginx配置文件,取名為nginx.conf,內(nèi)容如下
worker_processes 1;
events {
worker_connections 1024;
}
http {
sendfile on;
tcp_nodelay on;
keepalive_timeout 30;
include /etc/nginx/mime.types;
default_type Application/octet-stream;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/front/dist;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
location / {
try_files $uri $uri/ =404;
index index.html index.htm;
gzip_static on;
expires max;
add_header Cache-Control public;
if ($request_filename ~* ^.*?.(eot)|(ttf)|(woff)|(svg)|(otf)$) {
add_header Access-Control-Allow-Origin *;
}
}
}
}
在項(xiàng)目根目錄下添加docker配置文件,取名為Dockerfile,內(nèi)容如下
FROM node:17-buster as builder
WORKDIR /src
COPY ./ /src
RUN npm install -g pnpm
&& pnpm install
&& pnpm build
FROM nginx:alpine-slim
RUN mkdir /usr/share/nginx/front
&& mkdir /usr/share/nginx/front/dist
&& rm -rf /etc/nginx/nginx.conf
COPY --from=builder /src/nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /src/dist /usr/share/nginx/front/dist
EXPOSE 80
接下來(lái)使用docker build打包鏡像(如果有桌面工具,打包成功后docker桌面工具的images欄目能看到), docker run執(zhí)行鏡像(如果有桌面工具,運(yùn)行成功后docker桌面工具的contAIners欄目能看到), docker run運(yùn)行成功后可以打開(kāi)瀏覽器輸入:http://localhost 進(jìn)行查看
docker buildx build -t webapp-demo:v1 .
docker run -d -p 80:80 webapp-demo:v1
4.3 如何基于Dockerfile做pnpm緩存
這里我引用一段話(huà): 使用多階段構(gòu)建,構(gòu)建的鏡像中只包含了目標(biāo)文件夾 dist,但仍然存在一些問(wèn)題,當(dāng) package.json 文件變動(dòng)時(shí),RUN npm i && rm -rf ~/.npm 這一層會(huì)重新執(zhí)行,變更多次后,生成了大量的中間層鏡像。
為解決這個(gè)問(wèn)題,進(jìn)一步的我們可以設(shè)想一個(gè)類(lèi)似 數(shù)據(jù)卷 的功能,在鏡像構(gòu)建時(shí)把 node_modules 文件夾掛載上去,在構(gòu)建完成后,這個(gè) node_modules 文件夾會(huì)自動(dòng)卸載,實(shí)際的鏡像中并不包含 node_modules 這個(gè)文件夾,這樣我們就省去了每次獲取依賴(lài)的時(shí)間,大大增加了鏡像構(gòu)建效率,同時(shí)也避免了生成了大量的中間層鏡像。
此處課代表總結(jié)一下:就是盡量減少中間層鏡像的可能,最小化docker映像大小和構(gòu)建時(shí)間
由于我使用的是pnpm進(jìn)行npm包管理,所以我去翻閱了pnpm官方文檔關(guān)于此優(yōu)化如下:
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
FROM base AS build
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
FROM base
COPY --from=prod-deps /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
EXPOSE 8000
CMD [ "pnpm", "start" ]
于是本著依葫蘆畫(huà)瓢的精神,還有使用生產(chǎn)化的nginx配置,我找了同事寫(xiě)的nginx包裝鏡像,同樣你可以執(zhí)行docker build、docker run進(jìn)行驗(yàn)證,然后我改造后的代碼如下:
FROM node:17-buster AS builder
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /src
COPY ./ /src
RUN --mount=type=cache,target=/src/node_modules,id=myapp_pnpm_module,sharing=locked
--mount=type=cache,target=/pnpm/store,id=pnpm_cache
pnpm install
RUN --mount=type=cache,target=/src/node_modules,id=myapp_pnpm_module,sharing=locked
pnpm run build
FROM ghcr.io/zboyco/webrunner:0.0.7
COPY --from=builder /src/dist /app
4.4 如何利用buildx制作多架構(gòu)鏡像
docker buildx的工具,說(shuō)白了就是給你提供一個(gè)能力,當(dāng)你的宿主機(jī)是x86 64的架構(gòu)時(shí),你想構(gòu)建鏡像為ARM64的架構(gòu),就需要這個(gè)工具,給人的感覺(jué)有點(diǎn)類(lèi)似交叉編譯,諸如:go build的交叉編譯,在win10下編譯可執(zhí)行程序,可用于特定linux平臺(tái)
buildx本質(zhì)上調(diào)用了 buildkit 的 api,構(gòu)建是在 buildkit 的環(huán)境中進(jìn)行的。 是否支持多架構(gòu),取決于 buildkit 的環(huán)境,如果需要 buildkit支持多架構(gòu),需要在宿主機(jī)執(zhí)行(當(dāng)然這個(gè)不是必須的,按構(gòu)建的需求進(jìn)行控制,Docker桌面版無(wú)需進(jìn)行此項(xiàng)設(shè)置):
docker run --privileged --rm tonistiigi/binfmt --install all
我們這里改造上面Dockerfile代碼,使它支持多架構(gòu),由于platform是實(shí)驗(yàn)性質(zhì),所以需要先執(zhí)行docker pull docker/dockerfile 拉取鏡像
# syntax = docker/dockerfile:experimental
# --platform, 會(huì)讓 builder 只會(huì)有一份,且 arch 與宿主機(jī)一致
FROM --platform=${BUILDPLATFORM:-linux/amd64} node:17-buster AS builder
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /src
COPY ./ /src
RUN --mount=type=cache,target=/src/node_modules,id=myapp_pnpm_module,sharing=locked
--mount=type=cache,target=/pnpm/store,id=pnpm_cache
pnpm install
RUN --mount=type=cache,target=/src/node_modules,id=myapp_pnpm_module,sharing=locked
pnpm run build
FROM ghcr.io/zboyco/webrunner:0.0.7
COPY --from=builder /src/dist /app
在執(zhí)行打包鏡像命令之前,我們先查看下我們機(jī)器默認(rèn)的 builder 實(shí)例
docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default docker
default default running v0.11.7-0.20230525183624-798ad6b0ce9f linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
desktop-linux * docker
desktop-linux desktop-linux running v0.11.7-0.20230525183624-798ad6b0ce9f linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
使用buildx執(zhí)行上面的腳本打包鏡像會(huì)報(bào)錯(cuò)如下
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t webapp-official-website:v1 .
ERROR: Multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")
由于 Docker 默認(rèn)的 builder 實(shí)例不支持同時(shí)指定多個(gè) --platform,我們必須首先創(chuàng)建一個(gè)新的 builder 實(shí)例。同時(shí)由于國(guó)內(nèi)拉取鏡像較緩慢,我們可以使用配置了鏡像加速地址的 dockerpracticesig/buildkit:master 鏡像替換官方鏡像。
如果你有私有的鏡像加速器,可以基于 https://github.com/docker-practice/buildx 構(gòu)建自己的 buildkit 鏡像并使用它。
# 適用于國(guó)內(nèi)環(huán)境
$ docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master
# 適用于騰訊云環(huán)境(騰訊云主機(jī)、coding.NET 持續(xù)集成)
$ docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master-tencent
# $ docker buildx create --name mybuilder --driver docker-container
$ docker buildx use mybuilder
我們選擇適用于國(guó)內(nèi)環(huán)境的方案的命令進(jìn)行創(chuàng)建, 可以看到多了name為 mybuilder-cn 的實(shí)例
docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master
docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
mybuilder-cn * docker-container
mybuilder-cn0 desktop-linux inactive
default docker
default default running v0.11.7-0.20230525183624-798ad6b0ce9f linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
desktop-linux docker
desktop-linux desktop-linux running v0.11.7-0.20230525183624-798ad6b0ce9f linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
$ docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t myusername/hello . --push
# 查看鏡像信息
$ docker buildx imagetools inspect myusername/hello
在不同架構(gòu)運(yùn)行該鏡像,可以得到該架構(gòu)的信息。
$ docker run -it --rm myusername/hello
5.如何利用容器化做前端環(huán)境變量注入
- 前端雖然對(duì)環(huán)境變量的需求場(chǎng)景不多,但是基本的api baseURL, appName, env這些是需要的
- 如果是微前端的場(chǎng)景,那么需要的其他網(wǎng)站url都是環(huán)境變量,還挺多的
- 依稀記得剛?cè)胄袝r(shí),前端區(qū)分測(cè)試環(huán)境,線上環(huán)境就是直接通過(guò)域名進(jìn)行判斷,例如: inlcudes(url, ".com")?, 然后得到isProd去獲取項(xiàng)目中配置的不同環(huán)境的變量,這樣顯得很low
- 后面出了vue, react這種框架,可以在npm run dev時(shí)候指明--prod,然后通過(guò)process拿到isProd,去獲取對(duì)應(yīng)配置
- 現(xiàn)在可以直接通過(guò)容器化注入環(huán)境變量,然后使用nginx將容器中的環(huán)境變量注入前端項(xiàng)目html的meta標(biāo)簽content中, 然后從meta標(biāo)簽獲取變量
- 如果是monorepo項(xiàng)目,npm run build的時(shí)候,Dockerfile里面也需要通過(guò)容器中的環(huán)境變量獲取打包哪個(gè)項(xiàng)目
- 測(cè)試環(huán)境通過(guò)ts文件配置環(huán)境變量,然后項(xiàng)目啟動(dòng)時(shí)組合這些環(huán)境變量信息,生成config default.yml, ci/cd時(shí)k8s自動(dòng)將default.yml中配置的環(huán)境變量寫(xiě)入容器中
- 線上環(huán)境直接提供UI頁(yè)面配置環(huán)境變量,然后調(diào)用api,后端api通過(guò)k8s將變量寫(xiě)入容器中
- 如何通過(guò)k8s讀取配置的環(huán)境變量并寫(xiě)入容器中且聽(tīng)下回分解
下面貼一段生產(chǎn)場(chǎng)景下的Dockerfile示例代碼(公司應(yīng)該不會(huì)砍我吧!),這里省略k8s如何往容器中注入環(huán)境變量,只考慮如何從容器中讀取環(huán)境變量(假設(shè)環(huán)境變量已經(jīng)注入容器中)
FROM --platform=${BUILDPLATFORM} hub-dev.rockontrol.com/rk-infrav2/docker.io/library/node:17-bullseye as builder
WORKDIR /src
COPY ./ ./
ARG APP
ARG ENV
ARG PROJECT_GROUP
ARG PROJECT_NAME
ARG PROJECT_VERSION
ARG YARN_NPM_REGISTRY_SERVER
RUN npm install -g --registry=${YARN_NPM_REGISTRY_SERVER} pnpm
RUN pnpm --registry=${YARN_NPM_REGISTRY_SERVER} install
RUN PROJECT_GROUP=${PROJECT_GROUP} PROJECT_VERSION=${PROJECT_VERSION}
npx devkit build --prod ${APP} ${ENV}
FROM hub-dev.rockontrol.com/rk-infrav2/ghcr.io/zboyco/webrunner:0.0.7
ARG PROJECT_NAME
COPY --from=builder /src/public/${PROJECT_NAME} /app
下面貼一段nginx如何將環(huán)境變量寫(xiě)入html中
#!/bin/sh
# This script is used to start the application
# 初始化一個(gè)字符串,用于存儲(chǔ)拼接后的值
app_config="${APP_CONFIG}"
ext_config=""
# 遍歷所有環(huán)境變量
for var in $(env | cut -d= -f1); do
# 檢查變量是否以 "APP_CONFIG__" 開(kāi)頭
if [ "$(echo "$var" | grep '^APP_CONFIG__')" ]; then
# 去除變量名前綴 "APP_CONFIG__"
trimmed_var=$(echo "$var" | sed 's/^APP_CONFIG__//')
# 使用 eval 來(lái)獲取變量值并拼接到字符串中
value=$(eval echo "$$var")
app_config="${app_config},${trimmed_var}=${value}"
fi
done
# 去掉起始的逗號(hào)
export app_config=$(echo "$app_config" | sed 's/^,//')
# 解析app_config變量
# 以,分割 app_config
IFS=","
set -- $app_config
# 遍歷數(shù)組
for config in "$@"; do
# 以等號(hào)分剝數(shù)組
IFS="="
set -- $config
# 將單個(gè)環(huán)境變量單獨(dú)注入
ext_config="${ext_config} sub_filter '__$1__' '$2';n"
echo "$1: $2"
done
# Install envsubst
echo "Installing envsubst"
# 將擴(kuò)展變量替換到 conf.template 中
sed "s@__EXTENT_CONFIG__@${ext_config}@g" /etc/nginx/conf.d/conf-base.template > /etc/nginx/conf.d/conf.template
envsubst '${PROJECT_VERSION} ${ENV} ${app_config}' < /etc/nginx/conf.d/conf.template > /etc/nginx/conf.d/default.conf
# Start nginx
echo "Starting nginx"
nginx -g 'daemon off;'
下面貼一段前端如何從html meta標(biāo)簽中讀取環(huán)境變量
import appConfig from "../../config";
interface IConfig {
appName: string;
baseURL: string;
version?: string;
env?: string;
}
export function getConfig(): IConfig {
const defaultAppConfig = {
appName: "",
version: "",
env: "",
baseURL: "",
};
console.log("metaEnv", import.meta.env);
if (import.meta.env.DEV) {
return appConfig;
} else {
const appConfigStr = getMeta("app_config");
if (!appConfigStr) return defaultAppConfig;
return parseEnvVar(appConfigStr);
}
}
function getMeta(metaName: string) {
const metas = document.getElementsByTagName("meta");
for (let i = 0; i < metas.length; i++) {
if (metas[i].getAttribute("name") === metaName) {
return metas[i].getAttribute("content");
}
}
return "";
}
function parseEnvVar(envVarURL: string) {
const arrs = envVarURL.split(",");
return arrs.reduce((pre, item) => {
const keyValues = item.split("=");
return {
...pre,
[keyValues[0]]: keyValues[1],
};
}, {} as IConfig);
}
const BASE_URL = getConfig().baseURL;
const instance = axIOS.create({
baseURL: BASE_URL,
headers: {
"Content-Type": "application/json",
},
timeout: 60000, // 超時(shí)時(shí)間60秒
});
最后的最后,都貼了Dockerfile了,那就一不做二不休,貼個(gè)真實(shí)場(chǎng)景下的ci文件源碼吧!!!
stages:
- ship
- deploy
ship:
stage: ship
image: hub-dev.rockontrol.com/rk-infrav2/gitlab-runner-buildx:0.0.0-b0450fe
# variables:
# MULTI_ARCH_BUILDER: 1
before_script:
- echo "${DOCKER_PASSword}" | docker login "${DOCKER_REGISTRY}" -u="${DOCKER_USERNAME}" --password-stdin
- BUILDKIT_NAME=node-buildkit hx buildx ci-setup
script:
- export PLATFORM=linux/amd64,linux/arm64
- |
if [[ -f ./.platform ]]; then
source ./.platform
else
echo "WARNING, there is no .platform in project, USE default PLATFORM=${PLATFORM} "
fi
- hx buildx --with-builder --push --platform=${PLATFORM}
tags:
- webapp
deploy:
stage: deploy
script:
- hx config
- hx deploy
dependencies:
- ship
tags:
- webapp
6.前端應(yīng)用的Kubernetes部署
Kubernetes是一個(gè)開(kāi)源的容器編排平臺(tái),可以實(shí)現(xiàn)自動(dòng)化部署、擴(kuò)展和管理容器化應(yīng)用程序。以下是將前端應(yīng)用部署到Kubernetes集群的步驟:
6.1 創(chuàng)建Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-app
spec:
replicas: 3
selector:
matchLabels:
app: frontend-app
template:
metadata:
labels:
app: frontend-app
spec:
containers:
- name: frontend-app
image: my-frontend-app:latest
ports:
- containerPort: 3000
6.2 創(chuàng)建Service
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
6.3 部署到Kubernetes集群
使用kubectl命令部署應(yīng)用到Kubernetes集群:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
現(xiàn)在,您的前端應(yīng)用已經(jīng)在Kubernetes集群中運(yùn)行,并可以通過(guò)LoadBalancer類(lèi)型的Service外部訪問(wèn)。
7.關(guān)于前端React項(xiàng)目架構(gòu)
7.1 核心技術(shù)
- 打包編譯 - vite
- 包管理 - pnpm
- 編程語(yǔ)言 - typescript
- 前端框架 - react
- 路由 - react-router
- UI組件庫(kù) - antd
- cssinjs(不考慮性能開(kāi)銷(xiāo)) - emotion
- 全局?jǐn)?shù)據(jù)共享 - zustand
- 自動(dòng)生成api - openapi
- 網(wǎng)絡(luò)請(qǐng)求 - axios
- 數(shù)據(jù)請(qǐng)求利器 - react-query
- 通用hook(可不用) - ahooks
- 錯(cuò)誤邊界 - react-error-boundary
- 前端日志(暫未集成) - sentry-JAVAscript
- hack - babel
- 代碼檢查 - eslint
- ts代碼檢查插件 - typescript-eslint
- 代碼美化 - prettier
- git鉤子 - husky
- commit格式化 -commitlint
7.2 基于openapi自動(dòng)獲取api請(qǐng)求函數(shù)
// src/core/openapi/index.ts
// 示例代碼
generateService({
// openapi地址
schemaPath: `${appConfig.baseURL}/${urlPath}`,
// 文件生成目錄
serversPath: "./src",
// 自定義網(wǎng)絡(luò)請(qǐng)求函數(shù)路徑
requestImportStatement: `/// <reference types="./typings.d.ts" />nimport request from "@request"`,
// 代碼組織命名空間, 例如:Api
namespace: "Api",
});
7.3 調(diào)用接口(react-query), 支持自動(dòng)loading和接口請(qǐng)求聯(lián)動(dòng)
// HelloGet是一個(gè)基于axios的promise請(qǐng)求
export async function HelloGet(
// 疊加生成的Param類(lèi)型 (非body參數(shù)swagger默認(rèn)沒(méi)有生成對(duì)象)
params: Api.HelloGetParams,
options?: { [key: string]: any },
) {
return request<Api.HelloResp>('/gin-demo-server/api/v1/hello', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
// 自動(dòng)調(diào)用接口獲取數(shù)據(jù)
const { data, isLoading } = useQuery({
queryKey: ["hello", name],
queryFn: () => {
return HelloGet({ name: name });
},
});
export async function HelloPost(body: Api.HelloPostParam, options?: { [key: string]: any }) {
return request<Api.HelloResp>('/gin-demo-server/api/v1/hello', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
// 提交編輯數(shù)據(jù)
const { mutate, isLoading } = useMutation({
mutationFn: HelloPost,
onSuccess(data) {
setName(data?.data || "");
},
onError() {
// 清除queryKey為hello的接口數(shù)據(jù)緩存,自動(dòng)重新獲取接口數(shù)據(jù)
queryClient.invalidateQueries({ queryKey: ['hello'] });
}
})
mutate({ name: "lisi" });
8.前端React代碼CLI
代碼地址:https://github.com/rookie-luochao/create-vite-app-cli
9.結(jié)語(yǔ)
- 介紹了gitlab-action的在前端npm領(lǐng)域的基本配置
- 介紹了前端Dockerfile文件的編寫(xiě),以及pnpm在docker的優(yōu)化方案,如何利用buildx生成前端多架構(gòu)鏡像
- 介紹了生產(chǎn)場(chǎng)景下前端環(huán)境變量的使用
- 介紹了前端React項(xiàng)目技術(shù)架構(gòu)方案