集市前端重构总结
怎么说呢, 前段时间花了点时间把自己写的东西重构了一下. 基本是当作最后一次给集市做点贡献了. 之后的维护或者升级交给后人吧.
感觉我在这个项目还是学到挺多东西的, 从一个普普通通的小白变成了普普通通的前端程序员.
组件的封装
由于错误的封装, 在最开始我使用了BasicCard
来作为布局, 让拓展卡片来完成点赞, 评论等功能. 因为评论, 子评论, 帖子, 帖子详情基本都有用户名, 点赞信息, 删除按钮, 所以我都写在 BasicCard 里了. 但是出现了一点问题, 那就是子评论有个 xxx 回复 xxx, 当时直接传一个 prop 判断了, 其实这样不好. 如果未来还要加的话又只能继续传 prop 了.
因此我把 BasicCard 完全拆掉了, 只留下最外面的 div. 用户头像, 点赞信息等全部在拓展卡片完成. 在封装好卡片后, 有很多重复的代码, 比如头像总是那一份代码, 点赞评论观看量信息也是那几行, 于是再次封装出两个组件, UserAvatar
和BasicInfo
, 顺便统一了等级样式代码.
至于点赞, 评论等功能, 之前我使用的是自定义事件, 把进行评论的函数传给父组件来执行. 不过这样对类型提示不友好, 父组件完全不知道 detail 里有什么东西, 除非用 as xx. 我个人认为像这种难把控的东西越少越好, 因此在评论卡片中自定义事件没有传任何的 detail, 只要触发这个事件就让父组件获取一次评论列表, 并且相关操作在评论卡片完成. 如果后端有提供获取单个评论的接口的话性能上应该会更好, 不过没有呢.
组件的封装的话, 我现在更偏向于父组件处理数据, 子组件只管触发事件提醒父组件(如果用 v-for 之类的渲染了很多子组件那就考虑用自定义事件来触发事件了, 其它的 emit 就好). 好好展示数据就可以了. 也就是单向数据流. 尽量避免子组件修改数据的情况. 之前的评论卡片, 帖子卡片都是自己修改点赞数据的, 很抽象.
自定义事件
跟 emit 类似, 不过自定义事件一般需要冒泡, 父组件不是直接监听某个子组件的事件, 而是监听根节点或者子组件们的父节点的事件, 减少事件监听的注册.
自定义事件如果要使用 detail 传递数据的话对类型提示不友好. 用的时候还得去找这个事件相关的类型然后 as. 也许再封装一个组合式函数来处理自定义事件可能会更好一些.
打包产物的分析与分包
之前问 ai 问出来的一个打包产物分析工具vite-bundle-analyzer
, 安装后在vite.config.ts
配置:
import { defineConfig } from 'vite';
import { analyzer } from 'vite-bundle-analyzer';
export default defineConfig({
plugins: [
analyzer({
analyzerMode: 'server', // 默认值, 启动本地服务器
openAnalyzer: true, // 自动打开浏览器
analyzerPort: 8888, // 分析服务器端口
}),
],
});
这样 build 后就可以看打包产物了, 可以看里面的相关依赖, 然后删掉或者替换不必要的东西.
crypto-js
最新版是浏览器的和 node 环境的打包放到一起了, 因此包体积会特别大. 换成比较旧的版本就小了. 再加上按需导入
import AES from 'crypto-js/aes';
import Utf8 from 'crypto-js/enc-utf8';
import pad from 'crypto-js/pad-zeropadding';
import SHA256 from 'crypto-js/sha256';
这样打包后的 crypto-js 更小了.
Markdown 组件即使换了更小的高亮包依旧很大, 原因是 Katex 太大了, 虽然没什么人用. 最后将 Markdown 渲染相关的包都单独分包, 不放在 MarkdownContainer 里了.
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (!id.includes('node_modules')) {
return;
}
id = id.split('node_modules/')[1];
if (id.includes('vue')) {
return 'vue';
}
if (
id.includes('markdown-it') ||
id.includes('dompurify') ||
id.includes('katex')
) {
return 'markdown';
}
// 不知道以后会不会换高亮包, 单独提出来吧
if (id.includes('prismjs')) {
return 'prismjs';
}
if (id.includes('crypto-js')) {
return 'cryptoJs';
}
return 'vendor';
},
},
},
},
});
这样之后MarkdownContainer修改了, 也不会影响第三方库的缓存. 虽然总体积还是一样的, 不过再次访问要下载的东西变少了.
DNS预解析
这是一个没什么所谓的优化.
在遇到图片或者别的什么外部资源时, 会需要先进行DNS解析, 然后才能发起HTTP请求. DNS预解析就是提前进行DNS解析, 而不是等到需要这个外部资源时才进行DNS解析了.
在index.html手动插入这个DNS预解析不太可能, 最好是build后自动插入. 于是让ai写了个插件, 扫描所有文件的http和https链接, 生成DNS预解析插到index.html里.
之后的事
集市反正我是打算放下了, 除了bug不打算再改了.
要是有时间的话, 说不定我会用astro重构博客, vitepress怎么说呢, 感觉确实很好, 但是如果不是完全自定义主题的话不太好把控, 那些默认组件基本是透明的.
astro岛的概念感觉还是挺吸引我的, 大部分都由服务端先渲染完成, 只有需要客户端交互的部分才发过去, 不过现在的SSR应该都是这样吧, vitepress也是这样.