Skip to content

Switch nutils to vite build#226

Merged
seonglae merged 10 commits intomainfrom
codex/refactor-tsup-to-vite-and-reduce-build-size
Feb 4, 2026
Merged

Switch nutils to vite build#226
seonglae merged 10 commits intomainfrom
codex/refactor-tsup-to-vite-and-reduce-build-size

Conversation

@seonglae
Copy link
Member

@seonglae seonglae commented Jun 6, 2025

Summary

  • convert nutils from tsup to vite
  • add vite-plugin-dts to root deps
  • format vite config

Testing

  • pnpm test (fails: fetch failed)
  • pnpm build

https://chatgpt.com/codex/tasks/task_e_6842ca0173248327a02f307c5bfe9848

Summary by CodeRabbit

  • Bug Fixes

    • Fixed custom components not being preserved when providing wrapper components in nreact context.
  • Chores

    • Migrated build system from tsup to Vite across all packages for improved build performance.
    • Added developer documentation for repository usage and configuration.

@codesandbox
Copy link

codesandbox bot commented Jun 6, 2025

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@seonglae seonglae self-assigned this Jun 6, 2025
@seonglae seonglae requested a review from Copilot June 7, 2025 17:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR converts the nutils build process from tsup to Vite while adding related plugin and configuration changes, and extends the Notion API and CLI export features.

  • Switched build tool and updated configuration in nutils (vite.config.ts, package.json, and removal of tsup.config.ts).
  • Added a new Notion API method (getPageBacklinks) along with corresponding tests and documentation updates.
  • Updated CLI export features with options for treemap and stats generation, though duplicate imports and redundant exports were introduced.

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/nutils/vite.config.ts New Vite configuration replacing tsup
packages/nutils/tsup.config.ts Tsup configuration removed
packages/nutils/package.json Updated build and watch scripts to use Vite
packages/nreact/src/context.tsx Added cleanup of falsy component values
packages/nreact/src/components/search-dialog.tsx Modified debounce logic with an unexpected onInput attribute
packages/nclient/src/notion-api.ts Added new getPageBacklinks method
packages/nclient/src/notion-api.test.ts New tests for the backlinks feature
packages/nclient/readme.md Documentation updated for backlinks
packages/cli/src/treemap.ts Changes in treemap generation with a potential undefined variable
packages/cli/src/notion/export.ts Extended export functionality with duplicate import statements
packages/cli/src/main.ts Duplicate export statements added
package.json Added vite-plugin-dts dependency
Comments suppressed due to low confidence (1)

packages/cli/src/treemap.ts:15

  • The removal of the computation for 'treemapDataBlocks' causes its later use in generateTreemapHTML to reference an undefined variable. Ensure that a proper blocks metric is computed or remove the corresponding usage.
-  const treemapDataBlocks = computeMetrics(pageTree, 'blocks')


// debounce search calls so the expensive query only runs after typing stops
this._search = debounce(this._searchImpl.bind(this), 500)
onInput={this._onChangeQuery}
Copy link

Copilot AI Jun 7, 2025

Choose a reason for hiding this comment

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

The 'onInput={this._onChangeQuery}' attribute appears to be misplaced within the debounce function block. Consider moving it to the appropriate component JSX element to avoid unintended behavior.

Copilot uses AI. Check for mistakes.
const stats = computeStats(tree)
await writeStats(`${this.folder}/stats.json`, stats)
}
import { generateTreemaps, PageNode } from '../treemap'
Copy link

Copilot AI Jun 7, 2025

Choose a reason for hiding this comment

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

A duplicate import of 'generateTreemaps' and 'PageNode' was introduced, which can lead to confusion and potential maintenance issues. Removing the redundant import should resolve this.

Suggested change
import { generateTreemaps, PageNode } from '../treemap'

Copilot uses AI. Check for mistakes.
Comment on lines 21 to 22
export * from './treemap'
export * from './stats'
Copy link

