Skip to content

docs: Updated vanilla docs and added example (BLO-1010)#2915

Open
matthewlipski wants to merge 1 commit into
mainfrom
vanilla-update
Open

docs: Updated vanilla docs and added example (BLO-1010)#2915
matthewlipski wants to merge 1 commit into
mainfrom
vanilla-update

Conversation

@matthewlipski

@matthewlipski matthewlipski commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds an example for instantiating an editor and adding a basic side menu in vanilla JS. The docs have been updated to use the example.

Closes #2441

Rationale

The existing vanilla JS docs were out of date and the example code was incorrect, throwing errors.

Changes

  • Added vanilla JS example
  • Updated vanilla JS docs

Impact

N/A

Testing

N/A

Screenshots/Video

N/A

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature

Additional Notes

N/A

Summary by CodeRabbit

  • New Features

    • Added a Vanilla JS custom side menu example with add-block and drag-and-drop interactions.
    • Added the example to the documentation and playground listings.
    • Added metadata, setup instructions, and a README for the new example.
  • Documentation

    • Updated Vanilla JS guidance for editor setup and UI element extensions.
    • Added examples of subscribing to extension state stores.

@matthewlipski
matthewlipski requested a review from nperez0111 July 24, 2026 16:04
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blocknote Ready Ready Preview Jul 24, 2026 4:23pm
blocknote-website Ready Ready Preview Jul 24, 2026 4:23pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The vanilla JavaScript guide now documents extension-based UI elements and adds a runnable custom side menu example, including editor integration, project configuration, styling, metadata, and playground registration.

Changes

Vanilla JS custom side menu

