mirror of https://github.com/YunYouJun/valaxy
refactor: use dayjs instead of date-fns & optimize test, close #486
This commit is contained in:
parent
5da91b0b82
commit
072290535a
|
@ -185,3 +185,11 @@ export function getRollupOptions(options: ResolvedValaxyOptions) {
|
|||
return rollupOptions
|
||||
}
|
||||
```
|
||||
|
||||
## date-fns vs dayjs?
|
||||
|
||||
尽管 [date-fns](https://date-fns.org/) 支持 ESM,而 [dayjs](https://github.com/iamkun/dayjs/) 不支持 ESM。
|
||||
|
||||
但 Valaxy 所使用到的函数,打包分析后,date-fns 的 chunk 约为 `30KB`,而 dayjs 的 chunk 约为 `21KB`。
|
||||
|
||||
因此 dayjs 占用体积仍小于 date-fns,且 dayjs 全局的特性使得 API 更加简洁。
|
||||
|
|
|
@ -1,18 +1,60 @@
|
|||
<script setup lang="ts">
|
||||
import type { FormatOptionsWithTZ } from 'date-fns-tz'
|
||||
import { formatDate } from 'valaxy'
|
||||
import { computed } from 'vue'
|
||||
|
||||
defineProps<{ date?: string | number | Date, format?: string, timezone?: string, options?: FormatOptionsWithTZ }>()
|
||||
const props = defineProps<{
|
||||
date?: string | number | Date
|
||||
format?: string
|
||||
timezone?: string
|
||||
keepLocalTime?: boolean
|
||||
}>()
|
||||
|
||||
const formattedDate = computed(() => {
|
||||
return formatDate(props.date, {
|
||||
formatStr: props.format,
|
||||
timezone: props.timezone,
|
||||
keepLocalTime: props.keepLocalTime,
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div flex="~">
|
||||
<time mr-4>
|
||||
{{ formatDate(date ?? new Date(), format, timezone, options) }}
|
||||
</time>
|
||||
<div flex="~ gap-2 justify-between" p-2 my-2 border>
|
||||
<slot />
|
||||
|
||||
<code>
|
||||
{{ format }}
|
||||
</code>
|
||||
<div flex="~ col gap-1" class="text-sm w-xs">
|
||||
<span class="flex justify-between gap-2">
|
||||
<span op="55" font-bold>DATE:</span>
|
||||
<span flex="~ gap-1 items-center">
|
||||
<span text-xs op-80>{{ timezone }}</span>
|
||||
<span>{{ date }}</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="flex justify-between gap-2">
|
||||
<span op="55" font-bold>
|
||||
FORMAT:
|
||||
</span>
|
||||
<span>
|
||||
{{ format }}
|
||||
</span>
|
||||
</span>
|
||||
<span class="flex justify-between gap-2">
|
||||
<span op="55" font-bold>
|
||||
KeepLocalTime:
|
||||
</span>
|
||||
<span>
|
||||
{{ keepLocalTime }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span op="55" font="bold">
|
||||
Formatted:
|
||||
</span>
|
||||
<time>
|
||||
{{ formattedDate }}
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs'
|
||||
import { onBeforeMount } from 'vue'
|
||||
import { dateExamples } from '../../../../e2e/utils/date-examples'
|
||||
|
||||
onBeforeMount(() => {})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Guess TimeZone: {{ dayjs.tz.guess() }}
|
||||
</div>
|
||||
<TestFormatDate
|
||||
v-for="(example, i) in dateExamples"
|
||||
:key="i"
|
||||
class="test-format-date"
|
||||
:class="`item-${i}`"
|
||||
v-bind="example"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center p-2">
|
||||
{{ i + 1 }}
|
||||
</div>
|
||||
</TestFormatDate>
|
||||
</template>
|
|
@ -11,13 +11,13 @@ toc: false
|
|||
|
||||
<TestFormatDate date="2023-07-19T00:00:00+08:00" format="d MMM yyyy" />
|
||||
|
||||
<TestFormatDate date="1847-05-16T00:01:15.000Z" format="yyyy-MM-dd HH:mm:ss" />
|
||||
<TestFormatDate date="1847-05-16T00:01:15.000Z" format="YYYY-MM-DD HH:mm:ss" />
|
||||
|
||||
<TestFormatDate format="EEEE, MMMM d, yyyy" />
|
||||
|
||||
<TestFormatDate format="EEEE, d MMMM yyyy" />
|
||||
|
||||
<TestFormatDate format="yyyyMMdd" />
|
||||
<TestFormatDate format="YYYYMMDD" />
|
||||
|
||||
<TestFormatDate format="yy/MM/dd" />
|
||||
|
||||
|
@ -29,27 +29,21 @@ toc: false
|
|||
|
||||
<TestFormatDate format="K:mm a, z" />
|
||||
|
||||
<TestFormatDate date="2023-07-19T00:00:00+08:00" format="EEEE, d MMMM yyyy" />
|
||||
<TestFormatDate date="2023-07-19T00:00:00+08:00" format="EEEE, d MMMM YYYY" />
|
||||
|
||||
<TestFormatDate id="text-time-format-1" date="2023-07-19T00:00:00+08:00" format="yyyyMMdd" :options="{ timeZone: 'Asia/Shanghai' }" />
|
||||
|
||||
<TestFormatDate :date="1722589089" format="yyyyMMdd" />
|
||||
|
||||
<TestFormatDate id="text-time-format-2" date="2021.3.1 12:00" format="yyyyMMddHHmmss" :options="{ timeZone: 'Asia/Shanghai' }" />
|
||||
<TestFormatDate :date="1722589089" format="YYYYMMDD" />
|
||||
|
||||
<TestFormatDate format="yyMMdd" />
|
||||
|
||||
<TestFormatDate date="2021/3/1 12:00" format="yyyy/MM/dd" />
|
||||
|
||||
<TestFormatDate id="text-time-format-3" date="2021-12-03 1:07:23" format="yyyy/MM/dd HH:mm" :options="{ timeZone: 'Asia/Shanghai' }" />
|
||||
<TestFormatDate date="2021/3/1 12:00" format="YYYY/MM/DD" />
|
||||
|
||||
<TestFormatDate format="X" />
|
||||
|
||||
<TestFormatDate format="x" />
|
||||
|
||||
<TestFormatDate date="2023-07-19 10:55:53Z" format="yyyy-MM-dd'T'HH:mm:ssXXX" />
|
||||
<TestFormatDate date="2023-07-19 10:55:53Z" format="YYYY-MM-DD'T'HH:mm:ssXXX" />
|
||||
|
||||
<TestFormatDate format="yyyy-MM-dd'T'HH:mm:ss.SSSXXX" />
|
||||
<TestFormatDate format="YYYY-MM-DD'T'HH:mm:ss.SSSXXX" />
|
||||
|
||||
<TestFormatDate :date="1722589089" format="T" />
|
||||
|
||||
|
@ -57,18 +51,6 @@ toc: false
|
|||
|
||||
<TestFormatDate format="do" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-1" date="2004-06-16T00:00:00+08:00" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Europe/Berlin" :options="{ timeZone: 'Europe/Berlin' }" />
|
||||
---
|
||||
|
||||
<TestFormatDate id="text-time-zone-2" date="2004-06-16 00:00:00" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Asia/Shanghai" :options="{ timeZone: 'Europe/Berlin' }" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-3" date="2004-06-16 00:00:00" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Asia/Shanghai" :options="{ timeZone: 'Asia/Shanghai' }" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-4" date="2004-06-16T00:00:00Z" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Asia/Shanghai" :options="{ timeZone: 'Europe/Berlin' }" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-5" date="2004-06-16 00:00:00" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Asia/Shanghai" :options="{ timeZone: 'Asia/Bangkok' }" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-6" date="2004-06-16 00:00:00" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Europe/Berlin" :options="{ timeZone: 'Asia/Shanghai' }" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-7" date="2004-06-16 00:00:00" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Europe/Berlin" :options="{ timeZone: 'Europe/Berlin' }" />
|
||||
|
||||
<TestFormatDate id="text-time-zone-8" date="2004-06-16T00:00:00Z" format="yyyy-MM-dd HH:mm:ssxxx zzz" timezone="Europe/Berlin" :options="{ timeZone: 'Asia/Shanghai' }" />
|
||||
<TestFormatDateExamples />
|
||||
|
|
|
@ -606,7 +606,8 @@ Valaxy 决定通过插件中心化地提供各类封装好的评论组件和辅
|
|||
为了提高后续页面的加载性能,Vite 将那些具有许多内部模块的 ESM 依赖项转换为单个模块。
|
||||
如果你的主题依赖了一些大型的 ESM 包,你可以通过添加 `optimizeDeps` 选项来预构建这些依赖项。
|
||||
|
||||
> `date-fns` 已被默认预构建,您无需再次添加。
|
||||
> `dayjs` 已被默认预构建,您无需再次添加。
|
||||
> [为什么用 dayjs 而不是 date-fns?](/notes/app-bundle-size.html#date-fns-vs-dayjs?)
|
||||
|
||||
:::
|
||||
|
||||
|
@ -617,7 +618,7 @@ Valaxy 决定通过插件中心化地提供各类封装好的评论组件和辅
|
|||
To improve the loading performance of subsequent pages, Vite bundles ESM dependencies with many internal modules into a single module.
|
||||
If your theme depends on some large ESM packages, you can pre-build these dependencies by adding the `optimizeDeps` option.
|
||||
|
||||
> `date-fns` has been pre-built by default, you don't need to add it again.
|
||||
> `dayjs` has been pre-built by default, you don't need to add it again.
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ test.beforeEach(async ({ page }) => {
|
|||
|
||||
test.describe('Theme Yun', () => {
|
||||
test('banner', async ({ page }) => {
|
||||
// refresh to trigger animation
|
||||
await page.reload()
|
||||
await page.waitForSelector('#yun-banner')
|
||||
await expect(page.locator('.char-box')).toHaveCount(6)
|
||||
await expect(page.locator('.char-box').nth(0)).toHaveText('云')
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
import { env } from '../env'
|
||||
import { dateExamples } from '../utils/date-examples'
|
||||
|
||||
test.use({
|
||||
baseURL: env['theme-yun'],
|
||||
|
@ -10,21 +11,10 @@ test.beforeEach(async ({ page }) => {
|
|||
})
|
||||
|
||||
test.describe('Frontmatter', () => {
|
||||
test('time format validation', async ({ page }) => {
|
||||
await expect(page.locator('#text-time-format-1 time')).toHaveText('20230719')
|
||||
await expect(page.locator('#text-time-format-2 time')).toHaveText('20210301120000')
|
||||
await expect(page.locator('#text-time-format-3 time')).toHaveText('2021/12/03 01:07')
|
||||
})
|
||||
|
||||
test('timezone format validation', async ({ page }) => {
|
||||
await expect(page.locator('#text-time-zone-1 time')).toHaveText('2004-06-15 18:00:00+02:00 GMT+2')
|
||||
await expect(page.locator('#text-time-zone-2 time')).toHaveText('2004-06-15 18:00:00+02:00 GMT+2')
|
||||
await expect(page.locator('#text-time-zone-3 time')).toHaveText('2004-06-16 00:00:00+08:00 GMT+8')
|
||||
await expect(page.locator('#text-time-zone-4 time')).toHaveText('2004-06-16 02:00:00+02:00 GMT+2')
|
||||
await expect(page.locator('#text-time-zone-5 time')).toHaveText('2004-06-15 23:00:00+07:00 GMT+7')
|
||||
await expect(page.locator('#text-time-zone-6 time')).toHaveText('2004-06-16 06:00:00+08:00 GMT+8')
|
||||
await expect(page.locator('#text-time-zone-6 time')).toHaveText('2004-06-16 06:00:00+08:00 GMT+8')
|
||||
await expect(page.locator('#text-time-zone-7 time')).toHaveText('2004-06-16 00:00:00+02:00 GMT+2')
|
||||
await expect(page.locator('#text-time-zone-8 time')).toHaveText('2004-06-16 08:00:00+08:00 GMT+8')
|
||||
for (let i = 0; i < dateExamples.length; i++) {
|
||||
const example = dateExamples[i]
|
||||
await expect(page.locator(`.test-format-date.item-${i} time`)).toHaveText(example.expected)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
export const dateExamples: {
|
||||
date: string
|
||||
format: string
|
||||
timezone: string
|
||||
keepLocalTime?: boolean
|
||||
expected: string
|
||||
}[] = [
|
||||
// simple
|
||||
{
|
||||
date: '2023-07-19',
|
||||
format: 'YYYYMMDD',
|
||||
timezone: 'Asia/Shanghai',
|
||||
expected: '20230719',
|
||||
},
|
||||
{
|
||||
date: '2021-03-01T12:00:00',
|
||||
format: 'YYYYMMDDHHmmss',
|
||||
timezone: 'Asia/Shanghai',
|
||||
expected: '20210301120000',
|
||||
},
|
||||
{
|
||||
date: '2021-12-03T01:07:00',
|
||||
format: 'YYYY/MM/DD HH:mm',
|
||||
timezone: 'Asia/Shanghai',
|
||||
expected: '2021/12/03 01:07',
|
||||
},
|
||||
|
||||
// timezone
|
||||
{
|
||||
date: '2004-06-16 00:00:00',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Asia/Shanghai',
|
||||
expected: '2004-06-16 00:00:00+08:00',
|
||||
},
|
||||
{
|
||||
date: '2004-06-16 00:00:00',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Asia/Shanghai',
|
||||
keepLocalTime: true,
|
||||
expected: '2004-06-16 00:00:00+08:00',
|
||||
},
|
||||
|
||||
{
|
||||
date: '2004-06-16T00:00:00Z',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Asia/Shanghai',
|
||||
expected: '2004-06-16 08:00:00+08:00',
|
||||
},
|
||||
{
|
||||
date: '2004-06-16T00:00:00Z',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Asia/Shanghai',
|
||||
keepLocalTime: true,
|
||||
expected: '2004-06-16 08:00:00+08:00',
|
||||
},
|
||||
|
||||
{
|
||||
date: '2004-06-16 00:00:00',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Europe/Berlin',
|
||||
expected: '2004-06-15 18:00:00+02:00',
|
||||
},
|
||||
{
|
||||
date: '2004-06-16 00:00:00',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Europe/Berlin',
|
||||
keepLocalTime: true,
|
||||
expected: '2004-06-16 00:00:00+02:00',
|
||||
},
|
||||
|
||||
{
|
||||
date: '2004-06-16T00:00:00',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Europe/Berlin',
|
||||
expected: '2004-06-15 18:00:00+02:00',
|
||||
},
|
||||
{
|
||||
date: '2004-06-16T00:00:00',
|
||||
format: 'YYYY-MM-DD HH:mm:ssZ',
|
||||
timezone: 'Europe/Berlin',
|
||||
keepLocalTime: true,
|
||||
expected: '2004-06-16 00:00:00+02:00',
|
||||
},
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import { differenceInSeconds } from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
|
@ -18,9 +18,9 @@ const passSecond = ref(0)
|
|||
* get live time
|
||||
*/
|
||||
function siteLiveTime() {
|
||||
const start = (props.startTime)
|
||||
const now = new Date()
|
||||
const timeDiff = differenceInSeconds(now, start)
|
||||
const start = dayjs(props.startTime)
|
||||
const now = dayjs()
|
||||
const timeDiff = now.diff(start) / 1000
|
||||
passDay.value = Math.floor(timeDiff / 60 / 60 / 24)
|
||||
passHour.value = Math.floor(timeDiff / 60 / 60 % 24)
|
||||
passMinute.value = Math.floor(timeDiff / 60 % 60)
|
||||
|
|
|
@ -1,27 +1,35 @@
|
|||
<script lang="ts" setup>
|
||||
import { differenceInMilliseconds, formatDistanceToNow } from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { useFrontmatter } from 'valaxy'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
const fm = useFrontmatter()
|
||||
const { t, locale } = useI18n()
|
||||
const { t } = useI18n()
|
||||
|
||||
const updated = computed(() => fm.value.updated || fm.value.date || new Date())
|
||||
const ago = ref('')
|
||||
const updated = computed(() => {
|
||||
return dayjs(fm.value.updated || fm.value.date)
|
||||
})
|
||||
|
||||
watch(locale, () => {
|
||||
const fromNow = formatDistanceToNow(updated.value, { addSuffix: true })
|
||||
ago.value = /^\d/.test(fromNow) ? ` ${fromNow}` : fromNow
|
||||
}, { immediate: true })
|
||||
const ago = computed(() => {
|
||||
const fromNow = updated.value.fromNow()
|
||||
if (/^\d/.test(fromNow))
|
||||
return ` ${fromNow}`
|
||||
else
|
||||
return fromNow
|
||||
})
|
||||
|
||||
/**
|
||||
* when the post is updated more than 180 days ago, show a warning
|
||||
* default 180 days, you can set `time_warning` in frontmatter to change it
|
||||
*/
|
||||
const time_warning = computed(() => {
|
||||
const diff = differenceInMilliseconds(new Date(), updated.value)
|
||||
const diff = dayjs().valueOf() - updated.value.valueOf()
|
||||
/**
|
||||
* if `time_warning` is a number, compare the time difference
|
||||
* if `time_warning` is a boolean, show warning by flag
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import type { Article } from '@unhead/schema-org'
|
||||
import { defineArticle, useSchemaOrg } from '@unhead/schema-org'
|
||||
|
||||
import { toDate } from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
import { useFrontmatter, useFullUrl, useSiteConfig } from 'valaxy'
|
||||
import { computed } from 'vue'
|
||||
|
||||
|
@ -27,8 +27,8 @@ const article: Article = {
|
|||
url: siteConfig.value.author.link,
|
||||
},
|
||||
],
|
||||
'datePublished': toDate(frontmatter.value.date || ''),
|
||||
'dateModified': toDate(frontmatter.value.updated || ''),
|
||||
'datePublished': dayjs(frontmatter.value.date || '').toDate(),
|
||||
'dateModified': dayjs(frontmatter.value.updated || '').toDate(),
|
||||
}
|
||||
|
||||
const image = frontmatter.value.image || frontmatter.value.cover
|
||||
|
|
|
@ -14,9 +14,9 @@ export function onImgError(e: Event, defaultImg = noneImg) {
|
|||
}
|
||||
|
||||
/**
|
||||
* date-fns format date with 'yyyy-MM-dd HH:mm:ss'
|
||||
* date-fns format date with 'YYYY-MM-DD HH:mm:ss'
|
||||
* @param date
|
||||
*/
|
||||
export function formatTimestamp(date: string | number | Date): string {
|
||||
return formatDate(date, 'yyyy-MM-dd HH:mm:ss')
|
||||
return formatDate(date, 'YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import dayjs from 'dayjs'
|
||||
import { useSiteConfig } from 'valaxy'
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
|
||||
export const timezone = ref<string>()
|
||||
import { onBeforeMount } from 'vue'
|
||||
|
||||
/**
|
||||
* use timezone
|
||||
|
@ -11,6 +10,7 @@ export function useTimezone() {
|
|||
const siteConfig = useSiteConfig()
|
||||
|
||||
onBeforeMount(() => {
|
||||
timezone.value = siteConfig.value.timezone
|
||||
if (siteConfig.value.timezone)
|
||||
dayjs.tz.setDefault(siteConfig.value.timezone)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import { isClient, useStorage } from '@vueuse/core'
|
||||
import { setDefaultOptions } from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
// not optimize deps all locales
|
||||
import { enUS } from 'date-fns/locale/en-US'
|
||||
import { zhCN } from 'date-fns/locale/zh-CN'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import 'dayjs/locale/en'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
|
||||
export function useLocale() {
|
||||
const { availableLocales, locale } = useI18n()
|
||||
const lang = useStorage('valaxy-locale', locale.value)
|
||||
// set date locale
|
||||
setDefaultOptions({ locale: locale.value === 'zh-CN' ? zhCN : enUS })
|
||||
// setDefaultOptions({ locale: locale.value === 'zh-CN' ? zhCN : enUS })
|
||||
dayjs.locale(locale.value === 'zh-CN' ? 'zh-cn' : 'en')
|
||||
|
||||
const toggleLocales = () => {
|
||||
// change to some real logic
|
||||
|
@ -20,7 +22,8 @@ export function useLocale() {
|
|||
lang.value = locale.value
|
||||
|
||||
// set date locale
|
||||
setDefaultOptions({ locale: locale.value === 'zh-CN' ? zhCN : enUS })
|
||||
// setDefaultOptions({ locale: locale.value === 'zh-CN' ? zhCN : enUS })
|
||||
dayjs.locale(locale.value === 'zh-CN' ? 'zh-cn' : 'en')
|
||||
|
||||
if (isClient)
|
||||
document.documentElement.setAttribute('lang', locale.value)
|
||||
|
|
|
@ -1,64 +1,26 @@
|
|||
import type { ToDateOptionsWithTZ } from 'date-fns-tz'
|
||||
import type { Post } from '../../types'
|
||||
import { format, toDate } from 'date-fns'
|
||||
import { format as formatWithTZ, toZonedTime } from 'date-fns-tz'
|
||||
import { DateTime } from 'luxon'
|
||||
import { timezone as globalTimezone } from '../composables/global'
|
||||
import { i18n } from '../modules/valaxy'
|
||||
// dayjs
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import timezone from 'dayjs/plugin/timezone'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
|
||||
const referenceDate = new Date(1986, 3 /* Apr */, 4, 10, 32, 0, 900)
|
||||
dayjs.extend(relativeTime)
|
||||
dayjs.extend(timezone)
|
||||
dayjs.extend(utc)
|
||||
|
||||
const cnTimezone = 'Asia/Shanghai'
|
||||
dayjs.tz.setDefault(cnTimezone)
|
||||
|
||||
/**
|
||||
* format the date
|
||||
* @param date the original date
|
||||
* @param formatStr the string of tokens
|
||||
* @param timezone the time zone of this local time, can be an offset or IANA time zone
|
||||
* @param options the object with options. See [Options]{@link https://date-fns.org/docs/Options}
|
||||
* format the date (dayjs)
|
||||
*/
|
||||
export function formatDate(date: string | number | Date, formatStr = 'yyyy-MM-dd', timezone?: string, options?: ToDateOptionsWithTZ): string {
|
||||
const locale = i18n.global.locale.value
|
||||
|
||||
const mergedOptions: ToDateOptionsWithTZ = Object.assign({ locale: { code: locale } }, options)
|
||||
const clientTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
|
||||
try {
|
||||
/**
|
||||
* Format the timezone-less date to ISO. If none is specified, use the client's timezone.
|
||||
* If the input date is already in ISO format, the timezone won't be applied.
|
||||
*/
|
||||
date = handleTimeWithZone(date, timezone || globalTimezone.value || clientTimezone).toString()
|
||||
// Convert to the client's timezone unless the user specifies otherwise
|
||||
const zonedDate = toZonedTime(date, options?.timeZone || clientTimezone, mergedOptions)
|
||||
// The format function will never change the underlying date
|
||||
return formatWithTZ(zonedDate, formatStr, { timeZone: options?.timeZone })
|
||||
}
|
||||
catch (error) {
|
||||
console.error(
|
||||
'The date format provided is non-standard. The recommended format is \'yyyy-MM-dd HH:mm:ss\'',
|
||||
'\nError formatting date:',
|
||||
date.toString(),
|
||||
error,
|
||||
)
|
||||
return format(referenceDate, formatStr)
|
||||
}
|
||||
}
|
||||
|
||||
function handleTimeWithZone(date: string | number | Date, timezone: string) {
|
||||
if (typeof date !== 'string')
|
||||
date = toDate(date).toISOString()
|
||||
|
||||
let dateTime = DateTime.fromISO(date, { setZone: true })
|
||||
|
||||
const toDateTime = (date: string, zone: string) => {
|
||||
// Attempt to format the date using a function that handles non-ISO 8601 formats
|
||||
const isoDate = format(date, 'yyyy-MM-dd\'T\'HH:mm:ss')
|
||||
return DateTime.fromISO(isoDate, { zone })
|
||||
}
|
||||
|
||||
if (!dateTime.isValid || !dateTime.zoneName)
|
||||
dateTime = toDateTime(date, timezone)
|
||||
|
||||
return dateTime
|
||||
export function formatDate(date?: string | number | Date, options: {
|
||||
formatStr?: string
|
||||
timezone?: string
|
||||
keepLocalTime?: boolean
|
||||
} = {}) {
|
||||
return dayjs(date).tz(options.timezone, options.keepLocalTime).format(options.formatStr || 'YYYY-MM-DD')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -113,8 +113,7 @@ export function getRollupOptions(options: ResolvedValaxyOptions) {
|
|||
const libs = [
|
||||
'@vueuse/motion',
|
||||
|
||||
'date-fns',
|
||||
'luxon',
|
||||
'dayjs',
|
||||
'vue-i18n',
|
||||
'vue-router',
|
||||
'nprogress',
|
||||
|
|
|
@ -2,11 +2,12 @@ import { writeFile } from 'node:fs/promises'
|
|||
import { join, resolve } from 'node:path'
|
||||
import { ensureSuffix } from '@antfu/utils'
|
||||
import { consola } from 'consola'
|
||||
import { formatDate } from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
import { render } from 'ejs'
|
||||
import { green, magenta } from 'picocolors'
|
||||
import { defaultPostTemplate, userRoot } from './constants'
|
||||
import { exists } from './fs'
|
||||
|
||||
import { getTemplate } from './scaffold'
|
||||
|
||||
export interface CreatePostParams {
|
||||
|
@ -65,6 +66,6 @@ async function genLayoutTemplate({
|
|||
template = defaultPostTemplate
|
||||
|
||||
// 24h format
|
||||
const dateFormat = 'yyyy-MM-dd HH:mm:ss'
|
||||
return render(template, { title, layout, date: date ? formatDate(new Date(), dateFormat) : '' })
|
||||
const dateFormat = 'YYYY-MM-DD HH:mm:ss'
|
||||
return render(template, { title, layout, date: date ? dayjs().format(dateFormat) : '' })
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@ import { readFile } from 'node:fs/promises'
|
|||
import { dirname, join, resolve } from 'node:path'
|
||||
import consola from 'consola'
|
||||
import { colors } from 'consola/utils'
|
||||
import { formatDate } from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
import fg from 'fast-glob'
|
||||
import { Feed } from 'feed'
|
||||
|
||||
import fs from 'fs-extra'
|
||||
|
||||
import matter from 'gray-matter'
|
||||
|
@ -200,7 +201,7 @@ export async function writeFeed(feedOptions: FeedOptions, posts: Item[], options
|
|||
|
||||
const { config } = options
|
||||
const siteConfig = config.siteConfig
|
||||
const now = formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss zzz')
|
||||
const now = dayjs().format('YYYY-MM-DD HH:mm:ss zzz')
|
||||
const tableData = [
|
||||
[`${colors.yellow('RSS Feed Files')} 📡 ${colors.dim(now)}`, '', ''],
|
||||
[colors.bold('Site Url'), '', colors.cyan(siteConfig.url)],
|
||||
|
|
|
@ -11,13 +11,12 @@ import { isInstalledGlobally, resolveImportPath, toAtFS } from '../utils'
|
|||
*/
|
||||
const clientDeps = [
|
||||
// https://cn.vite.dev/guide/dep-pre-bundling.html#the-why
|
||||
// bundle date-fns to one file
|
||||
'date-fns',
|
||||
'date-fns/locale/en-US',
|
||||
'date-fns/locale/zh-CN',
|
||||
'date-fns-tz',
|
||||
// @TODO replace luxon by date-fns
|
||||
'luxon',
|
||||
'dayjs',
|
||||
'dayjs/locale/en',
|
||||
'dayjs/locale/zh-cn',
|
||||
'dayjs/plugin/relativeTime',
|
||||
'dayjs/plugin/timezone',
|
||||
'dayjs/plugin/utc',
|
||||
|
||||
'@unhead/schema-org',
|
||||
'@unhead/vue',
|
||||
|
|
|
@ -64,7 +64,6 @@
|
|||
"@iconify-json/ri": "catalog:",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.1",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@unhead/addons": "^1.11.14",
|
||||
"@unhead/schema-org": "^1.11.14",
|
||||
"@unhead/vue": "^1.11.14",
|
||||
|
@ -78,8 +77,7 @@
|
|||
"consola": "^3.2.3",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"css-i18n": "^0.0.5",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"debug": "^4.4.0",
|
||||
"defu": "^6.1.4",
|
||||
"ejs": "^3.1.10",
|
||||
|
@ -96,7 +94,6 @@
|
|||
"js-yaml": "^4.1.0",
|
||||
"katex": "^0.16.15",
|
||||
"lru-cache": "^11.0.2",
|
||||
"luxon": "^3.5.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-anchor": "^9.2.0",
|
||||
"markdown-it-attrs": "^4.3.0",
|
||||
|
|
|
@ -7,8 +7,8 @@ settings:
|
|||
catalogs:
|
||||
default:
|
||||
'@iconify-json/ant-design':
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4
|
||||
'@iconify-json/carbon':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4
|
||||
|
@ -19,11 +19,11 @@ catalogs:
|
|||
specifier: ^1.2.3
|
||||
version: 1.2.3
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: ^1.2.15
|
||||
version: 1.2.15
|
||||
specifier: ^1.2.16
|
||||
version: 1.2.16
|
||||
'@iconify-json/vscode-icons':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4
|
||||
specifier: ^1.2.5
|
||||
version: 1.2.5
|
||||
typescript:
|
||||
specifier: '5.6'
|
||||
version: 5.6.3
|
||||
|
@ -77,7 +77,7 @@ importers:
|
|||
version: 1.2.3
|
||||
'@iconify-json/vscode-icons':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.4
|
||||
version: 1.2.5
|
||||
'@microsoft/api-extractor':
|
||||
specifier: ^7.48.1
|
||||
version: 7.48.1(@types/node@22.10.2)
|
||||
|
@ -201,10 +201,10 @@ importers:
|
|||
dependencies:
|
||||
'@iconify-json/ant-design':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.3
|
||||
version: 1.2.4
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.15
|
||||
version: 1.2.16
|
||||
|
||||
demo/yun:
|
||||
dependencies:
|
||||
|
@ -269,7 +269,7 @@ importers:
|
|||
version: 1.2.4
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.15
|
||||
version: 1.2.16
|
||||
nodemon:
|
||||
specifier: ^3.1.9
|
||||
version: 3.1.9
|
||||
|
@ -376,9 +376,6 @@ importers:
|
|||
'@types/katex':
|
||||
specifier: ^0.16.7
|
||||
version: 0.16.7
|
||||
'@types/luxon':
|
||||
specifier: ^3.4.2
|
||||
version: 3.4.2
|
||||
'@unhead/addons':
|
||||
specifier: ^1.11.14
|
||||
version: 1.11.14(rollup@4.28.1)
|
||||
|
@ -418,12 +415,9 @@ importers:
|
|||
css-i18n:
|
||||
specifier: ^0.0.5
|
||||
version: 0.0.5
|
||||
date-fns:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
date-fns-tz:
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0(date-fns@4.1.0)
|
||||
dayjs:
|
||||
specifier: ^1.11.13
|
||||
version: 1.11.13
|
||||
debug:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0(supports-color@5.5.0)
|
||||
|
@ -472,9 +466,6 @@ importers:
|
|||
lru-cache:
|
||||
specifier: ^11.0.2
|
||||
version: 11.0.2
|
||||
luxon:
|
||||
specifier: ^3.5.0
|
||||
version: 3.5.0
|
||||
markdown-it:
|
||||
specifier: ^14.1.0
|
||||
version: 14.1.0
|
||||
|
@ -734,10 +725,10 @@ importers:
|
|||
version: 0.1.0
|
||||
'@iconify-json/ant-design':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.3
|
||||
version: 1.2.4
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.15
|
||||
version: 1.2.16
|
||||
'@vueuse/motion':
|
||||
specifier: ^2.2.6
|
||||
version: 2.2.6(rollup@4.28.1)(vue@3.5.13(typescript@5.6.3))
|
||||
|
@ -1746,8 +1737,8 @@ packages:
|
|||
'@iarna/toml@2.2.5':
|
||||
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
|
||||
|
||||
'@iconify-json/ant-design@1.2.3':
|
||||
resolution: {integrity: sha512-LoGrgGfRJ9iwwmTbtKnWg0FtN+87gy/C5WWErC2qUygyRuOyOMTxKJoUnl360UaXejiInDIK58o0jlJKoIVS4Q==}
|
||||
'@iconify-json/ant-design@1.2.4':
|
||||
resolution: {integrity: sha512-hcrq18yTNmYyDhP+Lk26aA30UmmnrFEk/kxj/kVMgLkBMglgnHRu2PAMHlS2h3mAqJCRj9+OtnczsAT60THvZA==}
|
||||
|
||||
'@iconify-json/carbon@1.2.4':
|
||||
resolution: {integrity: sha512-DhW2jjMVGwV0DLHc0cmDYohdtGxMra8UuwgjHrryPy+rQX4gXhJwCBBVP2h2UG/92AoRCTn7zUJve4WvY5MLYg==}
|
||||
|
@ -1764,9 +1755,15 @@ packages:
|
|||
'@iconify-json/simple-icons@1.2.15':
|
||||
resolution: {integrity: sha512-4vxMQwkjsbjVIVGsPjKBnLMqAXu4wSlHmeN35KaJLK0UJNUj/ef6ES5c4bT/U4bSZjD2oZqOjOWTPD+HCrSUkg==}
|
||||
|
||||
'@iconify-json/simple-icons@1.2.16':
|
||||
resolution: {integrity: sha512-mnQ0Ih8CDIgOqbi0qz01AJNOeFVuGFRimelg3JmJtD0y5EpZVw+enPPcpcxJKipsRZ/oqhcP3AhYkF1kM7yomg==}
|
||||
|
||||
'@iconify-json/vscode-icons@1.2.4':
|
||||
resolution: {integrity: sha512-cmSNh18IMlOgCIYqqW5zqvXn7/6bRpr246c+/ywE/Uq3F0zQPcpHhuJp1nAIj275PF7+ouj+MU1jlmuL59pPRA==}
|
||||
|
||||
'@iconify-json/vscode-icons@1.2.5':
|
||||
resolution: {integrity: sha512-VgDWPmgfNxgzkz8/NWLI6+42DDh3VuntXgrYZLmjkzFH8rosyGFz5SkGT7S6sNy+bIu67MCJOK62k1/r19twBw==}
|
||||
|
||||
'@iconify/types@2.0.0':
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
|
||||
|
@ -10034,7 +10031,7 @@ snapshots:
|
|||
|
||||
'@iarna/toml@2.2.5': {}
|
||||
|
||||
'@iconify-json/ant-design@1.2.3':
|
||||
'@iconify-json/ant-design@1.2.4':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
|
@ -10058,10 +10055,18 @@ snapshots:
|
|||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/simple-icons@1.2.16':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/vscode-icons@1.2.4':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/vscode-icons@1.2.5':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify/types@2.0.0': {}
|
||||
|
||||
'@iconify/utils@2.2.0':
|
||||
|
|
|
@ -7,12 +7,12 @@ packages:
|
|||
- packages/@valaxyjs/*
|
||||
- scripts
|
||||
catalog:
|
||||
'@iconify-json/ant-design': ^1.2.3
|
||||
'@iconify-json/ant-design': ^1.2.4
|
||||
'@iconify-json/carbon': ^1.2.4
|
||||
'@iconify-json/logos': ^1.2.3
|
||||
'@iconify-json/ri': ^1.2.3
|
||||
'@iconify-json/simple-icons': ^1.2.15
|
||||
'@iconify-json/vscode-icons': ^1.2.4
|
||||
'@iconify-json/simple-icons': ^1.2.16
|
||||
'@iconify-json/vscode-icons': ^1.2.5
|
||||
typescript: '5.6'
|
||||
unbuild: ^3.0.1
|
||||
vite: ^6.0.3
|
||||
|
|
Loading…
Reference in New Issue