How to design library the most efficient way?
I have an idea about ideal lib design. But seems to be not easy to achieve it. I want to support standard ES6 module, also other common use cases supported by UMD. BUT there is one more use case I want to support and so there is where the problem begins. I want to be able to switch parts of a library to different implementation.
The library is provided as pure standard ES6 module, without UMD or similar bundler specific wraps.
import MyLib from 'MyLib'
const mylib = new MyLib( {options:true} )
myLib.doSomethingAwesome( element )
The library is provided as UMD module.
const MyLib require( 'MyLib' )
const mylib = new MyLib( {options:true} )
myLib.doSomethingAwesome( element )
or
<script src="mylib.js"></script>
const mylib = new MyLib( {options:true} )
myLib.doSomethingAwesome( element )
The library is provided with switched implementation of its parts.
import MyLib from 'MyLibUnderscore'
const mylib = new MyLib( {options:true} )
myLib.doSomethingAwesome( element )
import MyLib from 'MyLibJQuey'
const mylib = new MyLib( {options:true} )
myLib.doSomethingAwesome( element )
import MyLib from 'MyLibAngular'
...
import MyLib from 'MyLibReact'
...
mylib.js
import MyLib from '@MyLib/core'
import utils from '@MyLib/utils'
import otherPart from '@MyLib/other-part'
MyLib.use( utils ) // utils must be first if you want it to reuse in 'otherPart'
MyLib.use( otherPart )
export default MyLib
mylibUnderscore.js
import MyLib from '@MyLib/core'
import utils from '@MyLib/utilsUnderscore' // underscore implementation of utils
import otherPart from '@MyLib/other-part'
MyLib.use( utils ) // utils must be first if you want it to reuse in 'otherPart'
MyLib.use( otherPart )
export default MyLib
mylibReact.js
import MyLib from '@MyLib/core'
import utils from '@MyLib/utils'
import otherPart from '@MyLib/other-part-react' // react implementation of otherPart
MyLib.use( utils ) // utils must be first if you want it to reuse in 'otherPart'
MyLib.use( otherPart )
export default MyLib
They acts like presets, and you are also able to do custom configuration
mylibCustom.js
import MyLib from '@MyLib/core'
import utils from '@MyLib/utilsJQuery' // jQuery implementation of utils
import otherPart from '@MyLib/other-part-angular' // angular implementation of otherPart
MyLib.use( [utils, otherPart] ) // utils must be first if you want it to reuse in 'otherPart'
export default MyLib
use( plugins ) {
if ( !Array.isArray( plugins ) )
plugins = [ plugins ]
plugins.forEach( plugin => this.using.indexOf( plugin ) > -1 ? 0 : plugin( this ) )
return this; // optional chaining
}
other-part.js
export default function otherPart( core ){
const utils = core.utils
let something = utils.giveMeSomething( 'fromThisString' )
core.anotherMethod = ( element ) => utils.addClass( element, something )
}
Would be nice if we can somehow dynamicaly switch implementation in imports. Imports are nicely declarative, so you see listed dependencies on the top of the file.
other-part-dynamic.js ( imaginary implementation )
import { giveMeSomething, addClass } from '@MyLib/utils' + env.utils_implementation
export default function otherPart( core ){
let something = giveMeSomething( 'fromThisString' )
core.anotherMethod = ( element ) => addClass( element, something )
}