diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6dee60e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +node_modules +dockerfile +.git +.gitignore \ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..f5a805c --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,31 @@ +name: Build app and deploy to aliyun +on: + #监听push操作 + push: + branches: + # master分支,你也可以改成其他分支 + - main +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3.5.2 + - name: Install Node.js + uses: actions/setup-node@v3.6.0 + with: + node-version: "16.13.2" + - name: Install npm dependencies + run: npm install + - name: Run build task + run: npm run build + - name: Deploy to Server + uses: easingthemes/ssh-deploy@v4.1.8 + env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }} + ARGS: "-rltgoDzvO --delete" + SOURCE: ".output/" + REMOTE_HOST: "81.68.108.130" + REMOTE_USER: root + TARGET: "/home/blog" # 打包后的 dist 文件夹将放在 + # EXCLUDE: "node_modules,.git,.github" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 9d91ea9..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Build app and deploy to aliyun -on: - #监听push操作 - push: - branches: - # master分支,你也可以改成其他分支 - - main -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3.5.2 - - name: Install Node.js - uses: actions/setup-node@v3.6.0 - with: - node-version: '16.13.2' - - name: Install npm dependencies - run: npm install - - name: Run build task - run: npm run build - - name: Deploy to Server - uses: easingthemes/ssh-deploy@v4.1.8 - env: - SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }} - ARGS: ${{secrets.ARGS}} - SOURCE: ${{secrets.SOURCE}} # 这是要复制到阿里云静态服务器的文件夹名称 - REMOTE_HOST: ${{secrets.REMOTE_HOST}} # 你的阿里云公网地址 - REMOTE_USER: ${{secrets.REMOTE_USER}} # 阿里云登录后默认为 root 用户,并且所在文件夹为 root - TARGET: ${{ secrets.TARGET}} # 打包后的 dist 文件夹将放在 /root/node-server - # EXCLUDE: "node_modules,.git,.github" \ No newline at end of file diff --git a/.output.zip b/.output.zip deleted file mode 100644 index 899df3d..0000000 Binary files a/.output.zip and /dev/null differ diff --git a/components/BlogsTree.vue b/components/BlogsTree.vue index 98d1bc4..7db9af4 100644 --- a/components/BlogsTree.vue +++ b/components/BlogsTree.vue @@ -1,47 +1,55 @@ +
  • + {{ fileNameHandler(item) }} + {{ item.name }} + +
  • + \ No newline at end of file + diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index e848b84..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: "1.0" -services: - container: - image: nginx - container_name: blog - ports: - - "3000:80" - volumes: - - "/home/blog/dist/nginx/default.conf:/etc/nginx/default.conf" - - "/home/blog/dist:/etc/nginx/html" diff --git a/docker/dev/docker-compose.yaml b/docker/dev/docker-compose.yaml new file mode 100644 index 0000000..e564af6 --- /dev/null +++ b/docker/dev/docker-compose.yaml @@ -0,0 +1,13 @@ +services: + blog: + image: duxiaohao/pm2:v1 + container_name: blog-dev + restart: always + # ports: + # - "3000:3000" + networks: + - docker + volumes: + - ../../.output:/blog + working_dir: /blog + entrypoint: pm2-runtime start ecosystem.config.js diff --git a/docker/prod/docker-compose.yaml b/docker/prod/docker-compose.yaml new file mode 100644 index 0000000..8c6a25c --- /dev/null +++ b/docker/prod/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + blog: + image: duxiaohao/pm2:v1 + container_name: blog-prod + restart: always + # ports: + # - "3000:3000" + networks: + - docker + volumes: + - .:/blog + working_dir: /blog + entrypoint: pm2-runtime start ecosystem.config.js +networks: + docker: + external: + name: docker diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..2faf8b1 --- /dev/null +++ b/dockerfile @@ -0,0 +1,5 @@ +FROM node:hydrogen-alpine + +LABEL name="duxiaohao" + +RUN npm i -g pm2 \ No newline at end of file diff --git a/nginx/default.conf b/nginx/default.conf deleted file mode 100644 index 149b8c6..0000000 --- a/nginx/default.conf +++ /dev/null @@ -1,15 +0,0 @@ -server { - listen 80; - server_name localhost; - access_log /var/log/nginx/host.access.log main; - error_log /var/log/nginx/error.log error; - location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri $uri/ /index.html; - } - #error_page 500 502 503 504 /50x.html; - #location = /50x.html { - # root /usr/share/nginx/html; - #} -} \ No newline at end of file diff --git a/package.json b/package.json index d988fd8..75b23d1 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "nuxt-app", "private": true, "scripts": { - "build": "nuxt build & copyfiles nginx/** .output & copyfiles docker-compose.yml .output", - "copy": "copyfiles nginx/** .output & copyfiles docker-compose.yml .output", + "build": "nuxt build && npm run copy", + "copy": "copyfiles ecosystem.config.js .output && copyfiles -u 2 docker/prod/docker-compose.yaml .output ", "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", diff --git a/pages/blogs/[blogPath].vue b/pages/blogs/[blogPath].vue index c03a696..a0e49fc 100644 --- a/pages/blogs/[blogPath].vue +++ b/pages/blogs/[blogPath].vue @@ -1,133 +1,137 @@ \ No newline at end of file + diff --git a/public/_blogs/monorepo.md b/public/_blogs/monorepo.md index 729bfa5..e09e9aa 100644 --- a/public/_blogs/monorepo.md +++ b/public/_blogs/monorepo.md @@ -1,2 +1,3 @@ # monorepo +测试 github action diff --git "a/public/_blogs/\346\216\230\351\207\221-\345\255\227\350\212\202go\350\257\255\350\250\200\345\255\246\344\271\240/\351\253\230\350\264\250\351\207\217\347\274\226\347\250\213\345\217\212\347\274\226\347\240\201\350\247\204\350\214\203.md" "b/public/_blogs/\346\216\230\351\207\221-\345\255\227\350\212\202go\350\257\255\350\250\200\345\255\246\344\271\240/\351\253\230\350\264\250\351\207\217\347\274\226\347\250\213\345\217\212\347\274\226\347\240\201\350\247\204\350\214\203.md" index 8be97ce..a96f81e 100644 --- "a/public/_blogs/\346\216\230\351\207\221-\345\255\227\350\212\202go\350\257\255\350\250\200\345\255\246\344\271\240/\351\253\230\350\264\250\351\207\217\347\274\226\347\250\213\345\217\212\347\274\226\347\240\201\350\247\204\350\214\203.md" +++ "b/public/_blogs/\346\216\230\351\207\221-\345\255\227\350\212\202go\350\257\255\350\250\200\345\255\246\344\271\240/\351\253\230\350\264\250\351\207\217\347\274\226\347\250\213\345\217\212\347\274\226\347\240\201\350\247\204\350\214\203.md" @@ -1,86 +1,86 @@ # 高质量编程及编码规范 -* 如何编写简洁清晰的代码 -* 常用go语言程序优化手段 -* 熟悉go程序性能分析工具 -* 工程中性能优化的原则和流程 +- 如何编写简洁清晰的代码 +- 常用 go 语言程序优化手段 +- 熟悉 go 程序性能分析工具 +- 工程中性能优化的原则和流程 1. 高质量编程(高质量编程简介|编码规范|性能优化建议) 1. 什么是高质量 - * 高质量就是,编写的代码能够达到正确可靠、简介清晰的目标 - * 各种边界条件是否考虑完备 - * 异常情况处理,稳定性保证 - * 易读易维护 + - 高质量就是,编写的代码能够达到正确可靠、简介清晰的目标 + - 各种边界条件是否考虑完备 + - 异常情况处理,稳定性保证 + - 易读易维护 2. 编程原则 - * 简单性 - * 可读性 - * 生产力 + - 简单性 + - 可读性 + - 生产力 3. 编码规范 - * 代码格式——推荐使用gofmt自动格式化代码 / goimports - * 注释——公共符号始终要注释,解释代码作用,解释代码如何做的,解释代码实现的原因(提供额外上下文,外部因素),解释代码什么情况会出错(代码的限制条件),代码是最好的注释,注释应该提供代码未表达出的上下文信息 - * 命名规范 - * 简洁 - * 变量命名 - * 缩略词全大写,位于变量开头且不需要导出时,使用全小写 - * 例如使用ServeHTTP而不是ServeHttp - * 使用XMLHTTPRequest或者xmlHTTPRequest - * 变量距离其被使用的地方越远,则需要携带越多的上下文信息 - * 全局变量在其名字中需要更多上下文信息 - * 例子:i和index的作用域仅限于for循环内部时index的额外冗余没有意义 - * 函数命名 - * 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现 - * 函数名尽量简短 - * 当名为foo的包某个函数返回类型为Foo时,可以省略类型信息而不导致歧义 - * 当名为foo的包某个函数返回类型为T时,可以在函数名中加入类型信息 - * package命名 - * 只由小写字母组成。不包括大写字母和下划线等字符 - * 简短并包含一定的上下文信息。例如schema、task等 - * 不要与标准库同名 - * 不适用常用变量名作为包名 - * 使用单数而不是复数 - * 谨慎使用缩写 - * 核心目标是降低阅读理解代码的成本 - * 重点考虑上下文信息,设计简洁清晰名称 - * 控制流程 - * 避免嵌套,保持正常流程 - * 尽量保持正常代码路径为最小缩进(有限处理错误/特殊情况,尽早返回或继续循环来减少嵌套) - * 线性原理,避免复杂嵌套 - * 错误和异常处理 - * 简单错误 - * 仅出现一次,其他地方无需捕获 - * 优先使用errors.New来创建匿名变量来直接表示简单错误 - * 如果有格式化的需求,使用fmt.Errorf - * 错误的Wrap和Unwrap - * 错误的Wrap实际上是提供了一个error嵌套另一个error的能力,从而生成一个error的跟踪链 - * 在fmt.Errorf中使用:%w关键字来将一个错误关联至错误链中 - * 错误判定 - * 判定一个错误是否为特定错误,使用errors.Is - * 不同于使用==,使用该方法可以判定错误链上的所有错误是否含有特定的错误 - * 在错误链上获取特定种类的错误,使用errors.As - * panic - * 不建议在业务代码中使用panic - * 调用函数不包含recover会造成程序崩溃 - * 若问题可以被屏蔽或解决,建议使用error代替panic - * 当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用panic - * recover - * recover只能在被defer的函数中使用 - * 嵌套无法生效 - * 只在当前goroutine生效 - * defer的语句总是先进后出 - * 如果需要更多上下文信息,可以在recover后在log中记录当前的调用栈 - * 总结: - * error尽可能提供简明的上下文信息链,方便定位问题 - * panic用于真正异常的情况 - * recover生效范围,在当前goroutine的被defer的函数中生效 + - 代码格式——推荐使用 gofmt 自动格式化代码 / goimports + - 注释——公共符号始终要注释,解释代码作用,解释代码如何做的,解释代码实现的原因(提供额外上下文,外部因素),解释代码什么情况会出错(代码的限制条件),代码是最好的注释,注释应该提供代码未表达出的上下文信息 + - 命名规范 + - 简洁 + - 变量命名 + - 缩略词全大写,位于变量开头且不需要导出时,使用全小写 + - 例如使用 ServeHTTP 而不是 ServeHttp + - 使用 XMLHTTPRequest 或者 xmlHTTPRequest + - 变量距离其被使用的地方越远,则需要携带越多的上下文信息 + - 全局变量在其名字中需要更多上下文信息 + - 例子:i 和 index 的作用域仅限于 for 循环内部时 index 的额外冗余没有意义 + - 函数命名 + - 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现 + - 函数名尽量简短 + - 当名为 foo 的包某个函数返回类型为 Foo 时,可以省略类型信息而不导致歧义 + - 当名为 foo 的包某个函数返回类型为 T 时,可以在函数名中加入类型信息 + - package 命名 + - 只由小写字母组成。不包括大写字母和下划线等字符 + - 简短并包含一定的上下文信息。例如 schema、task 等 + - 不要与标准库同名 + - 不适用常用变量名作为包名 + - 使用单数而不是复数 + - 谨慎使用缩写 + - 核心目标是降低阅读理解代码的成本 + - 重点考虑上下文信息,设计简洁清晰名称 + - 控制流程 + - 避免嵌套,保持正常流程 + - 尽量保持正常代码路径为最小缩进(有限处理错误/特殊情况,尽早返回或继续循环来减少嵌套) + - 线性原理,避免复杂嵌套 + - 错误和异常处理 + - 简单错误 + - 仅出现一次,其他地方无需捕获 + - 优先使用 errors.New 来创建匿名变量来直接表示简单错误 + - 如果有格式化的需求,使用 fmt.Errorf + - 错误的 Wrap 和 Unwrap + - 错误的 Wrap 实际上是提供了一个 error 嵌套另一个 error 的能力,从而生成一个 error 的跟踪链 + - 在 fmt.Errorf 中使用:%w 关键字来将一个错误关联至错误链中 + - 错误判定 + - 判定一个错误是否为特定错误,使用 errors.Is + - 不同于使用==,使用该方法可以判定错误链上的所有错误是否含有特定的错误 + - 在错误链上获取特定种类的错误,使用 errors.As + - panic + - 不建议在业务代码中使用 panic + - 调用函数不包含 recover 会造成程序崩溃 + - 若问题可以被屏蔽或解决,建议使用 error 代替 panic + - 当程序启动阶段发生不可逆转的错误时,可以在 init 或 main 函数中使用 panic + - recover + - recover 只能在被 defer 的函数中使用 + - 嵌套无法生效 + - 只在当前 goroutine 生效 + - defer 的语句总是先进后出 + - 如果需要更多上下文信息,可以在 recover 后在 log 中记录当前的调用栈 + - 总结: + - error 尽可能提供简明的上下文信息链,方便定位问题 + - panic 用于真正异常的情况 + - recover 生效范围,在当前 goroutine 的被 defer 的函数中生效 -2. 性能调优实战(性能调优简介|性能分析工具pprof实战|性能调优案例) +2. 性能调优实战(性能调优简介|性能分析工具 pprof 实战|性能调优案例) - * 性能优化前提是满足正确可靠、简介清晰等质量因素 - * 性能优化是综合评估 + - 性能优化前提是满足正确可靠、简介清晰等质量因素 + - 性能优化是综合评估 1. 如何使用 - * 性能表现需要实际数据衡量 - * Go语言提供了基准性能测试的benchmark工具 - 2. slice预分配内存 - * 尽可能在使用make()初始化切片时提供容量信息 \ No newline at end of file + - 性能表现需要实际数据衡量 + - Go 语言提供了基准性能测试的 benchmark 工具 + 2. slice 预分配内存 + - 尽可能在使用 make()初始化切片时提供容量信息 diff --git a/server/api/blogsTree.js b/server/api/blogsTree.js index fab45a1..0133c54 100644 --- a/server/api/blogsTree.js +++ b/server/api/blogsTree.js @@ -1,13 +1,13 @@ import { getAllfiles, blogsTreeHandler } from "../handler/blogsTree"; -export default defineEventHandler(even => { - return new Promise((resolve, reject) => { - const blogsTree = []; - try { - getAllfiles('public/_blogs', blogsTree); - blogsTreeHandler(blogsTree); - resolve(blogsTree); - } catch (error) { - reject(error); - } - }); -}); \ No newline at end of file +export default defineEventHandler((even) => { + return new Promise((resolve, reject) => { + const blogsTree = []; + try { + getAllfiles("public/_blogs", blogsTree); + blogsTreeHandler(blogsTree); + resolve(blogsTree); + } catch (error) { + reject(error); + } + }); +}); diff --git a/server/api/readblog.js b/server/api/readblog.js index c2d76ef..32660af 100644 --- a/server/api/readblog.js +++ b/server/api/readblog.js @@ -1,13 +1,13 @@ -import fs from 'fs'; -export default defineEventHandler(event => { - return new Promise((resolve, reject) => { - const query = getQuery(event); - const path = query.path; - fs.readFile(`${path}`, 'utf-8', (err, data) => { - if (err) { - reject(err); - } - resolve(data); - }); +import fs from "fs"; +export default defineEventHandler((event) => { + return new Promise((resolve, reject) => { + const query = getQuery(event); + const path = query.path; + fs.readFile(`${path}`, "utf-8", (err, data) => { + if (err) { + reject(err); + } + resolve(data); }); -}); \ No newline at end of file + }); +}); diff --git a/server/handler/blogsTree.js b/server/handler/blogsTree.js index d314cc9..06b65e0 100644 --- a/server/handler/blogsTree.js +++ b/server/handler/blogsTree.js @@ -1,36 +1,43 @@ -import fs from 'fs'; +import fs from "fs"; /** * @description 读取目录下所有目录文件 返回数组 * @param path 文件目录 - * @returns + * @returns */ -function getfiles(path) { //读取目录下所有目录文件 返回数组 - const dirfiles = fs.readdirSync(path, { encoding: 'utf8', withFileTypes: true }); - return dirfiles; +function getfiles(path) { + //读取目录下所有目录文件 返回数组 + const dirfiles = fs.readdirSync(path, { + encoding: "utf-8", + withFileTypes: true, + }); + console.log(dirfiles); + return dirfiles; } // const files = getfiles('../blogs/'); // console.log(files); /** * @description 判断是否是文件 Boolean - * @param filepath - * @returns + * @param filepath + * @returns */ -function isFile(filepath) { //判断是否是文件 Boolean - let stat = fs.statSync(filepath); - return stat.isFile(); +function isFile(filepath) { + //判断是否是文件 Boolean + let stat = fs.statSync(filepath); + return stat.isFile(); } // const type = isFile('../blogs/blo.md'); // console.log(type); /** * @description 判断是否是文件夹 Boolean - * @param filepath - * @returns + * @param filepath + * @returns */ -function isDir(filepath) { //判断是否是文件夹 Boolean - let stat = fs.statSync(filepath); - return stat.isDirectory(); +function isDir(filepath) { + //判断是否是文件夹 Boolean + let stat = fs.statSync(filepath); + return stat.isDirectory(); } //递归遍历所有文件夹和文件 @@ -40,39 +47,45 @@ function isDir(filepath) { //判断是否是文件夹 Boolean * @param path 路径 * @param arr 将结果存储到该数组中 */ -function getAllfiles(path, arr) { // 结果将存储到arr数组中 - const filesArr = getfiles(path); // 获取目录下所有文件 - if (path.slice(-1) == '/') { - path = path.slice(0, -1); +function getAllfiles(path, arr) { + // 结果将存储到arr数组中 + const filesArr = getfiles(path); // 获取目录下所有文件 + if (path.slice(-1) == "/") { + path = path.slice(0, -1); + } + filesArr.forEach((item) => { + const fileName = item.name; + const filePath = `${path}/${fileName}`; + if (isDir(filePath)) { + //如果是文件夹 + const itemFileArr = []; + getAllfiles(filePath, itemFileArr); + const dir = { + name: fileName, + type: "dir", + dirPath: `${filePath}/`, + children: itemFileArr, + }; + arr.push(dir); + } else if (isFile(filePath)) { + // 如果是文件 + arr.push({ name: fileName, type: "file", path: filePath }); } - filesArr.forEach(item => { - const fileName = item.name; - const filePath = `${path}/${fileName}`; - if (isDir(filePath)) { //如果是文件夹 - const itemFileArr = []; - getAllfiles(filePath, itemFileArr); - const dir = { name: fileName, type: 'dir', dirPath: `${filePath}/`, children: itemFileArr }; - arr.push(dir); - } else if (isFile(filePath)) { // 如果是文件 - arr.push({ name: fileName, type: 'file', path: filePath }); - } - }); + }); } // const arr = []; // getAllfiles('../blogs', arr); // console.log(arr); const blogsTreeHandler = (blogsTree) => { - let obj; - for (const key in blogsTree) { - if (blogsTree[key].name == 'README.md') { - obj = { ...blogsTree[key] }; - blogsTree.splice(key, 1); - blogsTree.unshift(obj); - return; - } + let obj; + for (const key in blogsTree) { + if (blogsTree[key].name == "README.md") { + obj = { ...blogsTree[key] }; + blogsTree.splice(key, 1); + blogsTree.unshift(obj); + return; } + } }; -export { - getAllfiles, blogsTreeHandler -}; +export { getAllfiles, blogsTreeHandler };