Skip to content

feat: implement strategy for optional peer deps#289

Open
sjinks wants to merge 4 commits into
trunkfrom
optional-peer-deps
Open

feat: implement strategy for optional peer deps#289
sjinks wants to merge 4 commits into
trunkfrom
optional-peer-deps

Conversation

@sjinks
Copy link
Copy Markdown
Member

@sjinks sjinks commented May 9, 2026

Adopt a hybrid dependency model aligning with ESLint shareable config and plugin packaging guidance. This allows consumers to opt in to optional framework/tooling packages (TypeScript, React, Jest, Prettier) while keeping runtime-required parser/plugin packages reliable and always installed.

Changes:

  • Move typescript, react, jest, and prettier from devDependencies to peerDependencies and mark as optional via peerDependenciesMeta
  • Expand is-package-installed() to detect optional peers in consumer package.json, enabling graceful handling in library contexts
  • Add utils/load-optional-config.js for guarded loading of optional config stacks, preventing MODULE_NOT_FOUND crashes when optional peers are absent
  • Refactor configs/recommended.js to use guarded loader for conditional TypeScript, testing, React, and Prettier config composition
  • Create public init.js entrypoint to preload optional packages for consumers requiring upfront resolution
  • Add comprehensive unit test coverage for guarded loader behavior

Package classification:

  • Keep in dependencies: all runtime-loaded parsers, plugins, resolvers, eslint-config-prettier, globals, find-package-json, typescript-eslint
  • Add as optional peers: typescript, react, jest, prettier
  • Keep as peerDependency: eslint

Benefits:

  • Consumers only install framework/tooling packages they actually use
  • Backward compatible: existing consumers with all packages installed continue working without changes
  • Clearer intent: optional ecosystem boundaries are explicit
  • Low setup friction: recommended config still works with minimal consumer configuration
  • Reliable defaults: parser/plugin stack remains guaranteed available

Documentation:

  • Update README to clarify optional peer behavior and usage patterns
  • Document init entrypoint for consumers requiring preloading
  • Add guidance for JS-only consumers and framework-specific setups

Adopt a hybrid dependency model aligning with ESLint shareable config and
plugin packaging guidance. This allows consumers to opt in to optional
framework/tooling packages (TypeScript, React, Jest, Prettier) while
keeping runtime-required parser/plugin packages reliable and always
installed.

Changes:
- Move typescript, react, jest, and prettier from devDependencies to
  peerDependencies and mark as optional via peerDependenciesMeta
- Expand is-package-installed() to detect optional peers in consumer
  package.json, enabling graceful handling in library contexts
- Add utils/load-optional-config.js for guarded loading of optional
  config stacks, preventing MODULE_NOT_FOUND crashes when optional
  peers are absent
- Refactor configs/recommended.js to use guarded loader for conditional
  TypeScript, testing, React, and Prettier config composition
- Create public init.js entrypoint to preload optional packages for
  consumers requiring upfront resolution
- Add comprehensive unit test coverage for guarded loader behavior

Package classification:
- Keep in dependencies: all runtime-loaded parsers, plugins, resolvers,
  eslint-config-prettier, globals, find-package-json, typescript-eslint
- Add as optional peers: typescript, react, jest, prettier
- Keep as peerDependency: eslint

Benefits:
- Consumers only install framework/tooling packages they actually use
- Backward compatible: existing consumers with all packages installed
  continue working without changes
- Clearer intent: optional ecosystem boundaries are explicit
- Low setup friction: recommended config still works with minimal
  consumer configuration
- Reliable defaults: parser/plugin stack remains guaranteed available

Documentation:
- Update README to clarify optional peer behavior and usage patterns
- Document init entrypoint for consumers requiring preloading
- Add guidance for JS-only consumers and framework-specific setups
@sjinks sjinks self-assigned this May 9, 2026
Copilot AI review requested due to automatic review settings May 9, 2026 23:26
Copy link
Copy Markdown
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 updates the package/dependency model to support optional peer dependencies (TypeScript, React, Jest, Prettier) and introduces guarded config loading so consumers can opt into integrations without runtime crashes when those optional packages are absent.

Changes:

  • Add a guarded optional-config loader and refactor recommended config composition to use it.
  • Expand package detection to consider peerDependencies in the consumer’s package.json.
  • Update packaging/docs and add unit tests + an init.js entrypoint for preloading optional stacks.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
utils/load-optional-config.js New helper to conditionally load optional config stacks and avoid hard crashes on missing modules.
utils/is-package-installed.js Extends dependency detection to include peerDependencies in the resolved parent package.json.
configs/recommended.js Refactors recommended config to compose optional stacks via the guarded loader.
init.js Adds an entrypoint that attempts to preload optional config stacks when the corresponding optional peer is present.
tests/load-optional-config.js Adds unit tests for guarded-loader behavior.
package.json Moves TypeScript/React/Jest/Prettier to optional peer dependencies (via peerDependenciesMeta).
package-lock.json Updates lockfile metadata to reflect new peer dependency configuration.
README.md Documents optional peer behavior and the init entrypoint usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread utils/load-optional-config.js
Comment thread __tests__/load-optional-config.js
Only swallow MODULE_NOT_FOUND when the missing module is the optional peer
itself or a subpath of it. Rethrow errors for unrelated modules to prevent
masking real packaging/config bugs.

- Update load-optional-config to parse error.message and check the missing
  module name against the optional peer package name
- Add test cases to verify unrelated module errors are rethrown
- Add test case to verify subpath modules are correctly swallowed
@sjinks sjinks force-pushed the optional-peer-deps branch from 85c56a3 to caae8b3 Compare May 9, 2026 23:35
@sjinks sjinks requested a review from Copilot May 9, 2026 23:35
Copy link
Copy Markdown
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

Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.

Comment thread configs/recommended.js
Copy link
Copy Markdown
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

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

Comment thread utils/is-package-installed.js Outdated
@sjinks sjinks force-pushed the optional-peer-deps branch from fe3341e to 056ace3 Compare May 10, 2026 06:40
@sjinks sjinks requested a review from Copilot May 10, 2026 06:47
Copy link
Copy Markdown
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

Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.

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.

2 participants