Skip to content

feat: typescript plugin for type-safe component paths#15779

Merged
AlessioGr merged 9 commits intomainfrom
feat/typescript-plugin
Feb 27, 2026
Merged

feat: typescript plugin for type-safe component paths#15779
AlessioGr merged 9 commits intomainfrom
feat/typescript-plugin

Conversation

@AlessioGr
Copy link
Copy Markdown
Member

@AlessioGr AlessioGr commented Feb 27, 2026

Adds @payloadcms/typescript-plugin, a TypeScript language service plugin that validates PayloadComponent import paths in the IDE.

screenshot.2026-02-26.at.15.55.40.mp4

It checks that referenced files and exports actually exist, provides autocomplete for both file paths and export names, and supports go-to-definition on component path strings. The plugin understands all of Payload's path conventions including absolute paths relative to baseDir, relative paths, tsconfig aliases, and package imports. It auto-detects baseDir by finding the nearest payload config file and can be overridden via tsconfig plugin options.

Installation

Install the plugin as a dev dependency:

pnpm add -D @payloadcms/typescript-plugin

Then add it to the plugins array in your tsconfig.json:

{
  "compilerOptions": {
    "plugins": [{ "name": "next" }, { "name": "@payloadcms/typescript-plugin" }]
  }
}

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 27, 2026

📦 esbuild Bundle Analysis for payload

This analysis was generated by esbuild-bundle-analyzer. 🤖

Meta File Out File Size (raw) Note
packages/next/meta_index.json esbuild/index.js 960.05 KB ✅ No change
packages/payload/meta_index.json esbuild/index.js 1.32 MB ⚠️ +32 B (+0.0%)
packages/payload/meta_shared.json esbuild/exports/shared.js 190.59 KB ✅ No change
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 281.80 KB ✅ No change
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.18 MB ✅ No change
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 16.32 KB ✅ No change
Largest paths These visualization shows top 20 largest paths in the bundle.

