0%

公司的流水线服务器因为一些原因无法升级 nodojs,无法安装 nvm,故使用 Docker 构建前端项目。

解决

在项目文件夹下新建 Dockerfile

1
2
3
4
5
6
FROM node:latest
WORKDIR /app
COPY . .
RUN npm i --legacy-peer-deps --registry=https://registry.npm.taobao.org
RUN npm rebuild esbuild
RUN npm run build:test

解释 Dockerfile

  1. 容器使用 Node ,版本为最新版本
  2. 指定工作目录 /app
  3. 将项目文件夹拷贝到 /app
  4. 运行 npm i 安装依赖
  5. 重新构建 esbuild 模块
  6. 执行构建命令

运行下面命令

1
2
3
4
## 构建容器
docker build -t docker/web:v1.0 .
## 运行容器
docker run -v /path/to/dist:/app/dist docker/web:v1.0 npm run build:test

踩坑

报错 Could not resolve entry module (index.html).

这就是为什么要用上面 COPY . . 的原因了,字面意思,vite 找不到这个 index.html 文件,所以需要复制到 Dokcer 容器中

报错 You installed esbuild on another platform than the one you're currently using.

我使用的是 Macbook Pro M1 Pro,但是容器中使用的是 Ubuntu,所以需要运行 npm rebuild esbuild 来解决这个问题

报错 Unable to resolve dependency tree

1
2
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps

根据报错提示,可以执行 `npm i –legacy-peer-deps 来解决这个问题

Docker 其他常见命令

列出运行的容器

1
2
3
4
5
docker ps -a

返回结果
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
de8f85fbfa70 docker/web:v1.0 "docker-entrypoint.s…" 2 hours ago Exited (0) 2 hours ago infallible_clarke

复制 Docker 容器中的文件

1
docker cp cc72747c1eb9:/app/dist ./out

参考文章

特别鸣谢

感谢微信群 Go语言中文网-孙膑@混沌摆 @李李很穷十二点必睡觉 @Zero 这几位大佬的指点。

资料整理

看上去是好厉害的东西

有 Demo

录像过程中的转换 CMSampleBuffer to AVAudioPCMBuffer

文本转语音

https://azure.microsoft.com/zh-cn/services/cognitive-services/text-to-speech/#overview

问题

高德地图添加点,删除指定点

解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const marker = new AMap.Marker({
map: map,
position: position,
icon: icon_style
});

var markers = [];
markers.push(marker);

map.plugin(["AMap.MarkerClusterer"], function () {
cluster = new AMap.MarkerClusterer(map, markers);
});

// 添加一个新的
clusterer.addMarker(marker);

// 删除指定点
clusterer.removeMarker(marker)

参考文章

问题

Element 表格数据刷新后,表头和表格数据错位。

常见解决方式

一个是 Css 方法修复,但是好像没效果,可能场景不太一样

1
2
3
4
5
<el-table :data="tableData" border>
<el-table-column :key="Math.random()" prop="date" label="日期"> </el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column prop="name" label="姓名"> </el-table-column>
</el-table>
1
2
3
.el-table th.gutter {
display: table-cell !important;
}

JS 方法修复

1
2
3
this.$nextTick(() => {
this.$refs.tableRef.doLayout();
});

剑走偏锋的解决方式

控制滚动条位置,触发表格重新计算

1
2
this.$refs.tableRef.bodyWrapper.scrollLeft++
this.$refs.tableRef.bodyWrapper.scrollLeft--

参考文章

资料整理

官网资料(机器学习)

官网教程

其他教程

相关组件使用方法

Demo和教程

中间碰到一些问题解决方案

很好的资料

Gin 的上传

直接看官方示例就可以 - https://gin-gonic.com/docs/examples/upload-file/multiple-file/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["upload[]"]

for _, file := range files {
log.Println(file.Filename)

// Upload the file to specific dst.
c.SaveUploadedFile(file, dst)
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
})
router.Run(":8080")
}

Gin 的 下载

一个是静态文件服务 - https://gin-gonic.com/zh-cn/docs/examples/serving-static-files/
另一个是 Github Readme.md - https://github.com/gin-gonic/gin#serving-data-from-file

1
2
3
4
5
6
7
8
9
10
11
12
func main() {
router := gin.Default()

router.GET("/local/file", func(c *gin.Context) {
c.File("local/file.go")
})

var fs http.FileSystem = // ...
router.GET("/fs/file", func(c *gin.Context) {
c.FileFromFS("fs/file.go", fs)
})
}

Sequelize 分页并计数

1
2
3
4
5
6
7
8
Post.findAndCountAll({
where: {...},
order: [...],
limit: 5,
offset: 0,
}).then(function (result) {
res.render(...);
});

完整写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const paginate = (query, { page, pageSize }) => {
const offset = page * pageSize;
const limit = pageSize;

return {
...query,
offset,
limit,
};
};


model.findAll(
paginate(
{
where: {}, // conditions
},
{ page, pageSize },
),
);

参考文章

需要查看哪些进程占用了太多内存和 CPU

查询占用内存最多的 10 个进程

1
ps -aux | sort -k4nr | head -10

参数 a 指代 all 所有的进程,u 指代 userid 执行该进程的用户 idx 指代显示所有程序,不以终端机来区分。ps -aux 的输出格式如下:

1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

或者 top 后按下 M 直接查看(注意大小写)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
top

PID:进程的ID
USER:进程所有者
PR:进程的优先级别,越小越优先被执行
NInice:值
VIRT:进程占用的虚拟内存
RES:进程占用的物理内存
SHR:进程使用的共享内存
S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
%CPU:进程占用CPU的使用率
%MEM:进程使用的物理内存和总内存的百分比
TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
COMMAND:进程启动命令名称

查使用CPU最多的3个进程

1
ps -aux | sort -k3nr | head -3

或者 top 后按下 P 直接查看(注意大小写)

有两个表,一个是主表,一个是子表,需要进行关联查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const User = sequelize.define(
'User',
{ name: DataTypes.STRING },
{ timestamps: false }
);

const UserInfo = sequelize.define(
'UserInfo',
{ userID: DataTypes.STRING },
{ timestamps: false }
);

// 表示通过子表的 userID 关联主表 中的 id,关系为一对多
User.hasMany(UserInfo, {
foreignKey: 'userID',
sourceKey: 'id',
});

参考文章

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { defineConfig } from 'vite'

export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `
@import "./src/styles/_animations.scss";
@import "./src/styles/_variables.scss";
@import "./src/styles/_mixins.scss";
@import "./src/styles/_helpers.scss";
`
}
}
}
})

参考文章