vite-plugin-dayjs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["Vue.volar"]
3
+ }
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Vue 3 + TypeScript + Vite
2
+
3
+ This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
4
+
5
+ Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
@@ -0,0 +1,5 @@
1
+ import antfu from '@antfu/eslint-config'
2
+
3
+ export default antfu({
4
+
5
+ })
package/index.html ADDED
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>vite-plugin-dayjs</title>
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ <script type="module" src="/src/main.ts"></script>
12
+ </body>
13
+ </html>
package/lib/index.ts ADDED
@@ -0,0 +1,48 @@
1
+ import type { Plugin } from 'vite'
2
+
3
+ export function vitePluginDayjs(): Plugin {
4
+ return {
5
+ name: 'vite-plugin-dayjs',
6
+ enforce: 'pre',
7
+ async resolveId(source, importer, options) {
8
+ // 1) 已经使用了 dayjs/esm 的不处理
9
+ if (source.startsWith('dayjs/esm'))
10
+ return null
11
+
12
+ // 2) 根入口:dayjs -> dayjs/esm
13
+ if (source === 'dayjs') {
14
+ const resolved = await this.resolve('dayjs/esm', importer, { skipSelf: true, ...options })
15
+ return resolved
16
+ }
17
+
18
+ // 3) 插件入口的多种写法
19
+ // - dayjs/plugin/xxx/index.js -> dayjs/esm/plugin/xxx/index.js
20
+ // - dayjs/plugin/xxx.js -> dayjs/esm/plugin/xxx/index.js
21
+ // - dayjs/plugin/xxx -> dayjs/esm/plugin/xxx
22
+ const pluginIndex = source.match(/^dayjs\/plugin\/([^/]+)\/index\.js$/)
23
+ if (pluginIndex) {
24
+ const target = `dayjs/esm/plugin/${pluginIndex[1]}/index.js`
25
+ const resolved = await this.resolve(target, importer, { skipSelf: true, ...options })
26
+ return resolved
27
+ }
28
+
29
+ const pluginWithJs = source.match(/^dayjs\/plugin\/([^/]+)\.js$/)
30
+ if (pluginWithJs) {
31
+ const target = `dayjs/esm/plugin/${pluginWithJs[1]}/index.js`
32
+ const resolved = await this.resolve(target, importer, { skipSelf: true, ...options })
33
+ return resolved
34
+ }
35
+
36
+ const pluginBare = source.match(/^dayjs\/plugin\/([^/]+)$/)
37
+ if (pluginBare) {
38
+ const target = `dayjs/esm/plugin/${pluginBare[1]}`
39
+ const resolved = await this.resolve(target, importer, { skipSelf: true, ...options })
40
+ return resolved
41
+ }
42
+
43
+ return null
44
+ },
45
+ }
46
+ }
47
+
48
+ export default vitePluginDayjs
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "vite-plugin-dayjs",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./dist/index.d.mts",
8
+ "import": "./dist/index.mjs",
9
+ "require": null
10
+ }
11
+ },
12
+ "main": "./dist/index.mjs",
13
+ "types": "./dist/index.d.mts",
14
+ "devDependencies": {
15
+ "@antfu/eslint-config": "^6.7.3",
16
+ "@types/node": "^24.10.1",
17
+ "@vitejs/plugin-vue": "^6.0.1",
18
+ "@vue/tsconfig": "^0.8.1",
19
+ "dayjs": "^1.11.19",
20
+ "eslint": "^9.39.2",
21
+ "jiti": "^2.6.1",
22
+ "tsdown": "0.19.0-beta.3",
23
+ "typescript": "~5.9.3",
24
+ "vite": "npm:rolldown-vite@7.2.5",
25
+ "vitest": "^4.0.16",
26
+ "vue": "^3.5.24",
27
+ "vue-tsc": "^3.1.4"
28
+ },
29
+ "scripts": {
30
+ "dev": "vite",
31
+ "build": "tsdown",
32
+ "preview": "vite preview",
33
+ "test": "vitest run",
34
+ "prepublish": "pnpm build"
35
+ }
36
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/src/App.vue ADDED
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import HelloWorld from './components/HelloWorld.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <div>
7
+ <a href="https://vite.dev" target="_blank">
8
+ <img src="/vite.svg" class="logo" alt="Vite logo" />
9
+ </a>
10
+ <a href="https://vuejs.org/" target="_blank">
11
+ <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
12
+ </a>
13
+ </div>
14
+ <HelloWorld msg="Vite + Vue" />
15
+ </template>
16
+
17
+ <style scoped>
18
+ .logo {
19
+ height: 6em;
20
+ padding: 1.5em;
21
+ will-change: filter;
22
+ transition: filter 300ms;
23
+ }
24
+ .logo:hover {
25
+ filter: drop-shadow(0 0 2em #646cffaa);
26
+ }
27
+ .logo.vue:hover {
28
+ filter: drop-shadow(0 0 2em #42b883aa);
29
+ }
30
+ </style>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+
4
+ defineProps<{ msg: string }>()
5
+
6
+ const count = ref(0)
7
+ </script>
8
+
9
+ <template>
10
+ <h1>{{ msg }}</h1>
11
+
12
+ <div class="card">
13
+ <button type="button" @click="count++">count is {{ count }}</button>
14
+ <p>
15
+ Edit
16
+ <code>components/HelloWorld.vue</code> to test HMR
17
+ </p>
18
+ </div>
19
+
20
+ <p>
21
+ Check out
22
+ <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
23
+ >create-vue</a
24
+ >, the official Vue + Vite starter
25
+ </p>
26
+ <p>
27
+ Learn more about IDE Support for Vue in the
28
+ <a
29
+ href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
30
+ target="_blank"
31
+ >Vue Docs Scaling up Guide</a
32
+ >.
33
+ </p>
34
+ <p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
35
+ </template>
36
+
37
+ <style scoped>
38
+ .read-the-docs {
39
+ color: #888;
40
+ }
41
+ </style>
package/src/main.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { createApp } from 'vue'
2
+ import './style.css'
3
+ import App from './App.vue'
4
+
5
+ createApp(App).mount('#app')
package/src/style.css ADDED
@@ -0,0 +1,79 @@
1
+ :root {
2
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ }
15
+
16
+ a {
17
+ font-weight: 500;
18
+ color: #646cff;
19
+ text-decoration: inherit;
20
+ }
21
+ a:hover {
22
+ color: #535bf2;
23
+ }
24
+
25
+ body {
26
+ margin: 0;
27
+ display: flex;
28
+ place-items: center;
29
+ min-width: 320px;
30
+ min-height: 100vh;
31
+ }
32
+
33
+ h1 {
34
+ font-size: 3.2em;
35
+ line-height: 1.1;
36
+ }
37
+
38
+ button {
39
+ border-radius: 8px;
40
+ border: 1px solid transparent;
41
+ padding: 0.6em 1.2em;
42
+ font-size: 1em;
43
+ font-weight: 500;
44
+ font-family: inherit;
45
+ background-color: #1a1a1a;
46
+ cursor: pointer;
47
+ transition: border-color 0.25s;
48
+ }
49
+ button:hover {
50
+ border-color: #646cff;
51
+ }
52
+ button:focus,
53
+ button:focus-visible {
54
+ outline: 4px auto -webkit-focus-ring-color;
55
+ }
56
+
57
+ .card {
58
+ padding: 2em;
59
+ }
60
+
61
+ #app {
62
+ max-width: 1280px;
63
+ margin: 0 auto;
64
+ padding: 2rem;
65
+ text-align: center;
66
+ }
67
+
68
+ @media (prefers-color-scheme: light) {
69
+ :root {
70
+ color: #213547;
71
+ background-color: #ffffff;
72
+ }
73
+ a:hover {
74
+ color: #747bff;
75
+ }
76
+ button {
77
+ background-color: #f9f9f9;
78
+ }
79
+ }
@@ -0,0 +1,103 @@
1
+ import dayjs from 'dayjs'
2
+ import advancedFormat from 'dayjs/plugin/advancedFormat.js'
3
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
4
+ import duration from 'dayjs/plugin/duration'
5
+ // 测试已经使用 dayjs/esm 的不应被重复处理
6
+ import isBetween from 'dayjs/plugin/isBetween'
7
+ import isSameOrAfter from 'dayjs/plugin/isSameOrAfter.js'
8
+ // 测试不同的导入写法
9
+ import relativeTime from 'dayjs/plugin/relativeTime'
10
+ import timezone from 'dayjs/plugin/timezone'
11
+ import utc from 'dayjs/plugin/utc'
12
+ import { describe, expect, it } from 'vitest'
13
+
14
+ describe('day.js', () => {
15
+ it('should parse and format dates correctly', () => {
16
+ const date = dayjs('2024-06-15')
17
+ expect(date.format('YYYY-MM-DD')).toBe('2024-06-15')
18
+ })
19
+
20
+ it('should handle relative time (bare import)', () => {
21
+ dayjs.extend(relativeTime)
22
+
23
+ const now = dayjs()
24
+ const pastDate = now.subtract(3, 'days')
25
+ expect(pastDate.fromNow()).toBe('3 days ago')
26
+ })
27
+
28
+ it('should handle isSameOrAfter (.js import)', () => {
29
+ dayjs.extend(isSameOrAfter)
30
+
31
+ const date1 = dayjs('2024-06-15')
32
+ const date2 = dayjs('2024-06-14')
33
+ expect(date1.isSameOrAfter(date2)).toBe(true)
34
+ expect(date2.isSameOrAfter(date1)).toBe(false)
35
+ expect(date1.isSameOrAfter(date1)).toBe(true)
36
+ })
37
+
38
+ it('should handle customParseFormat (bare import)', () => {
39
+ dayjs.extend(customParseFormat)
40
+
41
+ const date = dayjs('15/06/2024', 'DD/MM/YYYY')
42
+ expect(date.format('YYYY-MM-DD')).toBe('2024-06-15')
43
+ })
44
+
45
+ it('should handle advancedFormat (.js import)', () => {
46
+ dayjs.extend(advancedFormat)
47
+
48
+ const date = dayjs('2024-06-15')
49
+ expect(date.format('Q')).toBe('2') // 第二季度
50
+ expect(date.format('Do')).toBe('15th')
51
+ })
52
+
53
+ it('should handle duration plugin', () => {
54
+ dayjs.extend(duration)
55
+
56
+ const dur = dayjs.duration(1, 'hours')
57
+ expect(dur.asMinutes()).toBe(60)
58
+ expect(dur.asSeconds()).toBe(3600)
59
+ })
60
+
61
+ it('should handle utc plugin', () => {
62
+ dayjs.extend(utc)
63
+
64
+ const date = dayjs.utc('2024-06-15T12:00:00Z')
65
+ expect(date.format('YYYY-MM-DD HH:mm:ss')).toBe('2024-06-15 12:00:00')
66
+ })
67
+
68
+ it('should handle timezone plugin', () => {
69
+ dayjs.extend(utc)
70
+ dayjs.extend(timezone)
71
+
72
+ const date = dayjs.tz('2024-06-15 12:00', 'America/New_York')
73
+ expect(date.isValid()).toBe(true)
74
+ })
75
+
76
+ it('should handle isBetween from dayjs/esm (already ESM)', () => {
77
+ dayjs.extend(isBetween)
78
+
79
+ const date = dayjs('2024-06-15')
80
+ const start = dayjs('2024-06-01')
81
+ const end = dayjs('2024-06-30')
82
+ const outside = dayjs('2024-07-15')
83
+ expect(date.isBetween(start, end)).toBe(true)
84
+ expect(outside.isBetween(start, end)).toBe(false)
85
+ })
86
+ })
87
+
88
+ describe('dayjs type declarations', () => {
89
+ it('dayjs should be a function', () => {
90
+ expect(typeof dayjs).toBe('function')
91
+ })
92
+
93
+ it('plugins should be functions', () => {
94
+ expect(typeof relativeTime).toBe('function')
95
+ expect(typeof isSameOrAfter).toBe('function')
96
+ expect(typeof customParseFormat).toBe('function')
97
+ expect(typeof advancedFormat).toBe('function')
98
+ expect(typeof duration).toBe('function')
99
+ expect(typeof utc).toBe('function')
100
+ expect(typeof timezone).toBe('function')
101
+ expect(typeof isBetween).toBe('function')
102
+ })
103
+ })
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "@vue/tsconfig/tsconfig.dom.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
+ "types": ["vite/client"],
6
+
7
+ /* Linting */
8
+ "strict": true,
9
+ "noUnusedLocals": true,
10
+ "noUnusedParameters": true,
11
+ "erasableSyntaxOnly": true,
12
+ "noFallthroughCasesInSwitch": true,
13
+ "noUncheckedSideEffectImports": true
14
+ },
15
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
16
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.lib.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "moduleDetection": "force",
7
+ "module": "ESNext",
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "types": ["node"],
12
+ "allowImportingTsExtensions": true,
13
+
14
+ /* Linting */
15
+ "strict": true,
16
+ "noFallthroughCasesInSwitch": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "noEmit": true,
20
+ "verbatimModuleSyntax": true,
21
+ "erasableSyntaxOnly": true,
22
+ "skipLibCheck": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": [
26
+ "lib/**/*.ts"
27
+ ]
28
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "moduleDetection": "force",
7
+ "module": "ESNext",
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "types": ["node"],
12
+ "allowImportingTsExtensions": true,
13
+
14
+ /* Linting */
15
+ "strict": true,
16
+ "noFallthroughCasesInSwitch": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "noEmit": true,
20
+ "verbatimModuleSyntax": true,
21
+ "erasableSyntaxOnly": true,
22
+ "skipLibCheck": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": [
26
+ "vite.config.ts",
27
+ "lib/**/*.ts",
28
+ "tests/**/*.ts"
29
+ ]
30
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'tsdown'
2
+
3
+ export default defineConfig({
4
+ entry: 'lib/index.ts',
5
+ clean: true,
6
+ dts: true,
7
+ outDir: 'dist',
8
+ format: 'esm',
9
+ external: ['vite'],
10
+ tsconfig: 'tsconfig.lib.json',
11
+ })
package/vite.config.ts ADDED
@@ -0,0 +1,8 @@
1
+ import vue from '@vitejs/plugin-vue'
2
+ import { defineConfig } from 'vite'
3
+ import { vitePluginDayjs } from './lib'
4
+
5
+ // https://vite.dev/config/
6
+ export default defineConfig({
7
+ plugins: [vue(), vitePluginDayjs()],
8
+ })