简体   繁体   中英

Best practices for extendable and modifiable node (npm) modules

I need advice from the more experienced javascript(typescript) / nodejs developers. For a few months a I'm trying to find best practice for making extendable and modifiable node (npm) modules.

For better understanding: In most of PHP frameworks (like as Symfony, Laravel, Nette) we have DI container which can be used for changing or adding own implementation for services coming from packages. For example. I have a cart package which implements service for calculating cart price and apply taxes. When i need to change taxes calculation I can change implementation over DI container like as

services:
      myTaxCalculator:
    class: MyTaxCalculator
      Package\Taxes\CalculatorInterface: ‘@myTaxCalculator’

and now when package work with Package\\Taxes\\CalculatorInterface use my own calculator instead of default implementation.

And I looking for something like this in javascript(typescript)/nodejs. If I build any package and in package I need function for calculate taxes use this const taxCalculator = require('...') but now I can't change implementation of this function.

Of course I can make package configurable. Add some mechanism for set a custom function for specific cases but I think that I need this logic for all classes / function which is used in application to never have to call require('something').

The point is build basic and standard package with default logic which can be in concrete application modify to solve customer problems without writing a new package with 90% same code. I know that exists some IoC/DI implementation for javascript(typescript) / nodejs like as InversifyJS but I'm not sure when is a best way for javascript(typescript) / nodejs applications. Do you have any experiences with this? How do you solve these problems?

Thanks for any response!

I wouldn't say I'm an expert or "best practices guru", but I think three scenarios are pretty common. I won't dig into Inversify because you're already aware of it.

  1. Take an object with config at the entry point class/function. Default to your implementation.
interface TaxCalculator { /* tax related stuff */ }

interface CalculateCartPriceArgs {
  taxCalculator: TaxCalculator,
  // probably lots of other stuff
}

export function calculateCartPrice({
  taxCalculator = defaultTaxCalculator
}: CalculateCartPriceArgs) {
  // implementation
}
  1. Plugins / middleware.
  2. Expose internals to allow the user to build his own version of your thing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM