简介:这份微信小程序短视频源码面向小程序开发者、前端技术爱好者及希望学习短视频应用开发的人群,提供播放、上传、点赞、评论等核心功能模块的完整前后端实现,可用于技术学习、二次开发或搭建个性化短视频社交与娱乐类小程序。压缩包共45个文件,约225KB,以js逻辑脚本、json配置、wxss样式、vue组件、wxml模板为主,另含map映射、图片素材及scss、html等辅助文件,目录涵盖页面、组件、静态资源与公共配置等模块,结构清晰便于按需查阅。目前已有338人学习下载。读者可借此理解短视频小程序的整体架构与数据流程,掌握uniapp与vue.js在微信小程序中的组件化实践,并基于封装好的功能模块快速扩展出属于自己的短视频项目。
1. 从一份短视频小程序源码说起:TypeScript 全栈到底能跑多快
前阵子有个做本地生活服务的读者找到我,说他们想给商户做一套短视频展示工具,要求能发视频、能刷信息流、能点赞评论,还得能塞进微信里直接用。他手里已经有一份「微信小程序-短视频源码」,技术栈写着前端 TypeScript、后端 TypeScript,问我这套东西到底能不能落地、跑起来要多久、坑在哪。我花了一个周末把这份源码从目录结构到接口链路完整拆了一遍,结论是:这套东西的骨架是完整的,前端小程序端用 TypeScript 写页面逻辑和请求封装,后端也是 TypeScript 起服务,前后端语言统一,对中小团队来说上手成本确实低。它适合谁?适合想快速搭一个短视频 Demo 验证业务、或者需要一套可二次开发底座的开发者。但要注意,源码给的是「能跑通」的基线,不是「能上线」的成品,中间隔着配置、鉴权、存储、审核好几道坎。下面我按实际拆解顺序,把这份源码怎么用、参数怎么调、哪里容易翻车,一条条讲清楚。
2. 源码结构拆解:前端小程序与后端服务的 TypeScript 分工
2.1 目录布局与模块职责
拿到源码先别急着npm install,先看目录。这份源码典型的分法是两大块:miniprogram/放小程序端,server/放后端服务。小程序端里pages/按页面分目录,常见的有index(信息流)、publish(发布)、detail(播放详情)、profile(个人主页);utils/放请求封装和工具函数;components/放视频卡片、评论列表这类复用组件。后端server/里src/下一般分routes/、controllers/、services/、models/,TypeScript 的tsconfig.json决定编译目标。
为什么强调先看结构?因为短视频类小程序的核心链路就三条:拉流(列表接口)、推流(上传接口)、互动(点赞评论接口)。你只要在目录里定位到这三条链路的文件,剩下的都是外围。我一般会先打开utils/request.ts看请求基址和拦截器,再打开后端routes/看路由前缀,两边一对,接口地图就出来了。
# 查看源码顶层结构,先建立模块地图 ls -la # 典型输出会看到 miniprogram/ 和 server/ 两个目录 # 分别进入看 package.json,确认依赖和启动脚本 cat miniprogram/package.json cat server/package.json这段命令的作用是快速确认项目是不是「双端分离」结构。参数上没什么可调的,重点是看两个package.json里的scripts字段,前端一般有build或直接靠开发者工具编译,后端通常有dev、build、start。如果后端scripts里只有start没有dev,说明它没配热重载,改代码要手动重启,这点后面避坑章会细说。
2.2 前端 TypeScript 的编译配置
小程序端用 TypeScript,绕不开tsconfig.json和开发者工具的配合。这份源码里前端 TS 一般编译到 ES2017 或 ES5,module设成CommonJS,因为小程序运行时对模块系统的支持有限。关键参数是strict,很多源码为了省事把它设成false,这意味着类型检查形同虚设,你写错字段名它也不报错。
{ "compilerOptions": { "target": "ES2017", "module": "CommonJS", "strict": true, "noImplicitAny": true, "outDir": "./dist", "rootDir": "./src", "typeRoots": ["./typings"] }, "include": ["src/**/*.ts"], "exclude": ["node_modules"] }逻辑说明:target决定编译后的语法级别,小程序基础库版本低的话建议 ES5,高版本可以 ES2017。strict和noImplicitAny建议打开,虽然会暴露一堆历史类型错误,但这是把「玄学 bug」提前到编译期的唯一办法。typeRoots指向typings目录,小程序 API 的类型声明通常放这里,缺了它wx.request这类调用会飘红。改完配置记得在开发者工具里勾选「使用 TypeScript 编译」,否则工具还是按 JS 处理。
2.3 后端 TypeScript 服务的启动链路
后端这块,源码一般用 Express 或 Koa 起服务,TypeScript 通过ts-node或先tsc再node dist运行。启动入口通常是src/index.ts或src/app.ts,里面做三件事:加载环境变量、注册中间件、挂载路由。
// server/src/index.ts 典型启动逻辑 import express from 'express'; import dotenv from 'dotenv'; import videoRouter from './routes/video'; dotenv.config(); // 加载 .env 里的端口、数据库地址等 const app = express(); app.use(express.json()); // 解析 JSON 请求体,上传接口需要调大 limit app.use('/api/video', videoRouter); // 视频相关路由统一前缀 const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`server running on ${port}`); });逻辑说明:dotenv.config()必须在读取process.env之前调用,顺序错了端口永远是默认值。express.json()默认请求体上限是 100kb,短视频上传如果走 JSON 传 base64 会直接爆掉,常见做法是上传走独立接口用multipart/form-data,或者把 limit 调到'50mb'。路由前缀/api/video要和前端request.ts里的 baseURL 对上,对不上就是 404,这是新手最常见的翻车点。
3. 跑通第一条链路:从环境配置到视频列表接口返回
3.1 环境变量与依赖安装
先把后端跑起来,再管前端。后端依赖安装用npm install,但 TypeScript 项目要注意devDependencies里的@types/express、@types/node有没有装全,缺类型包编译会报一堆找不到声明的错。
cd server npm install # 复制环境变量模板,按实际改 cp .env.example .env # 编辑 .env,至少改这几项 # PORT=3000 # DB_HOST=127.0.0.1 # DB_NAME=shortvideo # JWT_SECRET=换成你自己的随机串 npm run dev参数说明:PORT是服务监听端口,前端请求基址要跟它一致。DB_HOST和DB_NAME指向数据库,源码如果带 SQL 脚本,先建库再导表。JWT_SECRET是签发登录令牌的密钥,源码里如果写死了一个默认值,务必换掉,否则任何人都能伪造令牌。npm run dev依赖ts-node,如果报command not found,说明devDependencies没装全,补一句npm install -D ts-node typescript。
3.2 数据库表结构与视频字段
短视频业务的核心表一般就几张:用户表、视频表、点赞表、评论表。视频表里几个字段决定后面所有逻辑:video_url(播放地址)、cover_url(封面)、duration(时长)、status(审核状态)、user_id(作者)。status这个字段特别关键,源码里如果默认是 1 表示已发布,那所有新上传的视频会直接可见,正式环境必须改成先审后发。
| 字段名 | 类型 | 说明 | 常见坑 |
|---|---|---|---|
| id | int | 主键自增 | 无 |
| user_id | int | 作者 ID | 没建索引,列表查询慢 |
| video_url | varchar | 播放地址 | 存了本地路径,换环境失效 |
| cover_url | varchar | 封面地址 | 为空时前端白屏 |
| duration | int | 时长秒 | 单位不统一,有的存毫秒 |
| status | tinyint | 0 待审 1 通过 2 拒绝 | 默认值给错导致未审先发 |
这张表不是让你照抄,是让你对照源码里的建表语句检查。我见过最典型的翻车是video_url存了http://localhost:3000/uploads/xxx.mp4,本地跑没问题,一部署到别的机器全挂。正确做法是存相对路径,前端拼基址,或者直接上对象存储返回完整 URL。
3.3 列表接口的请求与返回验证
后端起来后,先用 curl 验证列表接口,别急着开小程序。
# 请求视频列表,带分页参数 curl -X GET "http://127.0.0.1:3000/api/video/list?page=1&size=10" \ -H "Content-Type: application/json"逻辑说明:page和size是分页参数,源码里如果没做上限校验,size传 10000 会把数据库拖死,常见做法是后端强制Math.min(size, 50)。返回体一般是{ code, data: { list, total }, msg }这种结构,前端request.ts的拦截器会根据code判断成功失败。如果返回 401,说明接口要登录令牌,先走登录接口拿 token 再带上Authorization头。这一步验证通过,说明后端链路是通的,问题就缩小到前端了。
4. 前端小程序联调:请求封装、视频组件与登录态
4.1 请求基址与拦截器配置
小程序端最容易出问题的地方就是请求基址。开发者工具里可以勾「不校验合法域名」,但真机预览必须配合法域名,这是硬门槛。源码里utils/request.ts一般会导出一个baseURL,本地调试指向http://127.0.0.1:3000,上线要换成备案过的域名。
// miniprogram/utils/request.ts const baseURL = 'http://127.0.0.1:3000/api'; // 本地调试用,上线换域名 interface RequestOptions { url: string; method?: 'GET' | 'POST'; data?: Record<string, any>; } export function request<T>(options: RequestOptions): Promise<T> { const token = wx.getStorageSync('token'); // 从本地缓存取登录令牌 return new Promise((resolve, reject) => { wx.request({ url: baseURL + options.url, method: options.method || 'GET', data: options.data, header: { 'Content-Type': 'application/json', 'Authorization': token ? `Bearer ${token}` : '' // 有令牌就带上 }, success: (res) => { if (res.statusCode === 200) resolve(res.data as T); else reject(res); }, fail: reject }); }); }逻辑说明:baseURL是全局唯一入口,改一处全生效,千万别在每个页面里写死地址。Authorization头用Bearer加令牌是常见约定,后端解析时要对应。wx.getStorageSync('token')同步读取,量小没问题,但别在循环里调。如果接口返回 401,拦截器里最好统一处理跳登录,源码如果没做,自己补一个,否则用户令牌过期后每个页面都报错,体验很差。
4.2 视频组件的播放与列表复用
短视频信息流的核心是视频组件。小程序原生<video>组件在列表里大量使用时性能吃紧,常见做法是只让当前可见的那一个播放,划走就暂停。源码里如果每个卡片都自动播放,手机发烫、卡顿是必然的。
<!-- components/video-card/index.wxml --> <view class="card"> <video src="{{item.video_url}}" poster="{{item.cover_url}}" controls="{{false}}" autoplay="{{currentId === item.id}}" bindplay="onPlay" object-fit="cover" /> <view class="info"> <text>{{item.title}}</text> <text bindtap="onLike">{{item.liked ? '已赞' : '点赞'}}</text> </view> </view>逻辑说明:autoplay绑定currentId === item.id,只有当前激活的那条才自动播,这是控制性能的关键。controls="{{false}}"隐藏原生控件,用自定义交互替代。object-fit="cover"保证视频填满容器不变形。bindplay用来在播放时把currentId更新为当前项,形成互斥。这套逻辑源码里如果没写全,自己补上,否则列表滑动时多个视频同时播放,翻车是迟早的。
4.3 登录态与令牌刷新
小程序登录走wx.login拿 code,传给后端换 openid 和自定义令牌。源码里如果只做了首次登录没做令牌过期处理,用户用一段时间就会莫名退出。
// 登录并缓存令牌 export async function login() { const { code } = await wx.login(); // 拿临时登录凭证 const res = await request<{ token: string }>({ url: '/user/login', method: 'POST', data: { code } }); wx.setStorageSync('token', res.token); // 缓存令牌 return res.token; }逻辑说明:wx.login返回的 code 只能用一次,五分钟内有效,必须马上传给后端。后端拿 code 加 appid、secret 去换 openid,再签发自己的令牌。令牌有效期源码里如果设得很短又没刷新机制,建议改成七天并加静默续期。注意wx.login是异步的,用await要确认基础库版本支持 Promise 化,不支持就手动包一层。
5. 避坑与排查:这套源码最容易翻车的五个地方
5.1 现象:本地能播,真机视频黑屏
原因:video_url是http协议或者localhost地址,真机不认。小程序真机要求媒体资源走https,且域名要在后台配置。
解决:把视频传到对象存储,拿https完整地址回填数据库;本地调试阶段在开发者工具勾「不校验合法域名」,但真机预览必须配好域名,没有捷径。
5.2 现象:上传大视频接口 413 或超时
原因:express.json()默认 100kb 限制,或者上传接口没做分片,一个大文件直接怼过去。
解决:上传走multipart/form-data,用multer这类中间件接;超过几十兆的视频建议前端分片、后端合并,或者直接让前端传对象存储,后端只存地址。别硬扛,超时是必然的。
5.3 现象:列表滑动卡顿、手机发烫
原因:多个<video>同时自动播放,或者列表没做虚拟滚动,几百条数据全渲染。
解决:用currentId控制互斥播放,划走的视频调pause;列表分页加载,别一次拉全量。源码里如果用了scroll-view且没开enhanced,长列表性能也差,换成recycle-view或分页。
5.4 现象:点赞数对不上,刷新后归零
原因:点赞只改了前端状态没落库,或者后端用了缓存但没做持久化,重启就丢。
解决:点赞接口必须写库,前端乐观更新后以接口返回为准。高并发场景用 Redis 计数再定时落库,但源码级别一般直接写库就够,别过度设计。
5.5 现象:TypeScript 编译报一堆类型错误跑不起来
原因:strict打开后历史代码类型不全,或者@types包缺失。
解决:先补@types/node、@types/express等类型包;实在改不动的老代码,局部用// @ts-ignore顶一下,但别全局关strict,那是把问题埋进运行时。逐个文件修,比一次性关掉强。
6. 二次开发进阶:把 Demo 改成能用的三个具体技巧
第一个技巧是给视频表加软删除和审核状态机。源码里status往往只有 0 和 1,实际业务至少要待审 / 通过 / 拒绝 / 下架四态,配合deleted_at软删除,避免物理删除后关联数据成孤儿。改的时候在services/video.ts里把查询条件统一加上deleted_at IS NULL,别在每个接口里重复写。
第二个技巧是接口返回统一加缓存头。列表接口如果每次全查库,量一上来就慢。常见做法是对第一页结果做短缓存,比如Cache-Control: max-age=10,或者后端用内存缓存加过期时间。注意点赞、评论这类写操作要清缓存,否则用户点了赞刷新还是旧数据,体验很怪。
| 优化点 | 改前 | 改后 | 收益 |
|---|---|---|---|
| 列表查询 | 全表查 | 加索引 + 分页 | 响应从秒级到毫秒 |
| 视频地址 | 本地路径 | 对象存储 https | 真机可播 |
| 令牌 | 永不过期 | 七天 + 续期 | 安全且少掉线 |
| 上传 | JSON base64 | 分片直传 | 大文件不超时 |
第三个技巧是写一个最小化的冒烟测试脚本,每次改完跑一遍,确认登录、列表、上传、点赞四条链路没断。不用上完整测试框架,一个bash脚本加curl就够。
#!/bin/bash # smoke-test.sh 最小冒烟测试 BASE="http://127.0.0.1:3000/api" # 1. 登录拿令牌 TOKEN=$(curl -s -X POST "$BASE/user/login" -H "Content-Type: application/json" -d '{"code":"test"}' | grep -o '"token":"[^"]*"' | cut -d'"' -f4) # 2. 拉列表 curl -s "$BASE/video/list?page=1&size=5" -H "Authorization: Bearer $TOKEN" | head -c 200 # 3. 点赞第一条 curl -s -X POST "$BASE/video/like" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"videoId":1}'逻辑说明:grep -o加cut是从 JSON 里抠 token 的土办法,够用就行。三步依次验证鉴权、读、写,任何一步返回异常就说明链路断了。我一般把这个脚本放在项目根目录,改完代码先跑它,比开小程序点半天快得多。
从那以后我每次拿到这类前后端同栈的源码,都强制先跑一遍冒烟脚本再动业务代码,省得改了半天发现是环境没配对。希望帮到你。
本文还有配套的精品资源,点击获取