最近在做项目调优,一个 Vue3 项目当初使用 vuex 做的状态管理,最近大家都在谈 pinia,看了一下文档,它的使用方法更贴近于 Composition API,对 TypeScript 也更友好,写法上也更简洁,emmm…,香啊!
这必须安排啊,于是我开始用 pinia 替换 vuex。
- store 文件夹下的所有文件重构
- 项目中所有基于 vuex 的状态替换为基于 pinia 的状态
= 获取状态响应式丢失
然后遇到第一个问题,如果要获取某个状态,并进行一些操作,最好不要这么写
import { useSettingStore } from "@/store/setting";
const settingStore = useSettingStore();
const isCollapse = settingStore.isCollapse;
const changeCollapse = () => {
settingStore.isCollapse = !isCollapse;
};
复制代码
这样直接 const isCollapse = settingStore.isCollapse;
通过 =
赋值拿到的状态是没有响应式的,正确的方式是通过 storeToRefs
进行解构获取,修改后代码如下:
import { storeToRefs } from "pinia";
import { useSettingStore } from "@/store/setting";
const settingStore = useSettingStore();
const { isCollapse } = storeToRefs(settingStore);
const changeCollapse = () => {
settingStore.setCollapse(!isCollapse.value);
};
复制代码
ps: 修改状态的时候最好还是通过 action
来做。
cdn 加载 Vue 线上环境 pinia 响应式丢失
这个坑真的是如果思路不对,要被坑死。
为了项目更快的加载,我配置了 external
通过 cdn 加载 Vue
和 ElementPlus
,这里也说一下配置过程,方便需要的小伙伴。
// vite.config.js
import { viteExternalsPlugin } from "vite-plugin-externals";
plugins: [
// external cdn 引入依赖包
viteExternalsPlugin(
{
vue: "Vue",
"element-plus": "ElementPlus",
}
)
]
复制代码
// index.html
<head>
<meta ...
<!-- 导入 Vue 3 -->
<script src="//unpkg.com/vue@next"></script>
<!-- 导入样式 -->
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
<!-- 导入组件库 -->
<script src="//unpkg.com/element-plus"></script>
<title>...
<head>
复制代码
这样就完成了,这里用到了 vite-plugin-externals 插件,记得要安装一下。
到了这里,一切都很美好,打包上线吧!
项目部署之后,随便点一点测试下,然后发现当我点击这个按钮控制侧边栏展开收齐的时候,
没有作用?!打开本地服务,点击,比德芙还丝滑好不好!那么问题就出在了线上环境和本地服务的差异。
因为线上环境每次都需要部署,比较麻烦(我是在个人服务器上部署了一套测试,所以不影响真实的线上环境),同时为了对比是不是线上环境的问题(Linux 服务器以及 nginx 配置),我在登录页面获取了 isCollapse
并尝试进行操作,同样,本地服务没有问题,打包,开启 Live Serve
,发现本地环境操作也不行,那么就可以确定是打包后的文件出了问题。
因为我项目配置了 cdn 加载 Vue
,所以自然想到了这个问题,把 cdn 加载干掉,再次打包,开启 Live Serve
,发现本地环境可以了。
到了这里,可以确定配置 cdn 加载后,造成了这个问题。因为实际项目依赖和模块比较多,为了排除干扰,调试更方便,我开了一个新的测试项目(我是之前就有这么一个专门用来测试问题的项目,用来复现和调试实际项目中的问题),首先把 Vue ElementPlus pinia
都搞好,不开启 cdn 加载,本地服务和打包后的本地环境都是 OK 的,然后开启 cdn 加载,本地服务 OK,打包后本地环境 pinia
响应式失效,完美复现。
接下来就是排查具体原因,有两个点:
- vite-plugin-externals
- pinia
查看 vite-plugin-externals
的 README
可以看到,它只是把依赖库的引入转为 window
下的全局变量,
// 选项
viteExternalsPlugin({
vue: 'Vue',
}),
// 源代码
import Vue from 'vue'
// 转换后
const Vue = window['Vue']
复制代码
并没有其他什么操作,所以我感觉不是它的问题,排除嫌疑。
那么就剩下 pinia
了,这个时候我打开打包后的 vendor.js 发现里面还是有 Vue 的代码。