npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moodia/override-resolver

v2.1.3

Published

A Webpack resolver which allows the option to override file import paths.

Readme

OverrideResolver

A powerful Webpack plugin that allows you to override module imports based on file paths, with built-in import guards and extensive debugging capabilities.

Features

  • 🔄 File Override System: Override any module import from base source roots with custom implementations
  • 🎯 Priority-Based Overrides: Multiple override roots with configurable priority order
  • 🛡️ Import Guard: Enforce import restrictions to maintain architectural boundaries
  • 🔍 Debug Mode: Detailed logging for specific files to troubleshoot override resolution
  • 📊 Configuration Logging: Visual display of override configuration on startup
  • 🎨 Filters: Apply overrides only to specific file patterns (e.g., .shell, .style)

Installation

npm install @moodia/override-resolver

Quick Start

const OverrideResolver = require('@moodia/override-resolver');
const path = require('path');

module.exports = {
    resolve: {
        plugins: [
            new OverrideResolver(
                // Base source roots
                [path.resolve(__dirname, 'core'), path.resolve(__dirname, 'modules')],

                // Override source roots (with filters and extensions)
                [
                    {
                        path: path.resolve(__dirname, 'electron/src/renderer'),
                        filters: ['.shell', '.style', '.abstract'],
                        extensions: ['.tsx', '.ts']
                    }
                ],

                // Overridable directories
                ['components', 'modules'],

                // Excluded directories
                ['node_modules'],

                // Additional dependencies
                {
                    'core': path.resolve(__dirname, 'core'),
                    'modules': path.resolve(__dirname, 'modules')
                },

                // Import guard rules
                [],

                // Enable configuration logging
                true,

                // Debug specific files
                ['MyComponent.shell', 'AnotherFile.tsx']
            )
        ]
    }
}

How It Works

Override Resolution Process

When you import a file from a base source root, OverrideResolver follows this pipeline:

  1. Debug Setup: Checks if the file should be debugged
  2. Additional Dependencies: Resolves custom module path mappings
  3. Import Guard: Validates imports against security rules
  4. Relative Import Check: Only processes relative imports (starting with . or /)
  5. Applicability Check: Verifies the import is not from excluded directories
  6. Override Search: Looks for override files in configured override roots
  7. Resolution: Returns override if found, otherwise uses original file

Path Transformation

The plugin transforms paths by:

  1. Taking the relative path from the base source root
  2. Prepending the override source root
  3. Checking if a file exists at that location

Example:

Original:  modules/Stripe/Component/File.shell.tsx
Override:  electron/src/renderer/Stripe/Component/File.shell.tsx
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                    (relative path from base root)

Priority Order

Override roots are checked in reverse order (last in array = highest priority):

overrideSourceRoots: [
    { path: '/project/override1' },  // Priority 2 (checked second)
    { path: '/project/override2' }   // Priority 1 (checked first)
]

Constructor Parameters

1. baseSourceRoots (required)

Type: string[]

Array of directory paths that contain your original source files.

[
    path.resolve(__dirname, 'core'),
    path.resolve(__dirname, 'modules')
]

2. overrideSourceRoots (required)

Type: Array<string | OverrideRoot>

Array of override source roots. Can be strings or objects with configuration.

[
    {
        path: path.resolve(__dirname, 'electron/src/renderer'),
        filters: ['.shell', '.style', '.abstract'],  // Only override files with these in filename
        extensions: ['.tsx', '.ts']                   // Extensions to check
    }
]

OverrideRoot Object:

  • path: Directory path for overrides
  • filters (optional): Array of strings that must be in the filename
  • extensions (optional): File extensions to check (e.g., ['.tsx', '.ts'])

3. overridableDirectories (optional)

Type: string[]

Directory names that can be overridden. If empty, all directories are overridable.

['components', 'modules', 'routes']

4. excludedRequestDirectories (optional)

Type: string[]

Directories where overrides should NOT be applied.

['node_modules', 'dist']

5. additionalDependencies (optional)

Type: { [key: string]: string }

Maps module names to absolute paths for custom module resolution.

{
    'core': path.resolve(__dirname, 'core'),
    'modules': path.resolve(__dirname, 'modules')
}

6. importGuard (optional)

Type: ImportGuardRule[]

Array of rules to enforce import restrictions.

[
    {
        ward: './src/restrictedFolder',      // Directory to guard
        whitelist: [                          // Allowed imports
            'INTERNAL',                       // Special keyword: allows internal imports
            './src/allowedFolder'
        ]
    }
]

ImportGuardRule:

  • ward: Directory path to protect
  • whitelist: Array of allowed import paths (or 'INTERNAL' for internal imports)

7. logConfig (optional)

Type: boolean (default: false)

Enable startup configuration logging with visual examples.

true  // Shows configuration on webpack startup

Output Example:

═══════════════════════════════════════════════════════
        OverrideResolver Configuration
═══════════════════════════════════════════════════════

Base Source Roots:
  1. /project/core
  2. /project/modules

Override Source Roots (priority order, highest to lowest):
  1. /project/electron/src/renderer [filters: .shell, .style]
      Example:
        Original:  /project/modules/Module/Component/file.shell.tsx
        Override:  /project/electron/src/renderer/Module/Component/file.shell.tsx

8. debugFiles (optional)

Type: string[] (default: [])

Array of filenames to debug. Shows detailed resolution process for matching files.

['StripePayment.shell', 'MyComponent.tsx']

Output Example:

╔════════════════════════════════════════════════════════════════
║ DEBUG: StripePayment.shell
╠════════════════════════════════════════════════════════════════
Request Details:
  request.request: ./StripePayment.shell
  request.path: /project/modules/Stripe
  resolved path: /project/modules/Stripe/StripePayment.shell
  isApplicable: true

Checking Override Roots (reverse order):

  [0] Override Root: /project/electron/src/renderer
      Filters: .shell, .style
      ✓ Filter check passed

      Base Source Root: /project/modules
        ✓ Path is below source root (relative: Stripe/StripePayment.shell)
        Checking override path: /project/electron/src/renderer/Stripe/StripePayment.shell
        Extensions to check: .tsx, .ts
          ✓ /project/electron/src/renderer/Stripe/StripePayment.shell.tsx
          ✗ /project/electron/src/renderer/Stripe/StripePayment.shell.ts

        ✓✓✓ OVERRIDE FOUND! Using: /project/electron/src/renderer/Stripe/StripePayment.shell.tsx
╚════════════════════════════════════════════════════════════════

Usage Examples

Basic Override

Project Structure:

project/
├── modules/
│   └── MyModule/
│       └── Component.tsx          # Original
├── electron/src/renderer/
│   └── MyModule/
│       └── Component.tsx          # Override
└── webpack.config.js

Configuration:

new OverrideResolver(
    [path.resolve(__dirname, 'modules')],
    [{
        path: path.resolve(__dirname, 'electron/src/renderer'),
        extensions: ['.tsx', '.ts']
    }],
    [],
    ['node_modules']
)

Result:

import Component from 'modules/MyModule/Component';
// Resolves to: electron/src/renderer/MyModule/Component.tsx

Multiple Override Roots with Priority

new OverrideResolver(
    [path.resolve(__dirname, 'modules')],
    [
        {
            path: path.resolve(__dirname, 'overrides/base'),
            extensions: ['.tsx', '.ts']
        },
        {
            path: path.resolve(__dirname, 'overrides/custom'),  // Higher priority
            extensions: ['.tsx', '.ts']
        }
    ],
    [],
    ['node_modules']
)

If a file exists in both overrides/custom and overrides/base, the one in overrides/custom will be used.

Filtered Overrides

Only override specific file types:

new OverrideResolver(
    [path.resolve(__dirname, 'modules')],
    [{
        path: path.resolve(__dirname, 'electron/src/renderer'),
        filters: ['.shell', '.style'],  // Only override .shell.tsx and .style.ts files
        extensions: ['.tsx', '.ts']
    }],
    [],
    ['node_modules']
)

Files that will be overridden:

  • Component.shell.tsx
  • Component.style.ts
  • Component.tsx ✗ (no .shell or .style in filename)

Import Guard

Restrict what modules can be imported from specific directories:

new OverrideResolver(
    [path.resolve(__dirname, 'modules')],
    [{ path: path.resolve(__dirname, 'overrides') }],
    [],
    ['node_modules'],
    {},
    [
        {
            ward: path.resolve(__dirname, 'modules/CoreModule'),
            whitelist: [
                'INTERNAL',  // Allow imports within CoreModule
                path.resolve(__dirname, 'modules/SharedUtils')  // Allow imports from SharedUtils
            ]
        }
    ]
)

Allowed:

// In modules/CoreModule/ComponentA.tsx
import ComponentB from './ComponentB';  // ✓ INTERNAL
import { helper } from 'modules/SharedUtils/helper';  // ✓ Whitelisted

Blocked:

// In modules/CoreModule/ComponentA.tsx
import Something from 'modules/OtherModule/Something';  // ✗ Not whitelisted
// Error: A module in a guarded directory attempted an import that could not be matched with the whitelist

Debug Specific Files

Troubleshoot override resolution for specific files:

new OverrideResolver(
    [path.resolve(__dirname, 'modules')],
    [{
        path: path.resolve(__dirname, 'electron/src/renderer'),
        extensions: ['.tsx', '.ts']
    }],
    [],
    ['node_modules'],
    {},
    [],
    false,  // Don't log configuration
    ['MyComponent.shell', 'AnotherComponent.tsx']  // Debug these files
)

This will output detailed resolution information only for files matching MyComponent.shell or AnotherComponent.tsx.

Troubleshooting

Override Not Working?

  1. Enable debug logging for the specific file:

    debugFiles: ['YourFile.shell']
  2. Check the debug output to see:

    • Is the file passing the filter check?
    • Is the path below the source root?
    • Does the override file exist at the expected location?
    • What extensions are being checked?
  3. Verify path structure:

    • Override path = Override Root + Relative Path from Base Root
    • Example: If original is modules/A/B/File.tsx, override should be overrideRoot/A/B/File.tsx (NOT overrideRoot/modules/A/B/File.tsx)
  4. Enable configuration logging to verify your setup:

    logConfig: true

Common Issues

Issue: Override file exists but isn't being used

  • Check: Does the filename match the filter requirements?
  • Check: Is the file extension in the extensions array?
  • Check: Is webpack caching old results? Try deleting the cache directory.

Issue: Import guard errors

  • Check: Are you importing from outside the whitelist?
  • Check: Use 'INTERNAL' in whitelist to allow imports within the same directory

Issue: Relative imports not working

  • Check: Only relative imports (starting with . or /) are processed
  • Check: Library imports (e.g., import React from 'react') are not overridden

Best Practices

  1. Use filters to limit which files can be overridden (improves performance)
  2. Enable configuration logging during development to verify your setup
  3. Use debug files when troubleshooting specific override issues
  4. Organize overrides to mirror the structure of base source roots
  5. Document your override strategy in your project README
  6. Use import guards to enforce architectural boundaries

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.