ESM/Vite SSR compatibility issue - "is not a function" error with import * as matter #181

Open
opened 2026-02-08 05:07:27 +00:00 by Malay-dev · 0 comments
Malay-dev commented 2026-02-08 05:07:27 +00:00 (Migrated from github.com)

Description

Problem

When using gray-matter in an ESM project with Vite SSR (e.g., Astro), the module cannot be properly imported and called.

Environment

  • Node.js version: v20+
  • gray-matter version: 4.0.3
  • Bundler: Vite 6.x (via Astro 5.16.0)
  • Project type: ESM ("type": "module" in package.json)
  • TypeScript: 5.9.3
  • tsconfig: esModuleInterop: true, allowSyntheticDefaultImports: true

Error

TypeError: (0 , __vite_ssr_import_2__) is not a function
    at parseFrontmatter (eval at runInlinedModule (.../vite/dist/node/module-runner.js:1062:11), <anonymous>:73:45)

Reproduction Steps

  1. Create an ESM project with Vite or Astro:

    npm create astro@latest
    
  2. Install gray-matter:

    npm install gray-matter
    
  3. Import and use in a TypeScript file:

    import * as matter from 'gray-matter';
    // or
    import matter from 'gray-matter';
    
    const result = matter('---\ntitle: Test\n---\nContent');
    console.log(result.data); // Expected: { title: 'Test' }
    
  4. Run in Vite SSR mode:

    npm run dev
    

Expected Behavior

The import should work and matter() should be callable as a function.

Actual Behavior

  • import matter from 'gray-matter' fails with TypeScript error: "module has no default export"
  • import * as matter from 'gray-matter' imports a namespace object where matter() is not callable at runtime
  • The following workaround is required:
    const fn = (matter as any).default || matter;
    const result = fn(content);
    

Root Cause Analysis

The package only exports via CommonJS (module.exports = matter) with:

{
  "main": "index.js"
}

Missing:

  • No exports field for proper ESM support
  • No module field for bundlers
  • No .mjs entry point

The type definition uses export = matter which is the CommonJS-style export:

// gray-matter.d.ts line 114
export = matter

Suggested Fix

Add ESM support via the exports field in package.json:

{
  "main": "index.js",
  "module": "index.mjs",
  "exports": {
    ".": {
      "import": "./index.mjs",
      "require": "./index.js",
      "types": "./gray-matter.d.ts"
    }
  }
}

And create an ESM wrapper (index.mjs):

import matter from './index.js';
export default matter;
export const stringify = matter.stringify;
export const read = matter.read;
export const test = matter.test;
export const language = matter.language;

Update type definitions to support both:

// For ESM default import
declare const matter: MatterFunction;
export default matter;

// For named exports
export { stringify, read, test, language };

Current Workaround

import * as matter from 'gray-matter';

function parseFrontmatter(content: string) {
    // With `import * as matter`, the function may be on matter.default
    const parse = (matter as any).default || matter;
    const result = parse(content);
    return { meta: result.data, body: result.content };
}
## Description ### Problem When using `gray-matter` in an ESM project with Vite SSR (e.g., Astro), the module cannot be properly imported and called. ### Environment - **Node.js version:** v20+ - **gray-matter version:** 4.0.3 - **Bundler:** Vite 6.x (via Astro 5.16.0) - **Project type:** ESM (`"type": "module"` in package.json) - **TypeScript:** 5.9.3 - **tsconfig:** `esModuleInterop: true`, `allowSyntheticDefaultImports: true` ### Error ``` TypeError: (0 , __vite_ssr_import_2__) is not a function at parseFrontmatter (eval at runInlinedModule (.../vite/dist/node/module-runner.js:1062:11), <anonymous>:73:45) ``` ### Reproduction Steps 1. Create an ESM project with Vite or Astro: ```bash npm create astro@latest ``` 2. Install gray-matter: ```bash npm install gray-matter ``` 3. Import and use in a TypeScript file: ```typescript import * as matter from 'gray-matter'; // or import matter from 'gray-matter'; const result = matter('---\ntitle: Test\n---\nContent'); console.log(result.data); // Expected: { title: 'Test' } ``` 4. Run in Vite SSR mode: ```bash npm run dev ``` ### Expected Behavior The import should work and `matter()` should be callable as a function. ### Actual Behavior - `import matter from 'gray-matter'` fails with TypeScript error: "module has no default export" - `import * as matter from 'gray-matter'` imports a namespace object where `matter()` is not callable at runtime - The following workaround is required: ```typescript const fn = (matter as any).default || matter; const result = fn(content); ``` ### Root Cause Analysis The package only exports via CommonJS (`module.exports = matter`) with: ```json { "main": "index.js" } ``` Missing: - No `exports` field for proper ESM support - No `module` field for bundlers - No `.mjs` entry point The type definition uses `export = matter` which is the CommonJS-style export: ```typescript // gray-matter.d.ts line 114 export = matter ``` ### Suggested Fix Add ESM support via the `exports` field in package.json: ```json { "main": "index.js", "module": "index.mjs", "exports": { ".": { "import": "./index.mjs", "require": "./index.js", "types": "./gray-matter.d.ts" } } } ``` And create an ESM wrapper (`index.mjs`): ```javascript import matter from './index.js'; export default matter; export const stringify = matter.stringify; export const read = matter.read; export const test = matter.test; export const language = matter.language; ``` Update type definitions to support both: ```typescript // For ESM default import declare const matter: MatterFunction; export default matter; // For named exports export { stringify, read, test, language }; ``` ### Current Workaround ```typescript import * as matter from 'gray-matter'; function parseFrontmatter(content: string) { // With `import * as matter`, the function may be on matter.default const parse = (matter as any).default || matter; const result = parse(content); return { meta: result.data, body: result.content }; } ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rtlabs-llm-agents/gms-gray-matter#181
No description provided.