Copilot AI Jun 7, 2025

Choose a reason for hiding this comment

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

The duplicate export statement for './treemap' (and similarly for './stats') can cause redundancy and potential conflicts. Remove the extra export lines to keep the module exports clear.

Suggested change
export * from './treemap'
export * from './stats'

Copilot uses AI. Check for mistakes.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Duplicate Cleanup Logic Creates Dead Code

Duplicate code block for cleaning up falsy components. The logic to filter out falsy component values is duplicated, appearing both inside and immediately outside a React.useMemo callback. The original code outside the callback was not removed when the logic was moved inside, resulting in unreachable dead code.

packages/nreact/src/context.tsx#L190-L203

}
// ensure the user can't override default components with falsy values
// since it would result in very difficult-to-debug react errors
for (const key of Object.keys(components)) if (!components[key]) delete components[key]
return components
}, [themeComponents])
// ensure the user can't override default components with falsy values
// since it would result in very difficult-to-debug react errors
for (const key of Object.keys(components)) if (!components[key]) delete components[key]
return components
}, [themeComponents])

Fix in Cursor


Bug: Treemap Generation Fails Due to Syntax and Reference Errors

The generateTreemaps function is incomplete, causing a syntax error due to a missing closing brace. Additionally, it results in a runtime reference error because the treemapDataBlocks variable is used in a generateTreemapHTML call without being defined, as its declaration was removed. This prevents the blocktree.html generation feature from working.

packages/cli/src/treemap.ts#L14-L18

await generateTreemapHTML(treemapDataPages, titlePages, outputPathPages)
const titleBlocks = 'Texonom BlockMap'
const outputPathBlocks = `${folder}/blocktree.html`
await generateTreemapHTML(treemapDataBlocks, titleBlocks, outputPathBlocks)

Fix in Cursor


Bug: Duplicate Test Case Causes Runner Conflicts

The "Page Backlink" test case is duplicated. An identical test is defined twice, leading to test runner conflicts due to duplicate test names and potentially masking test failures.

packages/nclient/src/notion-api.test.ts#L67-L73

test(`Page Backlink`, { timeout: 10000, concurrent: true }, async () => {
const api = new NotionAPI({ authToken: process.env.NOTION_TOKEN })
const backlinks = await api.getPageBacklinks('441d5ce2-b781-46d0-9354-54042b4f06d9')
expect(backlinks.backlinks.length > 0)
})

Fix in Cursor


Bug: Code Corruption: Duplicate and Malformed `debounce` Function

The commit introduces malformed code that prevents compilation. It includes a duplicate, fragmented implementation of the debounce utility function, featuring an incomplete statement, an orphaned onInput JSX attribute, and a misplaced function body.

packages/nreact/src/components/search-dialog.tsx#L19-L29

// debounce search calls so the expensive query only runs after typing stops
this._search = debounce(this._searchImpl.bind(this), 500)
onInput={this._onChangeQuery}
let timeout: ReturnType<typeof setTimeout> | undefined
return (...args: any[]) => {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => func(...args), wait)
}
}

Fix in Cursor


Bug: Redundant Module Exports Cause Compilation Issues

Duplicate export statements for ./treemap and ./stats modules are present in packages/cli/src/main.ts. These redundant exports may cause compilation errors or unexpected module behavior.

packages/cli/src/main.ts#L20-L22

export * from './stats'
export * from './treemap'
export * from './stats'

Fix in Cursor


Bug: Malformed File Structure Causes Compilation Failure

The file has a malformed structure with duplicate import statements for generateTreemaps, PageNode, computeStats, and writeStats. It also includes orphaned Option.Boolean property definitions (treemap, stats) that are incorrectly placed outside the NotionExportCommand class. This will prevent compilation.

packages/cli/src/notion/export.ts#L1-L31

import { Option, Command } from 'clipanion'
import { NotionExporter } from './index'
import { generateTreemaps, PageNode } from '../treemap'
import { computeStats, writeStats } from '../stats'
treemap = Option.Boolean('--treemap', {
description: 'Generate HTML treemap after export'
})
stats = Option.Boolean('--stats', {
description: 'Generate statistics JSON after export'
})
if (this.treemap || this.stats) if (!exporter.pageTree) await exporter.loadRaw()
const tree = exporter.pageTree as unknown as PageNode
if (this.treemap && tree) await generateTreemaps(this.folder, tree)
if (this.stats && tree) {
const stats = computeStats(tree)
await writeStats(`${this.folder}/stats.json`, stats)
}
import { generateTreemaps, PageNode } from '../treemap'
import { computeStats, writeStats } from '../stats'
export class NotionExportCommand extends Command {
static paths = [['export']]
folder = Option.String('-o,--output', 'texonom-raw', {
description: 'Target root folder to export folder'
})
md = Option.String('-m,--md', 'texonom-md', {
description: 'Target folder to export markdown'

Fix in Cursor


BugBot free trial expires on June 13, 2025
You have used $0.00 of your $0.00 spend limit so far. Manage your spend limit in the Cursor dashboard.

Was this report helpful? Give feedback by reacting with 👍 or 👎

seonglae and others added 5 commits June 9, 2025 02:06
- Change assert to with for JSON imports
- Add vite-plugin-dts to root devDependencies
- Fix duplicate code from bad merge in context.tsx and search-dialog.tsx
- Add missing imports in search-dialog.tsx
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Keep vite-plugin-dts from branch
- Update vite and vitest to latest versions
- Fix ESLint 9.x compatibility by adding ESLINT_USE_FLAT_CONFIG=false

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

The pull request migrates the monorepo's build toolchain from tsup to Vite across multiple packages. Root configuration is updated with ESLint flat config and vite-plugin-dts. Each package's tsup configuration is replaced with Vite equivalents while updating build and watch scripts. Minor refactoring occurs in nreact components. Documentation is added in CLAUDE.md.

Changes

Cohort / File(s) Summary
Documentation & Root Configuration
CLAUDE.md, package.json
New documentation file added for Claude Code usage. Root package.json updated to prepend ESLint config flag and add vite-plugin-dts ^4.5.0 dependency.
Build Tool Migration - CLI Package
packages/cli/package.json, packages/cli/tsup.config.ts, packages/cli/vite.config.ts
Replaced tsup with Vite for build pipeline. Scripts updated to use vite build. Vite config targets Node.js v16 with ES module output, externalizes dependencies and core Node modules, includes DTS plugin.
Build Tool Migration - nclient Package
packages/nclient/package.json, packages/nclient/tsup.config.ts, packages/nclient/vite.config.ts
Migrated build from tsup to Vite. Package scripts updated to use vite build --watch --mode development. Vite config generates ES module with type definitions.
Build Tool Migration - ncompat Package
packages/ncompat/package.json, packages/ncompat/tsup.config.ts, packages/ncompat/vite.config.ts
Build toolchain migrated to Vite. Scripts and configuration aligned with consistent pattern. Library build targets es2015 with sourcemaps and minification enabled.
Build Tool Migration - nreact Package
packages/nreact/package.json, packages/nreact/tsup.config.ts, packages/nreact/vite.config.ts
Transitioned from tsup to Vite build. Watch command updated to use Vite's development mode. Config defines library build with DTS plugin integration.
Build Tool Migration - ntypes Package
packages/ntypes/package.json, packages/ntypes/tsup.config.ts, packages/ntypes/vite.config.ts
Build configuration replaced with Vite. New watch script added. vite-plugin-dts added as dev dependency for type declaration generation.
Build Tool Migration - nutils Package
packages/nutils/package.json, packages/nutils/tsup.config.ts, packages/nutils/vite.config.ts
Switched build toolchain to Vite with explicit external dependency handling. Added vite-plugin-dts ^3.8.1. Externalizes is-url-superb, mem, normalize-url, and other dependencies.
Component Enhancements
packages/nreact/src/components/search-dialog.tsx, packages/nreact/src/context.tsx
Minor import reordering in search-dialog. Context component now conditionally assigns PageLink and Link wrappers only when not already defined, preserving custom components.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 From tsup to Vite, our builds take flight,
Config files dance in the morning light,
Dependencies bundled, declarations flew,
A monorepo transformed, fresh and new!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks the required 'Description' and 'Notion Test Page ID' sections specified in the repository template, providing only a summary, testing notes, and a task link. Add a 'Description' section with detailed explanation of the changes, and include a 'Notion Test Page ID' for a publicly accessible Notion page related to the PR as required by the template.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Switch nutils to vite build' directly and clearly summarizes the primary change: migrating the nutils package from tsup to Vite, which is the main focus of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/refactor-tsup-to-vite-and-reduce-build-size

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@CLAUDE.md`:
- Around line 37-47: The fenced code block containing the ASCII architecture
diagram (the block starting with "ntypes (types)
─────────┬──────────────────────┐") is missing a language specifier; update that
opening fence to include a language identifier such as "text" or "plaintext"
(e.g., change "```" to "```text") so the markdown linter passes and the diagram
is rendered consistently.

In `@package.json`:
- Around line 46-47: The package.json has inconsistent indentation for the
"vite" dependency (the "vite" entry is missing the 4-space leading indentation
used by other entries); update the JSON so the "vite" line uses the same 4-space
indentation as surrounding dependency lines (ensure the key "vite": "^7.3.1",
matches the spacing style of "vite-plugin-dts" and other entries) and validate
the file remains valid JSON.

In `@packages/nutils/vite.config.ts`:
- Around line 1-20: The vite.config.ts currently hardcodes externals in the
build.rollupOptions.external array which diverges from other packages; update
this file to read peerDependencies and dependencies from this package's
package.json and compute the external list dynamically (like other packages do)
and replace the static array in build.rollupOptions.external with that computed
list; locate the export default defineConfig block and the
build.rollupOptions.external symbol to implement the change and ensure the dts
plugin usage (dts({ tsconfigPath: 'tsconfig.json', outDir: 'build' })) remains
unaffected.
🧹 Nitpick comments (2)
packages/ntypes/package.json (1)

26-28: Inconsistent vite-plugin-dts placement across packages.

This package has vite-plugin-dts as a local devDependency, while other packages (ncompat, cli, nclient, nreact) rely on the root workspace's devDependency. Consider whether this should be:

  1. Hoisted to root only (like other packages), or
  2. Added consistently to all packages that need DTS generation.

Either approach works, but consistency aids maintainability.

packages/cli/vite.config.ts (1)

16-26: Consider a more comprehensive approach for Node built-in externalization.

The explicit list of Node built-ins (fs, fs/promises, path, stream, util) works, but may miss other built-ins if they're added later (e.g., os, crypto, child_process). Consider using a regex pattern or the node: protocol prefix for more robust externalization.

♻️ Optional: Use regex for Node built-ins
     rollupOptions: {
       external: [
         ...Object.keys(pkg.dependencies || {}),
         ...Object.keys(pkg.peerDependencies || {}),
-        'fs',
-        'fs/promises',
-        'path',
-        'stream',
-        'util'
-      ]
+        /^node:/,
+        /^(fs|path|stream|util|os|crypto|child_process|http|https|url|querystring|buffer|events|assert|module|tty|readline|process)(\/.*)?$/
+      ]
     }

Comment on lines +37 to +47
```
ntypes (types) ─────────┬──────────────────────┐
│ │
▼ ▼
nutils (utilities) ncompat (compat layer)
┌─────────────┼─────────────┐
▼ ▼ ▼
nclient nreact cli
(API) (React) (exporter)
```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language specifier to fenced code block.

The architecture diagram code block lacks a language identifier. While this is an ASCII diagram, adding a language specifier (or text/plaintext) satisfies the markdown linting rule and improves consistency.

📝 Proposed fix
-```
+```text
 ntypes (types) ─────────┬──────────────────────┐
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 37-37: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In `@CLAUDE.md` around lines 37 - 47, The fenced code block containing the ASCII
architecture diagram (the block starting with "ntypes (types)
─────────┬──────────────────────┐") is missing a language specifier; update that
opening fence to include a language identifier such as "text" or "plaintext"
(e.g., change "```" to "```text") so the markdown linter passes and the diagram
is rendered consistently.

Comment on lines +46 to +47
"vite": "^7.3.1",
"vite-plugin-dts": "^4.5.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Formatting inconsistency on line 46.

The vite entry on line 46 is missing leading indentation spaces, breaking the consistent JSON formatting. All other entries have proper indentation with 4 spaces.

🔧 Proposed fix
-"vite": "^7.3.1",
+    "vite": "^7.3.1",
📝 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
"vite": "^7.3.1",
"vite-plugin-dts": "^4.5.0",
"vite": "^7.3.1",
"vite-plugin-dts": "^4.5.0",
🤖 Prompt for AI Agents
In `@package.json` around lines 46 - 47, The package.json has inconsistent
indentation for the "vite" dependency (the "vite" entry is missing the 4-space
leading indentation used by other entries); update the JSON so the "vite" line
uses the same 4-space indentation as surrounding dependency lines (ensure the
key "vite": "^7.3.1", matches the spacing style of "vite-plugin-dts" and other
entries) and validate the file remains valid JSON.

Comment on lines +1 to +20
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'

export default defineConfig({
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: () => 'index.js'
},
outDir: 'build',
target: 'es2015',
sourcemap: true,
minify: true,
rollupOptions: {
external: ['is-url-superb', 'mem', 'normalize-url', '@texonom/ntypes', 'p-queue']
}
},
plugins: [dts({ tsconfigPath: 'tsconfig.json', outDir: 'build' })]
})
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Inconsistent externalization approach compared to other packages.

This config hardcodes the external dependencies while other packages (ncompat, nclient, ntypes, nreact) dynamically read them from package.json. This inconsistency creates a maintenance burden—if dependencies change, both package.json and vite.config.ts need to be updated.

♻️ Align with other packages by reading externals from package.json
 import { defineConfig } from 'vite'
 import dts from 'vite-plugin-dts'
+import pkg from './package.json' with { type: 'json' }

 export default defineConfig({
   build: {
     lib: {
       entry: 'src/index.ts',
       formats: ['es'],
       fileName: () => 'index.js'
     },
     outDir: 'build',
     target: 'es2015',
     sourcemap: true,
     minify: true,
     rollupOptions: {
-      external: ['is-url-superb', 'mem', 'normalize-url', '@texonom/ntypes', 'p-queue']
+      external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]
     }
   },
   plugins: [dts({ tsconfigPath: 'tsconfig.json', outDir: 'build' })]
 })
🤖 Prompt for AI Agents
In `@packages/nutils/vite.config.ts` around lines 1 - 20, The vite.config.ts
currently hardcodes externals in the build.rollupOptions.external array which
diverges from other packages; update this file to read peerDependencies and
dependencies from this package's package.json and compute the external list
dynamically (like other packages do) and replace the static array in
build.rollupOptions.external with that computed list; locate the export default
defineConfig block and the build.rollupOptions.external symbol to implement the
change and ensure the dts plugin usage (dts({ tsconfigPath: 'tsconfig.json',
outDir: 'build' })) remains unaffected.

@seonglae seonglae merged commit 298ac0e into main Feb 4, 2026
0 of 2 checks passed
@seonglae seonglae deleted the codex/refactor-tsup-to-vite-and-reduce-build-size branch February 4, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant