Compare commits
74 Commits
51e2c87828
...
42ccd7c049
Author | SHA1 | Date | |
---|---|---|---|
42ccd7c049 | |||
abbe9f6531 | |||
c61d9a9355 | |||
504788e991 | |||
8ab7fa45b5 | |||
1732030bf0 | |||
42fcfde81d | |||
d8724ef952 | |||
73e019913a | |||
0c75cbf3a4 | |||
3c00d793e2 | |||
33a261d757 | |||
cc0ad4a2c8 | |||
b4c7a0386d | |||
2f22303de5 | |||
|
e205bc1942 | ||
|
e1dff5ce69 | ||
|
1f691f91e3 | ||
1e7e9be5f6 | |||
|
4fbdcdae37 | ||
cb5142d648 | |||
|
ec69e9403a | ||
|
fee2f40de7 | ||
|
6070ab11ae | ||
2f28366cca | |||
b8a59c7205 | |||
85c2005d0a | |||
|
64e0c71ab4 | ||
|
e057b66bcd | ||
dfc2ce806e | |||
dba22a3b3e | |||
|
05be1ee86a | ||
57a8463a69 | |||
6a59de3e0a | |||
b8577e9d46 | |||
116ea59ab3 | |||
38f29890c1 | |||
9560e2d12b | |||
fbb5dbfcde | |||
9f161840a2 | |||
|
58e4f88d3b | ||
|
d4c86e26d5 | ||
138bbad1ea | |||
6e9c97b650 | |||
0f067e344b | |||
6f85e334fb | |||
1cf5f91f49 | |||
66d4a0c842 | |||
0f642439ec | |||
39d3003600 | |||
02a20b4ab2 | |||
9f5c7d036c | |||
555665274d | |||
|
4e2bd4e267 | ||
|
858c85c6d9 | ||
0e2da22ed8 | |||
c37169e590 | |||
7daff00e94 | |||
34ea3c2353 | |||
09b644f3a2 | |||
|
a6dc513e27 | ||
|
a1ba1e1c5e | ||
|
8792c5262a | ||
|
39daa26779 | ||
|
d079b1c73a | ||
|
24c397bc3b | ||
7d1e2e9b02 | |||
13115c849b | |||
|
37ccf6b593 | ||
|
324ea28d39 | ||
72d8fba305 | |||
a549820459 | |||
|
5fdd391545 | ||
|
8415c981b8 |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
18
.drone.yml
Normal file
18
.drone.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: Build and Push to Local Registry
|
||||
|
||||
steps:
|
||||
- name: Build and Push Docker Image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
# Custom registry address
|
||||
registry: localhost:32000
|
||||
# Repository name (include registry address in repo path)
|
||||
repo: localhost:32000/log101-dot-dev
|
||||
# Tags for the image
|
||||
tags:
|
||||
- latest
|
||||
- ${DRONE_COMMIT_SHA:0:7}
|
||||
# Allow insecure connections (for HTTP registries)
|
||||
insecure: true
|
|
@ -1,18 +1,45 @@
|
|||
run-name: ${{ gitea.actor }}, deploy to docker registry
|
||||
name: Build and Push Docker Image
|
||||
run-name: Build triggered by ${{ gitea.actor }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04 # Using specific Ubuntu version instead of latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to private registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.acayip.dev
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Generate image tag
|
||||
id: meta
|
||||
run: |
|
||||
VERSION=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
||||
echo "TAG=registry.acayip.dev/log101-dot-dev:${VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: registry.container-registry:5000/log101-blog:latest
|
||||
context: .
|
||||
push: ${{ gitea.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.TAG }}
|
||||
# Add build caching for faster builds
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
# Add labels for better tracking
|
||||
labels: |
|
||||
org.opencontainers.image.source=${{ gitea.repository }}
|
||||
org.opencontainers.image.revision=${{ gitea.sha }}
|
||||
org.opencontainers.image.created=${{ gitea.event.created_at }}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
FROM node:lts AS build
|
||||
FROM oven/bun AS build
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
RUN bun install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
ENV PUBLIC_BACKEND_HOST=https://api.acayip.dev
|
||||
RUN bun run build
|
||||
|
||||
FROM nginx:alpine AS runtime
|
||||
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
|
|
50
Jenkinsfile
vendored
Normal file
50
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
pipeline {
|
||||
agent {
|
||||
docker {
|
||||
image 'ubuntu-latest'
|
||||
}
|
||||
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git(branch: 'main', url: 'https://git.acayip.dev/log101/log101-dot-dev.git')
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build Docker Image') {
|
||||
steps {
|
||||
script {
|
||||
docker.build("${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
stage('Push to microk8s Registry') {
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry("http://${REGISTRY}") {
|
||||
docker.image("${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}").push()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
stage('Cleanup') {
|
||||
steps {
|
||||
script {
|
||||
sh "docker rmi ${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG} || true"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
environment {
|
||||
DOCKER_IMAGE = 'log101-dot-dev'
|
||||
DOCKER_TAG = 'latest'
|
||||
REGISTRY = '192.168.88.252:5000'
|
||||
}
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
> Geçmesi imkansız geçmiş, gelmesi imkansız gelecek...
|
||||
|
||||
log101.dev blog
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import remarkToc from "remark-toc";
|
|||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: "https://blog.log101.dev",
|
||||
site: "https://blog.acayip.dev",
|
||||
markdown: {
|
||||
remarkPlugins: [[remarkToc, { heading: "İçindekiler" }]],
|
||||
shikiConfig: {
|
||||
|
|
23
chart/.helmignore
Normal file
23
chart/.helmignore
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
24
chart/Chart.yaml
Normal file
24
chart/Chart.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
name: blog
|
||||
description: blog.log101.dev helm chart
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "1.0.0"
|
22
chart/templates/NOTES.txt
Normal file
22
chart/templates/NOTES.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "chart.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "chart.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
62
chart/templates/_helpers.tpl
Normal file
62
chart/templates/_helpers.tpl
Normal file
|
@ -0,0 +1,62 @@
|
|||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "chart.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "chart.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "chart.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "chart.labels" -}}
|
||||
helm.sh/chart: {{ include "chart.chart" . }}
|
||||
{{ include "chart.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "chart.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "chart.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "chart.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "chart.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
86
chart/templates/deployment.yaml
Normal file
86
chart/templates/deployment.yaml
Normal file
|
@ -0,0 +1,86 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "chart.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "chart.serviceAccountName" . }}
|
||||
{{- with .Values.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.containerPort | default 8080 }} # ← Now points to 8080
|
||||
protocol: TCP
|
||||
{{- if .Values.env }}
|
||||
env:
|
||||
{{- range $key, $value := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.volumeMounts }}
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.volumes }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
32
chart/templates/hpa.yaml
Normal file
32
chart/templates/hpa.yaml
Normal file
|
@ -0,0 +1,32 @@
|
|||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "chart.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
43
chart/templates/ingress.yaml
Normal file
43
chart/templates/ingress.yaml
Normal file
|
@ -0,0 +1,43 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- with .pathType }}
|
||||
pathType: {{ . }}
|
||||
{{- end }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "chart.fullname" $ }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
13
chart/templates/service.yaml
Normal file
13
chart/templates/service.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}
|
||||
labels: {{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector: {{- include "chart.selectorLabels" . | nindent 4 }}
|
13
chart/templates/serviceaccount.yaml
Normal file
13
chart/templates/serviceaccount.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "chart.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
|
||||
{{- end }}
|
15
chart/templates/tests/test-connection.yaml
Normal file
15
chart/templates/tests/test-connection.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "chart.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "chart.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
136
chart/values.yaml
Normal file
136
chart/values.yaml
Normal file
|
@ -0,0 +1,136 @@
|
|||
# Default values for chart.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
|
||||
replicaCount: 1
|
||||
revisionHistoryLimit: 3
|
||||
|
||||
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
|
||||
image:
|
||||
repository: registry.acayip.dev/log101-dot-dev
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets:
|
||||
- name: acayip-registry-secret
|
||||
# This is to override the chart name.
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Automatically mount a ServiceAccount's API credentials?
|
||||
automount: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
# This is for setting Kubernetes Annotations to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
podAnnotations: {}
|
||||
# This is for setting Kubernetes Labels to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext:
|
||||
{}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext:
|
||||
{}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/
|
||||
service:
|
||||
# This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
|
||||
type: ClusterIP
|
||||
# This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports
|
||||
port: 8080
|
||||
|
||||
containerPort: 8080
|
||||
|
||||
# Environment variables to be passed to the container
|
||||
env:
|
||||
PUBLIC_BACKEND_HOST: "https://api.acayip.dev"
|
||||
|
||||
# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||
ingress:
|
||||
enabled: true
|
||||
className: ""
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: lets-encrypt
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: blog.acayip.dev
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
|
||||
tls:
|
||||
- secretName: blog-tls
|
||||
hosts:
|
||||
- blog.acayip.dev
|
||||
|
||||
resources:
|
||||
{}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
|
||||
# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# Additional volumes on the output Deployment definition.
|
||||
volumes: []
|
||||
# - name: foo
|
||||
# secret:
|
||||
# secretName: mysecret
|
||||
# optional: false
|
||||
|
||||
# Additional volumeMounts on the output Deployment definition.
|
||||
volumeMounts: []
|
||||
# - name: foo
|
||||
# mountPath: "/etc/foo"
|
||||
# readOnly: true
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
20
config/deployment.yaml
Normal file
20
config/deployment.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: blog-deployment
|
||||
labels:
|
||||
app: blog
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: blog
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: blog
|
||||
spec:
|
||||
containers:
|
||||
- name: blog
|
||||
image: localhost:32000/log101-dot-dev:v3
|
||||
ports:
|
||||
- containerPort: 8080
|
|
@ -1,7 +0,0 @@
|
|||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
supportFile: false,
|
||||
},
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
describe("Home", () =>
|
||||
it("titles are correct", () => {
|
||||
const page = cy.visit("http://localhost:4321");
|
||||
|
||||
page.get("title").should("have.text", "log101");
|
||||
page.get("h1").should("have.text", "Log101");
|
||||
}));
|
|
@ -8,6 +8,7 @@ http {
|
|||
server {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
client_max_body_size 50M;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
|
6535
package-lock.json
generated
Normal file
6535
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -7,20 +7,19 @@
|
|||
"start": "astro dev",
|
||||
"build": "astro check && astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"test": "cypress run --browser chrome && cypress run --browser firefox"
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "0.9.4",
|
||||
"@astrojs/tailwind": "6.0.0",
|
||||
"astro": "5.3.0",
|
||||
"@astrojs/tailwind": "^6.0.2",
|
||||
"astro": "^5.13.7",
|
||||
"dewp": "^0.0.6",
|
||||
"htmx.org": "^1.9.12",
|
||||
"remark-toc": "^9.0.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cypress": "^13.11.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-astro": "^0.14.0"
|
||||
},
|
||||
|
|
25
public/admin/config.yml
Normal file
25
public/admin/config.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
backend:
|
||||
name: gitea
|
||||
repo: log101/log101-dot-dev # Path to your Gitea repository
|
||||
app_id: 2cb1c31c-4c74-4272-ac74-5d60a4b5c9ab # The Client ID provided by Gitea
|
||||
api_root: https://git.acayip.dev/api/v1 # API URL of your Gitea instance
|
||||
base_url: https://git.acayip.dev # Root URL of your Gitea instance
|
||||
auth_endpoint: https://git.acayip.dev/login/oauth/authorize
|
||||
branch: draft
|
||||
collections:
|
||||
- name: "blog" # Used in routes, e.g., /admin/collections/blog
|
||||
label: "Blog" # Used in the UI
|
||||
folder: "src/content/blog" # The path to the folder where the documents are stored
|
||||
create: true # Allow users to create new documents in this collection
|
||||
slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
|
||||
format: frontmatter
|
||||
fields: # The fields for each document, usually in front matter
|
||||
- { label: "Taslak", name: "draft", widget: "boolean", default: true }
|
||||
- { label: "Başlık", name: "title", widget: "string" }
|
||||
- { label: "Tarih", name: "date", widget: "datetime" }
|
||||
- { label: "Özet", name: "summary", widget: "string" }
|
||||
- { label: "Kategori", name: "category", widget: "select", options: ["fikir", "teknik", "edebiyat", "ansiklopedi"] }
|
||||
- { label: "Alt Kategori", name: "subcategory", widget: "string" }
|
||||
- { label: "Body", name: "body", widget: "markdown" }
|
||||
media_folder: "public/images"
|
||||
public_folder: "/images"
|
0
public/images/.gitkeep
Normal file
0
public/images/.gitkeep
Normal file
BIN
public/images/screenshot-from-2025-02-09-00-18-06.png
Normal file
BIN
public/images/screenshot-from-2025-02-09-00-18-06.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
|
@ -1,13 +1,19 @@
|
|||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { render, getCollection, type CollectionEntry } from "astro:content";
|
||||
|
||||
interface Props {
|
||||
post: CollectionEntry<"blog">;
|
||||
post: CollectionEntry<"posts">;
|
||||
componentType: "short" | "long" | "full";
|
||||
}
|
||||
|
||||
const { post, componentType } = Astro.props;
|
||||
|
||||
const categoryTitles = await Promise.all(
|
||||
post.data.categories.map(async (c) => await getEntry("categories", c.id))
|
||||
);
|
||||
|
||||
const parentCategory = categoryTitles.find((c) => !Boolean(c?.data.parent?.id));
|
||||
|
||||
// default options for the post component
|
||||
const deafultOptions = {
|
||||
showTags: false,
|
||||
|
@ -47,16 +53,15 @@ const postDateFormatted = post.data.date.toLocaleDateString("tr-TR", {
|
|||
});
|
||||
|
||||
// Create post link
|
||||
const postLink = `/${post.data.category}/${post.slug}`;
|
||||
const postLink = `/${parentCategory?.data.slug}/${post.data.slug}`;
|
||||
|
||||
// Create post content as an astro component
|
||||
const { Content } = await post.render();
|
||||
|
||||
const copyPost = post;
|
||||
const { Content } = await render(post);
|
||||
|
||||
import { Image } from "astro:assets";
|
||||
import questionMark from "@/images/questionMark.svg";
|
||||
import calendar from "@/images/calendar.svg";
|
||||
import { getEntry } from "astro:content";
|
||||
---
|
||||
|
||||
<style>
|
||||
|
@ -70,26 +75,13 @@ import calendar from "@/images/calendar.svg";
|
|||
}
|
||||
</style>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="tracking-wide text-slate-700">{post.data.subcategory}</p>
|
||||
<p class="tracking-wide text-slate-700">{categoryTitles[0]?.data.name}</p>
|
||||
<a class="no-underline text-inherit" href={postLink}>
|
||||
<h4 class="text-3xl font-normal">{post.data.title}</h4>
|
||||
<h4 class="text-2xl font-normal">{post.data.title.rendered}</h4>
|
||||
</a>
|
||||
<div class="flex flex-row gap-2">
|
||||
{
|
||||
options.showTags && post.data.tags?.length && (
|
||||
<div class="flex items-center gap-1">
|
||||
<Image alt="question mark" src={questionMark} />
|
||||
<ul class="list-none flex pl-0 meta-list">
|
||||
{post.data.tags.map((tag) => (
|
||||
<li class="text-sm text-gray-500">{tag}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
<Image alt="calendar" src={calendar} />
|
||||
<ul class="list-none flex pl-0 meta-list">
|
||||
|
@ -100,7 +92,7 @@ import calendar from "@/images/calendar.svg";
|
|||
</div>
|
||||
{
|
||||
(options.shortSummary || options.longSummary) && (
|
||||
<p class="post-summary">{post.data.summary}</p>
|
||||
<p class="post-summary" set:html={post.data.excerpt.rendered} />
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ Peki tüm bu saydığım servisler ne kadar kaynak tüketiyor? Özellikle RAM ka
|
|||
|
||||
### Gelecek
|
||||
|
||||
Sistemimde çalışan servisleri kısaca tanıtmış oldum. Bunlar şimdilik işimi görüyor fakat yakın gelecekte daha fazlasına ihtiyaç duyacağımı tahmin ediyorum. Özellikle güvenlik açısından sunucumun çok eksiği var. DDoS saldırılarına açık ve bildiğim bilmediğim birçok zafiyete sahip. Yine de kendi CI/CD sistemimi kullanmak ve kodum ile alakalı bütün süreçleri yönetmek projelerime esneklik katıyor.
|
||||
Sistemimde çalışan servisleri kısaca tanıttım. Bunlar şimdilik işimi görüyor fakat yakın gelecekte daha fazlasına ihtiyaç duyacağımı tahmin ediyorum. Özellikle güvenlik açısından sunucumun çok eksiği var. DDoS saldırılarına açık ve bildiğim bilmediğim birçok zafiyete sahip. Yine de kendi CI/CD sistemimi kullanmak ve kodum ile alakalı bütün süreçleri yönetmek projelerime esneklik katıyor.
|
||||
|
||||
Kendi sunucunuzu kurmanın, sizin için de keyifli ve kıymetli bir tecrübe olacağına inanıyorum.
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { z, defineCollection } from "astro:content";
|
||||
import { wpCollections } from "dewp/loaders";
|
||||
|
||||
export const CATEGORIES = ["fikir", "teknik", "edebiyat", "ansiklopedi"];
|
||||
|
||||
|
@ -35,4 +36,5 @@ const bookReviewCollection = defineCollection({
|
|||
export const collections = {
|
||||
blog: blogCollection,
|
||||
bookReview: bookReviewCollection,
|
||||
...wpCollections({ endpoint: "https://wp.log101.dev/wp-json/" }),
|
||||
};
|
||||
|
|
BIN
src/images/vlcsnap-2025-02-08-20h24m52s263.png
Normal file
BIN
src/images/vlcsnap-2025-02-08-20h24m52s263.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
import type { Page } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { CATEGORIES } from "@/content/config";
|
||||
|
||||
import Header from "@/components/Header.astro";
|
||||
import Footer from "@/components/Footer.astro";
|
||||
|
@ -9,19 +8,16 @@ import Layout from "@/layouts/Layout.astro";
|
|||
import Post from "@/components/Post.astro";
|
||||
|
||||
export async function getStaticPaths({ paginate }: { paginate: any }) {
|
||||
const blogEntries = await getCollection("blog");
|
||||
const allReviews = await getCollection("bookReview");
|
||||
const posts = await getCollection("posts");
|
||||
const categories = await getCollection("categories");
|
||||
|
||||
const allPosts = [...allReviews, ...blogEntries].filter(
|
||||
(post) => !post.data.draft
|
||||
);
|
||||
|
||||
return CATEGORIES.flatMap((category) => {
|
||||
const filteredPosts = allPosts.filter(
|
||||
(post) => post.data.category == category
|
||||
return categories.flatMap((category) => {
|
||||
const filteredPosts = posts.filter((post) =>
|
||||
post.data.categories.find((c) => c.id === category.id)
|
||||
);
|
||||
|
||||
return paginate(filteredPosts, {
|
||||
params: { category },
|
||||
params: { category: category.data.slug },
|
||||
pageSize: 3,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import { getCollection, getEntry } from "astro:content";
|
||||
|
||||
import Footer from "@/components/Footer.astro";
|
||||
import Header from "@/components/Header.astro";
|
||||
|
@ -8,7 +8,6 @@ import Post from "@/components/Post.astro";
|
|||
import EmojiReactionForm from "@/components/EmojiReactionForm.astro";
|
||||
import CommentForm from "@/components/CommentForm.astro";
|
||||
import HorizontalLine from "@/components/HorizontalLine.astro";
|
||||
import BookReview from "@/components/BookReview.astro";
|
||||
|
||||
const { entry } = Astro.props;
|
||||
|
||||
|
@ -17,33 +16,37 @@ const URL = Astro.url;
|
|||
const backendHost = import.meta.env.PUBLIC_BACKEND_HOST;
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const blogEntries = await getCollection("blog");
|
||||
const allReviews = await getCollection("bookReview");
|
||||
const posts = await getCollection("posts");
|
||||
|
||||
const allPosts = [...allReviews, ...blogEntries].filter(
|
||||
(post) => !post.data.draft
|
||||
return await Promise.all(
|
||||
posts.map(async (entry) => {
|
||||
const categoryTitles = await Promise.all(
|
||||
entry.data.categories.map(
|
||||
async (c) => await getEntry("categories", c.id)
|
||||
)
|
||||
);
|
||||
|
||||
const parentCategory = categoryTitles.find(
|
||||
(c) => !Boolean(c?.data.parent?.id)
|
||||
);
|
||||
|
||||
return {
|
||||
params: { category: parentCategory?.data.slug, slug: entry.data.slug },
|
||||
props: { entry },
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return allPosts.map((entry) => ({
|
||||
params: { category: entry.data.category, slug: entry.slug },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="log101"
|
||||
ogTitle={entry.data.title}
|
||||
ogDescription={entry.data.summary}
|
||||
ogTitle={entry.data.title.rendered}
|
||||
ogDescription={entry.data.excerpt.rendered}
|
||||
ogURL={URL.toString()}>
|
||||
<Header />
|
||||
{
|
||||
entry.collection === "blog" ? (
|
||||
<Post post={entry} componentType="full" />
|
||||
) : (
|
||||
<BookReview post={entry} componentType="full" />
|
||||
)
|
||||
}
|
||||
<Post post={entry} componentType="full" />
|
||||
|
||||
<EmojiReactionForm entryId={entry.id} />
|
||||
|
||||
<section class="comments">
|
||||
|
|
|
@ -5,30 +5,17 @@ import Layout from "@/layouts/Layout.astro";
|
|||
|
||||
import { getCollection } from "astro:content";
|
||||
import Post from "@/components/Post.astro";
|
||||
import BookReview from "@/components/BookReview.astro";
|
||||
|
||||
const allTeknikPosts = await getCollection("blog");
|
||||
const allReviews = await getCollection("bookReview");
|
||||
|
||||
const allPosts = [...allReviews, ...allTeknikPosts].filter(
|
||||
(post) => !post.data.draft
|
||||
);
|
||||
const posts = await getCollection("posts");
|
||||
---
|
||||
|
||||
<Layout title="log101">
|
||||
<Header />
|
||||
<div class="posts">
|
||||
{
|
||||
allPosts
|
||||
posts
|
||||
.sort((p1, p2) => p2.data.date.getTime() - p1.data.date.getTime())
|
||||
.map((p) => {
|
||||
if (p.collection == "blog") {
|
||||
return <Post post={p} componentType="short" />;
|
||||
} else {
|
||||
p.collection == "bookReview";
|
||||
return <BookReview post={p} componentType="short" />;
|
||||
}
|
||||
})
|
||||
.map((p) => <Post post={p} componentType="short" />)
|
||||
}
|
||||
</div>
|
||||
<a class="text-inherit" href="/posts/1">Tüm Yayınlar</a>
|
||||
|
|
|
@ -8,15 +8,10 @@ import Layout from "@/layouts/Layout.astro";
|
|||
import Post from "@/components/Post.astro";
|
||||
|
||||
export async function getStaticPaths({ paginate }: { paginate: any }) {
|
||||
const blogEntries = await getCollection("blog");
|
||||
const allReviews = await getCollection("bookReview");
|
||||
const posts = await getCollection("posts");
|
||||
|
||||
const allPosts = [...allReviews, ...blogEntries].filter(
|
||||
(post) => !post.data.draft
|
||||
);
|
||||
|
||||
return paginate(allPosts, {
|
||||
pageSize: 3,
|
||||
return paginate(posts, {
|
||||
pageSize: 10,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -43,3 +43,51 @@ video {
|
|||
font-family: "Source Code Pro", monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.shiki {
|
||||
font-size: 16px;
|
||||
line-height: 1rem;
|
||||
padding: 18px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h3,
|
||||
hr {
|
||||
margin: 0.7em 0 0.5em 0;
|
||||
}
|
||||
|
||||
#full-text p {
|
||||
margin: 0.5em 0 1.2em 0;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
color: gray;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#toc > ul {
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
li a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid slategrey;
|
||||
padding: 4px;
|
||||
background-color: #f8f9fa;
|
||||
margin: 0.5em 0 1.2em 0;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
"exclude": ["./src/components/*.astro"],
|
||||
"compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user