Layer / File(s) Summary
Document UI element extensions
docs/content/docs/getting-started/vanilla-js.mdx
Updates editor setup imports and explains UI element extensions, their stores, available extensions, and subscription usage.
Custom side menu implementation
examples/vanilla-js/vanilla-custom-side-menu/src/*, index.html, main.tsx, package.json, tsconfig.json, vite-env.d.ts, vite.config.ts
Adds a React-mounted BlockNote editor with a plain-DOM side menu supporting visibility, positioning, paragraph insertion, suggestion-menu opening, and dragging.
Example catalog registration
examples/vanilla-js/vanilla-custom-side-menu/.bnexample.json, README.md, docs/content/examples/meta.json, packages/dev-scripts/examples/util.ts, playground/src/examples.gen.tsx
Registers the example metadata, documentation, vanilla-js group title, and generated playground entry.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant BlockNoteEditor
  participant SideMenuExtension
  participant SideMenuDOM
  App->>BlockNoteEditor: Create and mount editor
  App->>SideMenuExtension: Subscribe to store updates
  SideMenuExtension->>SideMenuDOM: Apply visibility and position
  SideMenuDOM->>SideMenuExtension: Trigger add or drag actions
  App->>BlockNoteEditor: Insert paragraph or open suggestion menu
Loading

Suggested reviewers: nperez0111

Poem

A rabbit hops through vanilla JS,
With side-menu buttons dressed in bliss.
Stores reveal where menus go,
Drag handles dance, add buttons glow.
Docs and examples join the play—
“Hop, ship, and code!” we cheer today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the docs update and new vanilla JS example.
Description check ✅ Passed The description includes all required sections and gives a mostly complete summary, rationale, changes, impact, testing, and checklist.
Linked Issues check ✅ Passed The PR fixes the broken Vanilla JS docs and adds a working custom side menu example, matching issue #2441.
Out of Scope Changes check ✅ Passed The changes are focused on the vanilla JS docs, example, and supporting example metadata with no clear unrelated additions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch vanilla-update

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@2915

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@2915

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@2915

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@2915

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@2915

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@2915

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@2915

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@2915

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@2915

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@2915

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@2915

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@2915

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@2915

commit: d424dc8

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://TypeCellOS.github.io/BlockNote/pr-preview/pr-2915/

Built to branch gh-pages at 2026-07-24 16:36 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
examples/vanilla-js/vanilla-custom-side-menu/src/App.tsx (1)

66-90: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor duplication: openSuggestionMenu("/") call repeated in both branches.

Both the empty-block and non-empty-block paths end with editor.getExtension(SuggestionMenu)?.openSuggestionMenu("/");. Could be hoisted after the if/else by computing the target block once.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/vanilla-js/vanilla-custom-side-menu/src/App.tsx` around lines 66 -
90, The addBtn callback duplicates the SuggestionMenu opening logic across both
branches. In the block handling around isBlockEmpty, compute the target block by
reusing block for empty content or the result of insertBlocks for non-empty
content, set the cursor to that target, and call openSuggestionMenu("/") once
after the conditional.
examples/vanilla-js/vanilla-custom-side-menu/package.json (1)

14-18: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the BlockNote package versions emitted by the generator.

Using latest allows fresh installs to resolve a different API than the version this example was authored and tested against. Use the repository’s catalog, workspace, or release version consistently; update the generator rather than this generated file. npm documents latest as a mutable dist-tag. (docs.npmjs.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/vanilla-js/vanilla-custom-side-menu/package.json` around lines 14 -
18, Update the generator responsible for the vanilla custom side-menu package
manifest so all `@blocknote` package entries use the repository’s pinned catalog,
workspace, or release version instead of the mutable "latest" tag. Apply the
change at the generator source, not the generated package.json, and keep the
versions consistent across the listed packages.

Source: MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/vanilla-js/vanilla-custom-side-menu/index.html`:
- Around line 1-9: Add the HTML5 doctype declaration at the beginning of the
document, before the html element in the custom side menu page. Leave the
existing head metadata and generated-file marker unchanged.

In `@examples/vanilla-js/vanilla-custom-side-menu/src/App.tsx`:
- Around line 32-42: Update initEditor’s returned cleanup to remove both
dynamically appended DOM nodes from rootElement after unsubscribing and
unmounting the editor: the editorElement created in initEditor and the side-menu
element created in the side menu setup. Guard removal as needed so cleanup
remains safe when the side menu was never shown, while preserving the existing
unsubscribe and editor.unmount behavior.

In `@examples/vanilla-js/vanilla-custom-side-menu/vite.config.ts`:
- Around line 15-29: Update the source-path existence check and the
`@blocknote/core/`@blocknote/react aliases in the Vite configuration to resolve
the monorepo packages from the repository root rather than examples/packages.
Keep the build-mode bypass and live-source alias behavior unchanged.
- Line 16: Update the Vite configuration path handling to derive a reusable
configDir from import.meta.url, then use configDir in the three path expressions
currently based on __dirname. Remove reliance on Vite/VitePlus __dirname
injection while preserving the existing resolved paths.

---

Nitpick comments:
In `@examples/vanilla-js/vanilla-custom-side-menu/package.json`:
- Around line 14-18: Update the generator responsible for the vanilla custom
side-menu package manifest so all `@blocknote` package entries use the
repository’s pinned catalog, workspace, or release version instead of the
mutable "latest" tag. Apply the change at the generator source, not the
generated package.json, and keep the versions consistent across the listed
packages.

In `@examples/vanilla-js/vanilla-custom-side-menu/src/App.tsx`:
- Around line 66-90: The addBtn callback duplicates the SuggestionMenu opening
logic across both branches. In the block handling around isBlockEmpty, compute
the target block by reusing block for empty content or the result of
insertBlocks for non-empty content, set the cursor to that target, and call
openSuggestionMenu("/") once after the conditional.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ff6f895c-448a-4236-9017-507a414516b1

📥 Commits

Reviewing files that changed from the base of the PR and between dee7880 and d424dc8.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • docs/content/docs/getting-started/vanilla-js.mdx
  • docs/content/examples/meta.json
  • examples/vanilla-js/vanilla-custom-side-menu/.bnexample.json
  • examples/vanilla-js/vanilla-custom-side-menu/README.md
  • examples/vanilla-js/vanilla-custom-side-menu/index.html
  • examples/vanilla-js/vanilla-custom-side-menu/main.tsx
  • examples/vanilla-js/vanilla-custom-side-menu/package.json
  • examples/vanilla-js/vanilla-custom-side-menu/src/App.tsx
  • examples/vanilla-js/vanilla-custom-side-menu/src/styles.css
  • examples/vanilla-js/vanilla-custom-side-menu/tsconfig.json
  • examples/vanilla-js/vanilla-custom-side-menu/vite-env.d.ts
  • examples/vanilla-js/vanilla-custom-side-menu/vite.config.ts
  • packages/dev-scripts/examples/util.ts
  • playground/src/examples.gen.tsx

Comment on lines +1 to +9
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Side Menu (Vanilla JS)</title>
<script>
<!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY -->
</script>
</head>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add <!DOCTYPE html>.

Static analysis (HTMLHint) flags the missing doctype declaration, which causes the page to render in quirks mode.

🐛 Proposed fix
+<!DOCTYPE html>
 <html lang="en">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Side Menu (Vanilla JS)</title>
<script>
<!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY -->
</script>
</head>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Side Menu (Vanilla JS)</title>
<script>
<!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY -->
</script>
</head>
🧰 Tools
🪛 HTMLHint (1.9.2)

[error] 1-1: Doctype must be declared before any non-comment content.

(doctype-first)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/vanilla-js/vanilla-custom-side-menu/index.html` around lines 1 - 9,
Add the HTML5 doctype declaration at the beginning of the document, before the
html element in the custom side menu page. Leave the existing head metadata and
generated-file marker unchanged.

Source: Linters/SAST tools

Comment on lines +32 to +42
function initEditor(rootElement: HTMLElement) {
const editor = BlockNoteEditor.create();

// `editor.mount` turns the element it's given into the editable area, so we
// mount into a dedicated child element. This keeps our custom UI elements
// (like the Side Menu below) separate from the editor's content.
const editorElement = document.createElement("div");
rootElement.appendChild(editorElement);
editor.mount(editorElement);

const sideMenu = editor.getExtension(SideMenuExtension)!;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Cleanup doesn't remove the appended DOM nodes, leaking elements on remount/StrictMode double-invoke.

initEditor appends editorElement (line 39) and the custom side menu element (line 110) as children of rootElement, but the returned cleanup (lines 124-127) only calls unsubscribe() and editor.unmount() — it never removes these nodes from rootElement. Since main.tsx wraps <App /> in <React.StrictMode>, React will mount→cleanup→mount the effect once in development; without removing the appended nodes, a stale editorElement and (if the side menu was ever shown) a stale, detached-but-still-in-DOM side menu accumulate under the same root <div> every time the effect reruns.

🐛 Proposed fix
   return () => {
     unsubscribe();
     editor.unmount();
+    editorElement.remove();
+    element?.remove();
   };

Also applies to: 108-128, 130-139

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/vanilla-js/vanilla-custom-side-menu/src/App.tsx` around lines 32 -
42, Update initEditor’s returned cleanup to remove both dynamically appended DOM
nodes from rootElement after unsubscribing and unmounting the editor: the
editorElement created in initEditor and the side-menu element created in the
side menu setup. Guard removal as needed so cleanup remains safe when the side
menu was never shown, while preserving the existing unsubscribe and
editor.unmount behavior.

Comment on lines +15 to +29
conf.command === "build" ||
!fs.existsSync(path.resolve(__dirname, "../../packages/core/src"))
? {}
: ({
// Comment out the lines below to load a built version of blocknote
// or, keep as is to load live from sources with live reload working
"@blocknote/core": path.resolve(
__dirname,
"../../packages/core/src/",
),
"@blocknote/react": path.resolve(
__dirname,
"../../packages/react/src/",
),
} as any),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the monorepo source path.

Even if __dirname points to the config directory, ../../packages/core/src resolves to examples/packages/core/src, not the repository’s packages/core/src. The existence check therefore disables the local-source aliases during development.

Proposed fix
-      !fs.existsSync(path.resolve(__dirname, "../../packages/core/src"))
+      !fs.existsSync(path.resolve(__dirname, "../../../packages/core/src"))
...
-              "../../packages/core/src/",
+              "../../../packages/core/src/",
...
-              "../../packages/react/src/",
+              "../../../packages/react/src/",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
conf.command === "build" ||
!fs.existsSync(path.resolve(__dirname, "../../packages/core/src"))
? {}
: ({
// Comment out the lines below to load a built version of blocknote
// or, keep as is to load live from sources with live reload working
"@blocknote/core": path.resolve(
__dirname,
"../../packages/core/src/",
),
"@blocknote/react": path.resolve(
__dirname,
"../../packages/react/src/",
),
} as any),
conf.command === "build" ||
!fs.existsSync(path.resolve(__dirname, "../../../packages/core/src"))
? {}
: ({
// Comment out the lines below to load a built version of blocknote
// or, keep as is to load live from sources with live reload working
"`@blocknote/core`": path.resolve(
__dirname,
"../../../packages/core/src/",
),
"`@blocknote/react`": path.resolve(
__dirname,
"../../../packages/react/src/",
),
} as any),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/vanilla-js/vanilla-custom-side-menu/vite.config.ts` around lines 15
- 29, Update the source-path existence check and the
`@blocknote/core/`@blocknote/react aliases in the Vite configuration to resolve
the monorepo packages from the repository root rather than examples/packages.
Keep the build-mode bypass and live-source alias behavior unchanged.

resolve: {
alias:
conf.command === "build" ||
!fs.existsSync(path.resolve(__dirname, "../../packages/core/src"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python - <<'PY'
from pathlib import Path

config_dir = Path("examples/vanilla-js/vanilla-custom-side-menu").resolve()
actual = (config_dir / "../../../packages/core/src").resolve()
incorrect = (config_dir / "../../packages/core/src").resolve()

assert actual != incorrect
assert actual.is_dir()
print(f"expected source path: {actual}")
print(f"configured source path: {incorrect}")
PY

node --input-type=module -e \
  'if (typeof __dirname !== "undefined") process.exit(1); console.log("__dirname unavailable in ESM")'

Repository: TypeCellOS/BlockNote

Length of output: 316


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## Candidate files"
git ls-files | rg '(^|/)package\.json$|examples/vanilla-js/vanilla-custom-side-menu/vite\.config\.ts$|examples/vanilla-js/vanilla-custom-side-menu/package\.json$'

echo
echo "## package files"
for f in examples/vanilla-js/vanilla-custom-side-menu/package.json package.json; do
  if [ -f "$f" ]; then
    echo "--- $f"
    sed -n '1,220p' "$f"
  fi
done

echo
echo "## vite config"
if [ -f examples/vanilla-js/vanilla-custom-side-menu/vite.config.ts ]; then
  cat -n examples/vanilla-js/vanilla-custom-side-menu/vite.config.ts
fi

echo
echo "## root package.json type field"
python3 - <<'PY'
import json
from pathlib import Path
p=Path("package.json")
print(p.exists())
if p.exists():
    data=json.loads(p.read_text())
    print(data.get("type"))
PY

Repository: TypeCellOS/BlockNote

Length of output: 11191


🌐 Web query:

Vite Plus config loads as ESM commonjs shim __dirname __filename

💡 Result:

In Vite configuration files, dirname and filename are natively unavailable when using ES modules (ESM) [1], which is the standard behavior in modern Node.js environments (especially when "type": "module" is set in package.json) [1][2]. To address this, Vite automatically injects these variables into your config files and their dependencies during the loading process [3][4]. Key behaviors regarding this injection: - Automatic Injection: Vite pre-processes config files, injecting definitions for dirname and filename (along with import.meta.url) so they behave as they would in CommonJS [3][4]. - Global Scope Usage: Because Vite injects these as global-like variables in the context of the config file, you can use them directly at the top level [4][5]. - Shadowing Restrictions: You cannot declare your own variables named dirname or filename at the top level of your config file [4][6]. Doing so will result in a SyntaxError (e.g., Identifier has already been declared) because the injected variable is already present in that scope [4]. You can, however, shadow these variables inside local function scopes [4][5]. - Best Practice: While the injected variables are provided for compatibility, modern Node.js environments now support import.meta.dirname and import.meta.url directly [7]. Using import.meta.dirname is considered more idiomatic and "proper" for ESM files as it avoids relying on Vite-specific injection mechanisms [7]. If you encounter issues where these variables are not working as expected, ensure you are not attempting to manually declare them or use them in ways that conflict with the injected definitions [4][6]. For complex path resolution needs, using the built-in path module (e.g., import path from 'node:path') in combination with import.meta.url is the standard approach [7].

Citations:


🌐 Web query:

Vite Plus vite-plus config import __dirname commonjs shim

💡 Result:

Vite+ (vite-plus) is a unified toolchain built on top of Vite and other tools (like Vitest, Rolldown, and Oxc) that simplifies the development workflow into a single configuration and CLI [1][2][3]. Because Vite+ is a superset of Vite, it follows Vite's core configuration principles [2][3]. Regarding the use of dirname and CommonJS modules in your configuration: 1. dirname in ESM: In modern Node.js environments and Vite projects configured as ES modules ("type": "module" in package.json), dirname is not defined by default [4][5]. Vite performs automatic replacement of dirname and filename in config files, but this behavior can conflict if your project explicitly defines these or uses "type": "module" [6][4][7]. 2. Recommended Approach: To avoid "ReferenceError: dirname is not defined" or similar issues, the recommended practice is to use import.meta.dirname (supported in current Node.js versions) [5] or create your own shim. A commonly used snippet to derive dirname in ESM is [4]: import { fileURLToPath } from 'url'; import { dirname } from 'path'; const dirname = dirname(fileURLToPath(import.meta.url)); 3. CommonJS Compatibility: If you are importing CommonJS modules into your Vite or Vite+ project, you may encounter compatibility issues because Vite defaults to ESM [8]. You can resolve these by configuring the optimizeDeps and build.commonjsOptions fields in your vite.config.ts (or the Vite+ equivalent) [8]: export default defineConfig({ optimizeDeps: { include: ['your-commonjs-dependency'], }, build: { commonjsOptions: { include: [/your-commonjs-dependency/, /node_modules/], }, }, }); If you are using Vite+ specifically, you configure these settings within the same unified vite.config.ts file, ensuring that your logic handles ESM/CJS interop as shown above [9][2].

Citations:


🌐 Web query:

site:voidzero.dev vite-plus config defines __dirname package.json type module __dirname unavailable

💡 Result:

In Node.js, when your package is configured with "type": "module" in package.json, the environment is strictly ES Modules (ESM). In ESM, global variables like dirname and filename are unavailable because they are specific to the CommonJS module system. To replicate the functionality of dirname in an ESM Vite configuration file (e.g., vite.config.ts), you must manually derive the path using the file URL of the current module. You can achieve this using the import.meta object and the node:url module: import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; const dirname = dirname(fileURLToPath(import.meta.url)); This pattern allows you to determine the directory path of your configuration file reliably within an ESM environment. Vite and associated toolchains (like Vite+ and Rolldown) maintain compatibility with standard Node.js module resolution, so this approach is the standard solution for accessing directory paths in ESM-based configuration files. {confidence: 100%, citations: [1]}

Citations:


🌐 Web query:

voidzero vite-plus config imports auto inject __dirname __filename __dirname unavailable ESM __dirname

💡 Result:

In an ESM environment, such as a project using Vite+ (which enforces strict ESM and native Node resolution), dirname and filename are not available because they are specific to CommonJS [1][2]. To handle this in your codebase or Vite configuration, you should avoid relying on global injection and instead use the standard ESM import.meta property [1][3]. Recommended Approaches: 1. Use import.meta.dirname and import.meta.filename: Modern Node.js versions (and current Vite/Vite+ environments) support import.meta.dirname and import.meta.filename directly [1]. This is the most efficient and preferred method [1]. 2. Manually define them (Legacy/Compatibility): If you must support environments where import.meta.dirname is not available, use the standard url module pattern [3]: import { fileURLToPath } from 'url'; import { dirname } from 'path'; const filename = fileURLToPath(import.meta.url); const dirname = dirname(filename); Vite+ Specific Context: - Vite+ does not automatically inject dirname or filename into your ESM files [4][5]. - While some older tools (like tsdown) provided shims to transform these references for ESM compatibility, relying on such shims is fragile and deprecated in favor of native ESM practices [4][1]. - When using Vite+ vp pack for library builds, ensure your code is ESM-compliant; if you encounter issues with legacy code, these shims are sometimes managed via the shims: true option in vp pack, though resolution of these shims can be sensitive to your specific project structure [4][6]. - For configuration files (vite.config.ts), Vite+ typically uses native loaders [7][8]. If your config fails due to missing dirname, convert the logic to use import.meta.dirname or standard path utilities rather than relying on automatic injection [1][3].

Citations:


🌐 Web query:

git voidzero vite-plus packages config shim __dirname __filename ESM

💡 Result:

In the Vite+ (voidzero) ecosystem, shims are used to maintain compatibility between CommonJS and ESM, particularly for legacy Node.js variables like dirname and filename which are not available in standard ESM [1][2]. 1. Purpose of Shims: When enabled, shims allow code to access dirname and filename in ESM environments by automatically injecting the necessary logic (using fileURLToPath and import.meta.url) [2]. This is essential when migrating projects from CommonJS to ESM [2]. 2. Vite+ Configuration: In Vite+, projects often configure their builds through vite.config.ts [3]. Issues have been reported where tsdown-style shims (which Vite+ leverages for bundling) were not correctly bundled or resolved after migrating to Vite+, specifically leading to [UNRESOLVED_IMPORT] errors for esm-shims.js [4][5]. This was addressed in updates to the core package where the shim file is copied to the distribution directory during bundling [5]. 3. ESM and dirname/filename: While standard ESM does not support these variables, the Vite+ toolchain supports "native" config loading (which relies on native Node.js ESM loading) [6][7]. When using native ESM, developers are encouraged to move away from these CJS globals toward standard ESM patterns (e.g., using import.meta.url) [7]. 4. Potential Pitfalls: - Configuration Errors: If your vite.config.ts relies on these globals in an environment expecting strict ESM compatibility, it may fail unless the config loader handles the transformation [6]. - Tooling Issues: Some tools (like Oxlint or Oxfmt) that use dynamic import to load configuration files may encounter issues if the config relies on non-standard ESM features like dirname, leading to recommendations to decouple configuration into smaller, standard-compliant files [6]. If you are encountering errors related to these shims in Vite+, ensure you are on a recent version of the toolchain, as missing shim files in the distribution were a known issue [4][5]. When defining your project configuration, prioritize standard ESM syntax to avoid reliance on these shims where possible [7].

Citations:


🌐 Web query:

Vite documentation config commonjs-shims dirname filename __dirname __filename ts

💡 Result:

In modern Node.js and Vite environments, dirname and filename are CommonJS-specific global variables that are not available in ES modules (ESM) [1][2]. While Vite does not automatically provide these shims in your application code, you can resolve the issue using the standard Node.js approach or specific build-time shims [1][3][4]. 1. Recommended Approach (Node.js Standard): Instead of relying on dirname or filename, you should use the native import.meta.url [1]. In modern Node.js versions (v20.11.0+ / v21.2.0+), you can use import.meta.dirname and import.meta.filename directly [1]. For older versions, use the following pattern: import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; const filename = fileURLToPath(import.meta.url); const dirname = dirname(filename); 2. Vite Configuration Files (vite.config.ts/js): Vite internally transforms dirname and filename in configuration files if they are not in an ESM context (i.e., if your package.json does not have "type": "module") [5][2]. If you are using "type": "module" in your project, Vite will not provide these shims in your config file, and you must manually define them using the pattern above [2]. 3. Build-Time Shims: If your project or dependencies require dirname or filename in your ESM bundle, you can use build-time shims [6][4]. - Plugins: You can use a custom Vite plugin or build tools like tsdown that provide a shims: true option to automatically inject these variables into your ESM output [6][4]. - Library Authors: If you are encountering these errors from a third-party dependency, you may need to patch the dependency or use a plugin to polyfill the environment [3][4]. Note that Vite's build.commonjsOptions is primarily designed for Rollup's CommonJS plugin to handle CJS-to-ESM transformations and is generally not the tool used to provide global shims for your own code [7][8].

Citations:


🌐 Web query:

vite documentation "dirname filename" "__dirname" ES module package type module

💡 Result:

In ECMAScript modules (ESM)—which are used when "type": "module" is set in package.json or when using.mjs files—the global variables dirname and filename are not available [1][2][3]. To obtain the directory or file path in modern environments (Node.js 20.11.0 and later), you should use the built-in import.meta properties [2][4][5]: const dirname = import.meta.dirname; const filename = import.meta.filename; For older Node.js versions, you can reconstruct these values using the following approach [6][2]: import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; const filename = fileURLToPath(import.meta.url); const dirname = dirname(filename); Important Notes: 1. Vite Configuration: While older Vite documentation may have suggested Vite handles these variables automatically, this behavior primarily applies to CommonJS-style configurations [7][1]. If you are using native ESM (e.g., "type": "module"), you must define these variables manually as shown above [1][8]. 2. Browser Compatibility: These properties (import.meta.dirname/filename) and Node.js-specific modules (node:path, node:url) are intended for use in Node.js environments [2]. They will not work in the browser, where import.meta.dirname will return undefined [2]. 3. Dependency Issues: If you encounter errors due to dependencies that rely on dirname, this is often because the dependency is written for CommonJS [8]. You may need to patch the dependency or configure Vite to handle CommonJS transformations if necessary [9][10].

Citations:


🌐 Web query:

"import.meta.dirname" "vite-plus" "vite.config.ts" "__dirname"

💡 Result:

In modern Vite configurations, particularly when working with ES modules (such as in projects with "type": "module" in package.json or when using.ts config files), import.meta.dirname is the recommended way to resolve directory paths [1][2]. Historically, Vite attempted to automatically replace dirname in configuration files [3][4], but this behavior can be unreliable, especially in ESM environments where dirname is not natively available [4][5]. To safely resolve file paths in your vite.config.ts, you can use import.meta.dirname directly [1][2]: import { resolve } from 'node:path' import { defineConfig } from 'vite' export default defineConfig({ build: { rollupOptions: { input: { main: resolve(import.meta.dirname, 'index.html'), }, }, }, }) If you are working in an environment where import.meta.dirname is not supported (older Node.js versions), the standard approach is to derive it from import.meta.url [6][7]: import { dirname } from 'node:path' import { fileURLToPath } from 'node:url' const dirname = dirname(fileURLToPath(import.meta.url)) Using import.meta.dirname is now the preferred, idiomatic approach in Vite [1][2].

Citations:


Use ESM-compatible path resolution in vite.config.ts.

examples/vanilla-js/vanilla-custom-side-menu/package.json is "type": "module", so __dirname is not provided by Node here. Derive configDir from import.meta.url and reuse it for the three path expressions at lines 16, 22, and 26 instead of relying on Vite/VitePlus injection.
[low_effort_and high_reward]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/vanilla-js/vanilla-custom-side-menu/vite.config.ts` at line 16,
Update the Vite configuration path handling to derive a reusable configDir from
import.meta.url, then use configDir in the three path expressions currently
based on __dirname. Remove reliance on Vite/VitePlus __dirname injection while
preserving the existing resolved paths.

Source: MCP tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"editor.sideMenu" is undefined in @blocknote/core (Vanilla JS Setup Guide is broken)

1 participant