Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
hojas committed May 8, 2024
1 parent 09ec33e commit 80fc1ff
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .vitepress/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const nav: DefaultTheme.NavItem[] = [
{ text: 'Node.js', link: '/nodejs' },
// { text: '网络', link: '/network' },
// { text: '编程思想', link: '/thinking' },
{ text: '手搓代码', link: '/source-code' },
{ text: '博客文章', link: '/blog' },
// {
// text: '算法',
// link: '/algorithm',
Expand Down
10 changes: 4 additions & 6 deletions .vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,12 @@ export const sidebar: DefaultTheme.Sidebar = {
],
},
],
'/source-code': [
'/blog': [
{
text: '手搓代码',
text: '博客文章',
items: [
{ text: '防抖', link: '/source-code/debounce' },
{ text: '节流', link: '/source-code/throttle' },
{ text: '深拷贝', link: '/source-code/deep-copy' },
{ text: '音频可视化的实现', link: '/source-code/voice-visualization' },
{ text: '使用 Docker 一键部署带 Let\'s Encrypt SSL 证书的 Nginx', link: '/blog/1' },
{ text: '音频可视化的实现', link: '/blog/2' },
],
},
],
Expand Down
8 changes: 8 additions & 0 deletions src/docs/blog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: 博客文章
---

# 博客文章

1. [使用 Docker 一键部署带 Let's Encrypt SSL 证书的 Nginx](./blog/1.md)
2. [使用 Vue 实现音频可视化](./blog/2.md)
93 changes: 93 additions & 0 deletions src/docs/blog/1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
title: 使用 Docker 一键部署带 Let's Encrypt SSL 证书的 Nginx
---

# 使用 Docker 一键部署带 Let's Encrypt SSL 证书的 Nginx

使用镜像 [nginx-proxy](https://github.com/nginx-proxy/nginx-proxy)[acme-companion](https://github.com/nginx-proxy/acme-companion) 可以很方便地一键部署带 Let's Encrypt SSL 证书的 Nginx。

nginx-proxy 设置了一个运行 nginx 和 docker-gen 的容器。docker-gen 为 nginx 生成反向代理配置,并在容器启动和停止时重新加载 nginx。

acme-companion 是 nginx-proxy 的轻量级配套容器。它通过 ACME 协议为代理的 Docker 容器自动创建、更新和使用 SSL 证书。

编写一键部署的 `docker-compose.yaml` 文件:

```yaml
services:
nginx-proxy:
container_name: nginx-proxy
image: nginxproxy/nginx-proxy:alpine
restart: always
ports:
- 80:80
- 443:443
volumes:
- conf:/etc/nginx/conf.d
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- certs:/etc/nginx/certs:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
- nginx-proxy
acme-companion:
container_name: nginx-proxy-acme
image: nginxproxy/acme-companion
restart: always
environment:
- [email protected]
volumes_from:
- nginx-proxy
volumes:
- certs:/etc/nginx/certs:rw
- acme:/etc/acme.sh
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- nginx-proxy

networks:
nginx-proxy:
driver: bridge
name: nginx-proxy

volumes:
conf:
vhost:
html:
certs:
acme:
```
然后启动 Docker 容器:
```bash
$ docker compose up -d
```

在需要部署的应用中添加环境变量相关变量,并指定相关网络,例如:

```yaml
services:
web:
container_name: web
image: node:20-alpine
restart: always
environment:
- LETSENCRYPT_HOST=example.com
- VIRTUAL_HOST=example.com
- VIRTUAL_PORT=3000
- VIRTUAL_PATH=/
networks:
- nginx-proxy

networks:
nginx-proxy:
external: true
```
然后启动应用容器:
```bash
$ docker compose up -d
```

这样就可以在 `example.com` 上访问到部署的应用,并且自动配置了 Let's Encrypt SSL 证书。
168 changes: 168 additions & 0 deletions src/docs/blog/2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: 用 Vue 实现音频可视化
---

# 用 Vue 实现音频可视化

使用 `Web Audio API` 和 canvas 实现音频可视化。

https://developer.mozilla.org/en-US/docs/Web/API/AudioContext

## 效果

<script setup>
import VoiceVisualization from './voice-visualization/voice-visualization.vue'
</script>

<VoiceVisualization audio-source="./voice-visualization/Immortal.mp3" />

## 代码

```vue
<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'
defineProps({
audioSource: {
type: String,
required: true,
},
})
// 音频元素
const audio = ref()
// 画布元素
const canvas = ref()
// 画布上下文
const ctx = ref()
// 音频分析节点
const analyser = ref()
// 音频分析数据
const dataArray = ref()
const animationId = ref()
/**
* 初始化画布
*/
function initCanvas() {
if (ctx.value)
return
// 获取画布
canvas.value = canvas.value || canvas.value.$refs.canvas
// 获取画布上下文
ctx.value = canvas.value.getContext('2d')
ctx.value.fillRect(0, 0, canvas.value.width, canvas.value.height)
}
/**
* 音频播放事件
*/
function onAudioPlay() {
// 音频上下文
const audioCtx = new AudioContext()
// 音频源节点
const source = audioCtx.createMediaElementSource(audio.value)
// 音频分析节点
analyser.value = audioCtx.createAnalyser()
// 音频输出节点
const destination = audioCtx.destination
analyser.value.fftSize = 512
// 创建数组,用于接收分析器节点的分析数据
// analyser.frequencyBinCount = analyser.fftSize / 2
// 为什么用Uint8Array?
// 因为音频分析数据是无符号整数,范围是0~255
// Uint8Array的范围也是0~255,所以可以直接使用
// 可以用普通数组吗?
// 可以,但是需要将数据转换为无符号整数
dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)
source.connect(analyser.value)
analyser.value.connect(destination)
}
/**
* 绘制音频图
*/
function draw() {
// 递归调用
animationId.value = requestAnimationFrame(draw)
// 如果没有音频分析节点,不绘制
if (!analyser.value)
return
const width = canvas.value.width
const height = canvas.value.height
// 清空画布
ctx.value.clearRect(0, 0, width, height)
// 获取音频分析数据
analyser.value.getByteFrequencyData(dataArray.value)
// 除以2.5是为了让音频图更加平滑
const len = dataArray.value.length / 2.5
const barWidth = width / len / 2
ctx.value.fillStyle = '#99f'
for (let i = 0; i < len; i++) {
const data = dataArray.value[i]
// 除以255是为了让音频图的高度不超过画布高度
const barHeight = data / 255 * height
const x1 = barWidth * i + width / 2
const x2 = width / 2 - barWidth * (i + 1)
const y = height - barHeight
// 绘制两个对称的图形
// 宽度减2,留出间隙
// 右边的图形
ctx.value.fillRect(x1, y, barWidth - 2, barHeight)
// 左边的图形
ctx.value.fillRect(x2, y, barWidth - 2, barHeight)
}
}
onMounted(() => {
initCanvas()
draw()
audio.value.addEventListener('play', onAudioPlay)
})
onBeforeUnmount(() => {
cancelAnimationFrame(animationId.value)
audio.value.removeEventListener('play', onAudioPlay)
})
</script>
<template>
<div class="voice-visualization">
<div class="canvas-container">
<canvas ref="canvas" />
</div>
<div class="audio-container">
<audio ref="audio" controls>
<source :src="audioSource" type="audio/mpeg">
</audio>
</div>
</div>
</template>
<style scoped>
.voice-visualization {
padding: 20px 0;
}
canvas {
width: 100%;
height: 300px;
}
.canvas-container {
border: solid 1px #eee;
}
.audio-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
</style>
```
10 changes: 10 additions & 0 deletions src/docs/infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,22 @@ title: 前端基础建设

https://github.com/hojas/private-npm-registry

## 前端框架

1. Vue
2. React

## 代码构建

1. vite
2. rollup
3. webpack

## CSS 处理

1. SASS
2. PostCSS

## 项目部署

1. Github Actions
Expand Down

0 comments on commit 80fc1ff

Please sign in to comment.