Nuxt3中使用Day.js或dayjs-nuxt模块,加载中文语言配置后构建项目出现Hydration completed but contains mismatches.


具体现象:页面刷新时先是英文一闪而过然后才会正确显示中文,例如页面刷新后显示"a month ago"然后瞬间变会"1 个月前",控制台报错BGBimpvY.js:14 Hydration completed but contains mismatches.

这个问题是由于服务端渲染(SSR)和客户端水合不匹配导致的。服务端使用英文渲染,客户端加载后又立即切换成中文,造成水合错误。

假设我们直接引入Day.js或者通过dayjs-nuxt模块使用Day.js

方式一、直接引入Day.js

  1. 安装
shell 复制代码
npm install dayjs
  1. 配置
typescript 复制代码
// plugins/dayjs.ts
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/zh-cn'

export default defineNuxtPlugin(() => {
  dayjs.extend(relativeTime)
  dayjs.locale('zh-cn')
  
  return {
    provide: {
      dayjs
    }
  }
})
  1. 使用
vue 复制代码
<template>
  <span>{{ $dayjs('2025-09-04T19:00:00.000+00:00').fromNow() }}</span>
</template>

方式二、引入dayjs-nuxt模块

  1. 安装
shell 复制代码
npx nuxi@latest module add dayjs
  1. 配置
typescript 复制代码
// nuxt.config.ts
modules: ['dayjs-nuxt']
  dayjs: {
  locales: ['zh-cn'],  // 加载中文语言包
  defaultLocale: 'zh-cn' // 设置默认语言
  // 默认会引入 relativeTime 和 utc 插件
},
  1. 使用
vue 复制代码
<template>
  <span>{{ $dayjs('2025-09-04T19:00:00.000+00:00').fromNow() }}</span>
</template>

以上的配置在开发环境中似乎不会什么问题,但是通过npm run build构建打包部署到生产环境或者通过npm run preivew预览便会出现文章开头的情况。

通过查看dayjs-nuxt模块仓库issues发现有不少开发者已经提到了这个问题。似乎是由于import 'dayjs/locale/zh-cn'这样的加载方式(dayjs 加载语言包通常是通过一种“副作用导入”(side-effect import)的方式)并没有将文件内容赋值给一个变量,导致打包工具进行摇树优化(Tree-Shaking)的时候以为只是导入了这个文件,但没有从它里面导出任何变量来使用,所以这个导入是多余的,我可以把它‘摇掉’(删除掉)以减小最终打包的体积。

现在对以上两种引入方式做出调整

针对直接引入Day.js的方式,需要显式导入并赋值给变量,避免在构建时被优化掉,修改配置如下:

typescript 复制代码
// plugins/dayjs.ts
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
- import 'dayjs/locale/zh-cn'
+ // 显式导入并赋值给变量,避免在构建时被优化掉
+ import zhCn from 'dayjs/locale/zh-cn'

export default defineNuxtPlugin(() => {
  dayjs.extend(relativeTime)
-  dayjs.locale('zh-cn')
+  // 显式设置语言包
+  dayjs.locale('zh-cn', zhCn)
  
  return {
    provide: {
      dayjs
    }
  }
})

针对引入dayjs-nuxt模块的方式,需手动引入和配置中文语言,添加插件如下:

typescript 复制代码
// https://github.com/fumeapp/dayjs/issues/44#issuecomment-3052536121
// plugins/dayjs-locale.ts
export default defineNuxtPlugin(({ hook }) => {
  // 语言包配置
  const locales = {
    // 动态导入,按需加载
    'zh-cn': () => import('dayjs/locale/zh-cn'),
  }
  
  const { $dayjs } = useNuxtApp()

  // 监听 app:created 事件,在应用创建时执行(应用创建时的钩子)
  hook('app:created', async () => {
    // 设置 Day.js 的语言环境
    const currentLocale = 'zh-cn' // 或从其他地方获取当前语言
    // 异步加载语言包
    const localeModule = await locales[currentLocale]()
    $dayjs.locale(currentLocale, localeModule.default)
  })
})

参考文章:https://github.com/fumeapp/dayjs/issues/44
参考文章:Claude-4、Gemini-2.5

评论