Skip to content

Commit 2f2c057

Browse files
authored
refactor: Replace date-fns usage with existing d3-time to reduce bundle size (#551)
* Replace all date-fns `format()` usage * refactor: Replace `date-fns` usage with existing `d3-time` to reduce bundle size
1 parent c06aa1b commit 2f2c057

17 files changed

Lines changed: 83 additions & 59 deletions

File tree

.changeset/pink-hornets-rest.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': patch
3+
---
4+
5+
refactor: Replace `date-fns` usage with existing `d3-time` to reduce bundle size

packages/layerchart/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@
108108
"d3-shape": "^3.2.0",
109109
"d3-tile": "^1.0.0",
110110
"d3-time": "^3.1.0",
111-
"date-fns": "^4.1.0",
112111
"lodash-es": "^4.17.21",
113112
"runed": "^0.28.0"
114113
},

packages/layerchart/src/lib/components/MonthPath.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
</script>
3131

3232
<script lang="ts">
33-
import { timeWeek, timeYear } from 'd3-time';
34-
import { endOfMonth } from 'date-fns';
33+
import { timeWeek, timeMonth, timeYear } from 'd3-time';
34+
import { endOfInterval } from '$lib/utils/date.js';
3535
import { cls } from '@layerstack/tailwind';
3636
import { layerClass } from '$lib/utils/attributes.js';
3737
import Spline, { type SplinePropsWithoutHTML } from './Spline.svelte';
@@ -58,7 +58,7 @@
5858
const startWeek = $derived(timeWeek.count(timeYear(date), date));
5959
6060
// end of month
61-
const monthEnd = $derived(endOfMonth(date));
61+
const monthEnd = $derived(endOfInterval(date, timeMonth));
6262
const endDayOfWeek = $derived(monthEnd.getDay());
6363
const endWeek = $derived(timeWeek.count(timeYear(monthEnd), monthEnd));
6464
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { type TimeInterval } from 'd3-time';
2+
3+
/**
4+
* Get the date at the end of the interval
5+
* Similar to `interval.ceil(date)` except:
6+
* - returns end of day instead of start of next day
7+
* - properly handles start of day (i.e. not return same date)
8+
*/
9+
export function endOfInterval(date: Date, interval: TimeInterval) {
10+
// Can not use `new Date(+interval.ceil(date) - 1)`; as `.ceil()` will return same date when start of the day (matching `.floor()`)
11+
return new Date(interval.offset(interval.floor(date), 1).getTime() - 1);
12+
}

packages/layerchart/src/lib/utils/genData.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addMinutes, startOfDay, startOfToday, subDays } from 'date-fns';
1+
import { timeMinute, timeDay } from 'd3-time';
22
import { cumsum } from 'd3-array';
33
import { randomNormal } from 'd3-random';
44

@@ -65,7 +65,7 @@ export function createDateSeries<TKey extends string>(options: {
6565
keys?: TKey[];
6666
value?: 'number' | 'integer';
6767
}) {
68-
const now = startOfToday();
68+
const now = timeDay.floor(new Date());
6969

7070
const count = options.count ?? 10;
7171
const min = options.min;
@@ -74,7 +74,7 @@ export function createDateSeries<TKey extends string>(options: {
7474

7575
return Array.from({ length: count }).map((_, i) => {
7676
return {
77-
date: subDays(now, count - i - 1),
77+
date: timeDay.offset(now, -count + i),
7878
...Object.fromEntries(
7979
keys.map((key) => {
8080
return [
@@ -99,11 +99,11 @@ export function createTimeSeries<TKey extends string>(options: {
9999
const max = options.max;
100100
const keys = options.keys ?? ['value'];
101101

102-
let lastStartDate = startOfDay(new Date());
102+
let lastStartDate = timeDay.floor(new Date());
103103

104104
const timeSeries = Array.from({ length: count }).map((_, i) => {
105-
const startDate = addMinutes(lastStartDate, getRandomInteger(0, 60));
106-
const endDate = addMinutes(startDate, getRandomInteger(5, 60));
105+
const startDate = timeMinute.offset(lastStartDate, getRandomInteger(0, 60));
106+
const endDate = timeMinute.offset(startDate, getRandomInteger(5, 60));
107107
lastStartDate = startDate;
108108
return {
109109
name: `item ${i + 1}`,

packages/layerchart/src/routes/docs/components/AreaChart/+page.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
} from 'layerchart';
2222
import { curveBasis, curveCatmullRom, curveStepAfter } from 'd3-shape';
2323
import { group } from 'd3-array';
24-
import { Button, Field, ToggleGroup, ToggleOption, Kbd, Switch } from 'svelte-ux';
24+
import { timeDay } from 'd3-time';
25+
import { Button, Field, Kbd, Switch } from 'svelte-ux';
2526
import { format, sortFunc } from '@layerstack/utils';
26-
import { addDays } from 'date-fns';
2727
import { cls } from '@layerstack/tailwind';
2828
2929
import Preview from '$lib/docs/Preview.svelte';
@@ -55,11 +55,11 @@
5555
5656
const now = new Date();
5757
const denseDateSeriesData = randomWalk({ count: 1000 }).map((value, i) => ({
58-
date: addDays(now, i),
58+
date: timeDay.offset(now, i),
5959
value: 10 + value,
6060
}));
6161
const denseDateSeriesData2 = randomWalk({ count: 1000 }).map((value, i) => ({
62-
date: addDays(now, i),
62+
date: timeDay.offset(now, i),
6363
value: 10 + value,
6464
}));
6565

packages/layerchart/src/routes/docs/components/BrushContext/+page.svelte

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<script lang="ts">
22
import { scaleBand, scaleOrdinal, scaleTime } from 'd3-scale';
33
import { range } from 'd3-array';
4+
import { timeDay } from 'd3-time';
45
import { State } from 'svelte-ux';
56
import { format } from '@layerstack/utils';
67
import { cls } from '@layerstack/tailwind';
7-
import { subDays } from 'date-fns';
88
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
99
1010
import {
@@ -32,13 +32,27 @@
3232
let { data } = $props();
3333
3434
const now = new Date();
35-
let xDomain = $state([subDays(now, 60), subDays(now, 30)]) as DomainType | undefined;
35+
let xDomain = $state([timeDay.offset(now, -60), timeDay.offset(now, -30)]) as
36+
| DomainType
37+
| undefined;
3638
3739
const seriesData = [
38-
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
39-
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
40-
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
41-
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
40+
randomWalk({ count: 100 }).map((value, i) => ({
41+
date: timeDay.offset(now, -i),
42+
value: 10 + value,
43+
})),
44+
randomWalk({ count: 100 }).map((value, i) => ({
45+
date: timeDay.offset(now, -i),
46+
value: 10 + value,
47+
})),
48+
randomWalk({ count: 100 }).map((value, i) => ({
49+
date: timeDay.offset(now, -i),
50+
value: 10 + value,
51+
})),
52+
randomWalk({ count: 100 }).map((value, i) => ({
53+
date: timeDay.offset(now, -i),
54+
value: 10 + value,
55+
})),
4256
];
4357
4458
const randomData = range(200).map((d) => {

packages/layerchart/src/routes/docs/components/Calendar/+page.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
<script lang="ts">
2-
import { startOfYear, endOfYear } from 'date-fns';
32
import { scaleThreshold } from 'd3-scale';
43
import { range } from 'd3-array';
4+
import { timeYear } from 'd3-time';
55
66
import { Calendar, Chart, Group, Text, Tooltip, Layer } from 'layerchart';
77
88
import Preview from '$lib/docs/Preview.svelte';
99
import { createDateSeries } from '$lib/utils/genData.js';
1010
import { shared } from '../../shared.svelte.js';
11+
import { endOfInterval } from '$lib/utils/date.js';
1112
1213
const now = new Date();
13-
const firstDayOfYear = startOfYear(now);
14-
const lastDayOfYear = endOfYear(now);
14+
const firstDayOfYear = timeYear.floor(now);
15+
const lastDayOfYear = endOfInterval(now, timeYear);
1516
1617
const data = createDateSeries({ count: 365 * 4, min: 10, max: 100, value: 'integer' }).map(
1718
(d) => {
@@ -146,7 +147,7 @@
146147
<Layer type={shared.renderContext}>
147148
{#each range(2019, 2024) as year, i}
148149
{@const start = new Date(year, 0, 1)}
149-
{@const end = endOfYear(start)}
150+
{@const end = endOfInterval(start, timeYear)}
150151
<Group y={140 * i}>
151152
<Text
152153
value={year}

packages/layerchart/src/routes/docs/components/Pie/+page.svelte

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<script lang="ts">
2-
import { format } from 'date-fns';
32
import { sum } from 'd3-array';
43
import { cls } from '@layerstack/tailwind';
5-
import { format as formatUtil } from '@layerstack/utils';
4+
import { format } from '@layerstack/utils';
65
76
import { Arc, Chart, Group, Layer, Pie, Text, Tooltip } from 'layerchart';
87
@@ -278,7 +277,7 @@
278277
{#snippet children({ getArcTextProps })}
279278
{@const textProps = getArcTextProps('centroid')}
280279
<Text
281-
value={formatUtil(arc.data.value / dataSum, 'percent')}
280+
value={format(arc.data.value / dataSum, 'percent')}
282281
{...textProps}
283282
dy={-8}
284283
class={cls('text-base', colors.content)}
@@ -411,7 +410,7 @@
411410
</Layer>
412411
<Tooltip.Root>
413412
{#snippet children({ data })}
414-
<Tooltip.Header>{format(data.date, 'eee, MMMM do')}</Tooltip.Header>
413+
<Tooltip.Header value={data.date} format="day" />
415414
<Tooltip.List>
416415
<Tooltip.Item label="value" value={data.value} format="integer" valueAlign="right" />
417416
<Tooltip.Item
@@ -461,7 +460,7 @@
461460
>
462461
{#snippet children({ getArcTextProps })}
463462
<Text
464-
value={formatUtil(arc.data.value / dataSum, 'percent')}
463+
value={format(arc.data.value / dataSum, 'percent')}
465464
{...getArcTextProps('centroid')}
466465
class={cls('text-base', colors.content)}
467466
/>
@@ -475,7 +474,7 @@
475474

476475
<Tooltip.Root>
477476
{#snippet children({ data })}
478-
<Tooltip.Header>{format(data.date, 'eee, MMMM do')}</Tooltip.Header>
477+
<Tooltip.Header value={data.date} format="day" />
479478
<Tooltip.List>
480479
<Tooltip.Item label="value" value={data.value} format="integer" valueAlign="right" />
481480
<Tooltip.Item

packages/layerchart/src/routes/docs/examples/Duration/+page.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { scaleTime } from 'd3-scale';
3-
import { addMinutes, startOfDay } from 'date-fns';
3+
import { timeMinute, timeDay } from 'd3-time';
44
import { Duration } from 'svelte-ux';
55
66
import { BarChart, Points, Tooltip } from 'layerchart';
@@ -10,12 +10,12 @@
1010
import { shared } from '../../shared.svelte.js';
1111
1212
const count = 10;
13-
const now = startOfDay(new Date());
13+
const now = timeDay.floor(new Date());
1414
let lastStartDate = now;
1515
1616
const data = Array.from({ length: count }).map((_, i) => {
17-
const startDate = addMinutes(lastStartDate, getRandomInteger(0, 60));
18-
const endDate = addMinutes(startDate, getRandomInteger(0, 60));
17+
const startDate = timeMinute.offset(lastStartDate, getRandomInteger(0, 60));
18+
const endDate = timeMinute.offset(startDate, getRandomInteger(0, 60));
1919
lastStartDate = startDate;
2020
return {
2121
name: `Item ${i + 1}`,

0 commit comments

Comments
 (0)