diff --git a/src/date_utils.ts b/src/date_utils.ts index 2d28949e1..7ed5de367 100644 --- a/src/date_utils.ts +++ b/src/date_utils.ts @@ -99,6 +99,10 @@ export function __setDateFnsTzNull(): void { dateFnsTzLoadAttempted = true; } +// Declare webpack's special require function that bypasses bundling +// This is used to avoid webpack warnings for optional dependencies +declare const __non_webpack_require__: typeof require | undefined; + /** * Attempts to load date-fns-tz module. * Returns null if the module is not installed. @@ -111,13 +115,25 @@ function getDateFnsTz(): DateFnsTz | null { dateFnsTzLoadAttempted = true; try { - // Dynamic require for date-fns-tz - // Use a variable to prevent webpack from statically analyzing the require - // and showing warnings when the optional dependency is not installed - // See: https://github.com/Hacker0x01/react-datepicker/issues/6154 - const dateFnsTzModuleName = "date-fns-tz"; + // Use __non_webpack_require__ to tell webpack to use native require + // and avoid bundling warnings for this optional dependency + // See: https://github.com/Hacker0x01/react-datepicker/issues/6181 + // + // For Vite and other ESM-only bundlers, require is not available. + // In those environments, users need to configure their bundler to + // pre-bundle date-fns-tz or use the optimizeDeps option. + // See: https://github.com/Hacker0x01/react-datepicker/issues/6204 // eslint-disable-next-line @typescript-eslint/no-require-imports - dateFnsTz = require(dateFnsTzModuleName) as DateFnsTz; + const requireFn = + typeof __non_webpack_require__ !== "undefined" + ? __non_webpack_require__ + : typeof require !== "undefined" + ? require + : /* istanbul ignore next - only executes in ESM-only environments like Vite */ null; + + if (requireFn) { + dateFnsTz = requireFn("date-fns-tz") as DateFnsTz; + } } catch { /* istanbul ignore next - only executes when date-fns-tz is not installed */ dateFnsTz = null; diff --git a/src/test/timezone_test.test.tsx b/src/test/timezone_test.test.tsx index c9819f15d..032ea69f0 100644 --- a/src/test/timezone_test.test.tsx +++ b/src/test/timezone_test.test.tsx @@ -761,3 +761,36 @@ describe("Timezone fallback behavior (when date-fns-tz is not installed)", () => consoleSpy.mockRestore(); }); }); + +describe("Webpack __non_webpack_require__ support", () => { + beforeEach(() => { + __resetDateFnsTzCache(); + }); + + afterEach(() => { + // Clean up the global + // @ts-expect-error - cleaning up test global + delete globalThis.__non_webpack_require__; + __resetDateFnsTzCache(); + }); + + it("should use __non_webpack_require__ when available in webpack environment", () => { + const testDate = new Date("2024-06-15T12:00:00Z"); + + // Simulate webpack environment by defining __non_webpack_require__ + // @ts-expect-error - simulating webpack global + globalThis.__non_webpack_require__ = require; + + // This should use __non_webpack_require__ and successfully load date-fns-tz + const result = toZonedTime(testDate, "America/New_York"); + + // Should convert the date (not return original), proving date-fns-tz loaded + expect(result).toBeInstanceOf(Date); + expect(result.getHours()).toBe(8); // 12:00 UTC = 08:00 EDT + }); +}); + +// Note: The Vite ESM environment case (where require is not available) cannot be +// tested in Jest because require is always available in Node.js module scope. +// The code path is covered by an istanbul ignore comment and verified manually +// in actual Vite environments. See: https://github.com/Hacker0x01/react-datepicker/issues/6204