Meta file: packages/next/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████████▌ }}}$ 82.0%, 783.61 KB
dist/views/Version ${{\color{Goldenrod}{ █▎ }}}$ 5.4%, 51.49 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▌ }}}$ 2.3%, 21.54 KB
dist/views/Document ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 16.59 KB
dist/views/List ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 11.38 KB
dist/views/Root ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 9.03 KB
dist/views/Versions ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.17 KB
dist/views/API ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.08 KB
dist/elements/Nav ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.96 KB
dist/views/Account ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.55 KB
dist/elements/DocumentHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.81 KB
dist/views/Login ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.40 KB
dist/views/ForgotPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 3.09 KB
dist/layouts/Root ${{\color{Goldenrod}{ }}}$ 0.3%, 2.91 KB
dist/views/CreateFirstUser ${{\color{Goldenrod}{ }}}$ 0.3%, 2.81 KB
dist/templates/Default ${{\color{Goldenrod}{ }}}$ 0.3%, 2.63 KB
dist/views/BrowseByFolder ${{\color{Goldenrod}{ }}}$ 0.3%, 2.61 KB
dist/views/CollectionFolders ${{\color{Goldenrod}{ }}}$ 0.3%, 2.44 KB
dist/views/ResetPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 2.40 KB
dist/views/Logout ${{\color{Goldenrod}{ }}}$ 0.2%, 1.94 KB
(other) ${{\color{Goldenrod}{ ████▌ }}}$ 18.0%, 171.77 KB

Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████▉ }}}$ 67.6%, 887.23 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▊ }}}$ 3.3%, 43.59 KB
dist/collections/operations ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 39.77 KB
dist/versions/migrations ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 18.50 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.74 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.17 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.15 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.84 KB
dist/queues/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.80 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.54 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.87 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.35 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.69 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.67 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.54 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.83 KB
dist/collections/endpoints ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.22 KB
dist/config/sanitize.js ${{\color{Goldenrod}{ }}}$ 0.4%, 5.80 KB
dist/auth/strategies ${{\color{Goldenrod}{ }}}$ 0.4%, 5.50 KB
dist/auth/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 5.42 KB
(other) ${{\color{Goldenrod}{ ████████ }}}$ 32.4%, 424.33 KB

Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▊ }}}$ 79.4%, 148.51 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▍ }}}$ 5.6%, 10.54 KB
dist/config/orderable ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 3.13 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 2.54 KB
dist/auth/cookies.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.55 KB
dist/utilities/flattenTopLevelFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.42 KB
dist/fields/config ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 1.28 KB
dist/utilities/getVersionsConfig.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 1.04 KB
dist/utilities/flattenAllFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 943 B
dist/folders/utils ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 916 B
dist/utilities/unflatten.js ${{\color{Goldenrod}{ }}}$ 0.4%, 779 B
dist/utilities/sanitizeUserDataForEmail.js ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 651 B
dist/collections/config ${{\color{Goldenrod}{ }}}$ 0.3%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B
dist/fields/getFieldPaths.js ${{\color{Goldenrod}{ }}}$ 0.3%, 485 B
dist/errors/APIError.js ${{\color{Goldenrod}{ }}}$ 0.2%, 438 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.2%, 423 B
(other) ${{\color{Goldenrod}{ █████▏ }}}$ 20.6%, 38.43 KB

Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
dist/features/blocks ${{\color{Goldenrod}{ ███▏ }}}$ 12.6%, 35.15 KB
dist/lexical/plugins ${{\color{Goldenrod}{ ██▉ }}}$ 11.5%, 32.00 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▏ }}}$ 8.7%, 24.36 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 23.70 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▋ }}}$ 6.8%, 18.99 KB
dist/features/link ${{\color{Goldenrod}{ █▋ }}}$ 6.6%, 18.25 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▌ }}}$ 6.4%, 17.75 KB
dist/features/upload ${{\color{Goldenrod}{ █▏ }}}$ 4.9%, 13.77 KB
dist/features/textState ${{\color{Goldenrod}{ █ }}}$ 4.0%, 11.08 KB
dist/features/relationship ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 9.03 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 8.49 KB
dist/features/debug ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.39 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 7.15 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 7.05 KB
dist/lexical/config ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.08 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.00 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.17 KB
dist/lexical/theme ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.62 KB
dist/features/indent ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.50 KB
(other) ${{\color{Goldenrod}{ █████████████████████▊ }}}$ 87.4%, 243.39 KB

Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████▎ }}}$ 49.4%, 579.02 KB
dist/elements/FolderView ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 29.37 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 27.63 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 17.27 KB
dist/views/Edit ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 17.14 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.78 KB
dist/elements/Table ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.77 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.31 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 14.24 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 13.69 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 10.36 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 9.06 KB
dist/providers/Folders ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.47 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/ListHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.99 KB
dist/fields/Array ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.73 KB
dist/views/CollectionFolder ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.50 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.35 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.34 KB
(other) ${{\color{Goldenrod}{ ████████████▋ }}}$ 50.6%, 592.52 KB

Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ █████ }}}$ 20.0%, 3.12 KB
../../node_modules ${{\color{Goldenrod}{ ████▎ }}}$ 17.0%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▍ }}}$ 9.8%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 862 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █▎ }}}$ 5.2%, 814 B
dist/utilities/getGlobalData.js ${{\color{Goldenrod}{ █▏ }}}$ 4.9%, 762 B
dist/utilities/api.js ${{\color{Goldenrod}{ █▏ }}}$ 4.8%, 756 B
dist/elements/Translation ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▋ }}}$ 2.8%, 440 B
dist/utilities/traverseForLocalizedFields.js ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 399 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 339 B
dist/utilities/getVisibleEntities.js ${{\color{Goldenrod}{ ▌ }}}$ 2.1%, 329 B
dist/utilities/getNavGroups.js ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 301 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 180 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 159 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 152 B
dist/forms/Form ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 147 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 146 B
(other) ${{\color{Goldenrod}{ ████████████████████ }}}$ 80.0%, 12.51 KB
Details

Next to the size is how much the size has increased or decreased compared with the base branch of this PR.

  • ‼️: Size increased by 20% or more. Special attention should be given to this.
  • ⚠️: Size increased in acceptable range (lower than 20%).
  • ✅: No change or even downsized.
  • 🗑️: The out file is deleted: not found in base branch.
  • 🆕: The out file is newly found: will be added to base branch.

@AlessioGr AlessioGr marked this pull request as ready for review February 27, 2026 01:57
@AlessioGr AlessioGr requested a review from denolfe as a code owner February 27, 2026 01:57
@AlessioGr AlessioGr enabled auto-merge (squash) February 27, 2026 02:03
@AlessioGr AlessioGr changed the title feat: typescript plugin for import paths feat: typescript plugin for type-safe component paths Feb 27, 2026
Copy link
Copy Markdown
Member

@denolfe denolfe left a comment

Choose a reason for hiding this comment

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

Looks good since it's purely an opt-in.

@AlessioGr AlessioGr merged commit 7639664 into main Feb 27, 2026
292 of 304 checks passed
@AlessioGr AlessioGr deleted the feat/typescript-plugin branch February 27, 2026 19:15
@github-actions
Copy link
Copy Markdown
Contributor

🚀 This is included in version v3.78.0

@ZNAXNOR
Copy link
Copy Markdown

ZNAXNOR commented Mar 2, 2026

@payloadcms/typescript-plugin is not in the npm registry. Is this plugin not public yet?

@V-iktor
Copy link
Copy Markdown

V-iktor commented Mar 2, 2026

pnpm add -D @payloadcms/typescript-plugin
 ERR_PNPM_FETCH_404  GET https://registry.npmjs.org/@payloadcms%2Ftypescript-plugin: Not Found - 404

AlessioGr added a commit that referenced this pull request Mar 2, 2026
…15780)

- Renames `Widget.ComponentPath` to `Widget.Component` and types it as
`PayloadComponent` instead of `string`
- This aligns dashboard widgets with every other component reference in
Payload (collections, globals, fields, admin components) - none of them
use _path_ in the property name, and all of them are typed as
`PayloadComponent`
- Enables new [typescript
plugin](#15779) to work for
widget paths (the plugin uses `PayloadComponent` contextual type
detection - `string`-typed properties were invisible to it)

## Breaking Change

`Widget.ComponentPath` has been renamed to `Widget.Component`.

### Migration

Find and replace in your Payload config:

```diff
 widgets: [
   {
     slug: 'my-widget',
-    ComponentPath: './components/MyWidget#MyWidget',
+    Component: './components/MyWidget#MyWidget',
   },
 ]
```
@denolfe
Copy link
Copy Markdown
Member

denolfe commented Mar 5, 2026

@ZNAXNOR @V-iktor The package is now public 🎉

tadjh added a commit to digitalgroundgame/pragmatic-papers that referenced this pull request Mar 18, 2026
## Context

### BREAKING CHANGES:
The only listed breaking changes are in payload 3.79.0. Two of them.
>- rename widget ComponentPath to Component for consistency
([#15780](payloadcms/payload#15780))
([f7d0d04](payloadcms/payload@f7d0d04)
- Renames `Widget.ComponentPath` to `Widget.Component` and types it as
PayloadComponent`instead of`string`
- This aligns dashboard widgets with every other component reference in
(collections, globals, fields, admin components) - none of them _path_
in the property name, and all of them are typed as `PayloadComponent`
- Enables new [typescript
plugin](payloadcms/payload#15779) to work for
widget paths (the plugin uses `PayloadComponent` contextual type
detection - `string`-typed properties were invisible to it)
> - **ui:** typo in CodeEditor export statement
([#15795](payloadcms/payload#15795))
([c5b2a91](payloadcms/payload@c5b2a91))

>**Lexical Upgrade 0.35.0 → 0.41.0 (richtext-lexical)** — Upgrades the
Lexical rich text editor dependency from v0.35.0 to v0.41.0. Includes
upstream fixes like `normalizeMarkdown`
([facebook/lexical#7812](facebook/lexical#7812)).
All Lexical breaking changes are handled internally by Payload — no
action required for standard usage. If you installed `lexical` manually,
update it to 0.41.0 (though using the re-exported versions from
`@payloadcms/richtext-lexical/lexical/*` is recommended).
[#15760](payloadcms/payload#15760)

### Anaylsis of codebase vs breaking changes
Project does not currently define any custom dashboard widgets in
payload.config.ts, we are using the default payload dashboard.

codebase already correctly imports Lexical types via
@payloadcms/richtext-lexical/lexical (which is the recommended pattern)

CodeEditor, we are not importing or using the CodeEditor component

# Changes Made
Downgraded `next`: 15.5.9 → 15.4.11
Upgraded `lucide-react`: 0.378.0 → ^0.471.0 (latest)
Upgraded `baseline-browser-mapping` (latest)
Remove `lexical` dependency
### Further analysis after upgrade using gemini
#### 1. Payload CMS Compatibility Gap

Payload CMS 3.x relies on internal Next.js routing behaviors that were
altered in version 15.5. Staying on `15.5.9` introduced:

- **Build Failures**: Next.js 15.5's new strict TypeScript route
validation rejects Payload's auto-generated API route types
(specifically the `RouteHandlerConfig`).
    
- **Admin UI Slowness**: Documented performance regressions in 15.5
cause the Payload Admin panel to experience massive load-time spikes
(reported jumps from 2s to 30s+).

	OLD dev tested by espdesign
	` ✓ Compiled /admin/[[...segments]] in 5.5s (6831 modules)`
	NEW dev tested by espdesign
	` ✓ Compiled /admin/[[...segments]] in 9s (7912 modules
    
- **HMR Instability**: Turbopack HMR in 15.5 frequently fails to find
client modules in the manifest, leading to frequent "Module not found"
errors during development.
    
**Result**: Reverting to **15.4.11** restores the "Stable Zone" for
Payload 3.x, ensuring fast Admin UI performance and successful
production builds.

#### 2. React 19 Peer Conflict

The previous version of `lucide-react` was hard-coded to expect React 18
or older.

- **Fix**: Upgrading to the latest version of `lucide-react` adds
official support for **React 19**, resolving the peer dependency
warning.

Further changes:
```
`[baseline-browser-mapping] The data in this module is over two months old.  To ensure accurate Baseline data, please update: `npm i baseline-
browser-mapping@latest -D
```

### Migrations:
No :)
```
[22:04:26] INFO: Migration DOWN statements generation complete.
✔ No schema changes detected. Would you like to create a blank migration file? … no
```


## Test Plan
Confirm on staging.
Confirm on dev.

---------

Co-authored-by: tadjh <hello@tadjh.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants