Reputation: 781
I have been trying to build a library that requires its consumers to use a specific strategy per target. My current architecture follows:
[Application] -> contains -> [player] -> contains -> [renderer]
Currently, Renderer
is an interface which needs to be replaced for different platforms:
I have the freedom to use any bundlers - currently using Webpack for the app and Rollup for the lib - and what I could achieve follows:
My lib exports a Player
interface and a createPlayer
function which returns a PlayerInterface
. Then, on the application side I have a Webpack alias that resolves the correct platform library based on a build input.
e.g:
import { createPlayer } from "my-lib";
const player = createPlayer()
Then we build the application with
npm run build --platform=web
to which webpack will transform the my-lib
import into my-lib/platforms/web
, which also contains an exported createPlayer
function which uses the correct renderer.
My question is the, from the application's point of view, how can we make sure that we import the correct renderer per platform on build time while allowing tree-shaking (so only including the correct sources)? I find that using the build system to do that is quite obscure, as it doesn't leave a clear trace of what's going on.
Is there a better way of doing this?
Best,
Upvotes: 1
Views: 326
Reputation: 13709
You have a couple options. I'd recommend against having a compile-time switch, since that requires you to distribute multiple copies of your library (which isn't idiomatic). However, if you really wanted to do this, I'd suggest using webpack's ProvidePlugin
or resolve.alias
config field to dynamically link your code to the appropriate renderer at build time.
A more pragmatic approach, in my opinion, would be to have two entry points to your application, and allow the implementor to choose which entry point to use. This is similar to how react-dom
switches between browser rendering and server rendering (i.e., react-dom
versus react-dom/server
):
// index.js
export * from './shared';
export {default as renderer} from './renderers/web';
// mobile/index.js
export * from '../shared';
export {default as renderer} from '../renderers/mobile';
Then, someone using your library could import {renderer, foo} from 'your-lib'
or import {renderer, foo} from 'your-lib/mobile'
.
Both of the above approaches work at build time.
While the latter approach normally forces you to choose which version of the library to use in your code, you can use webpack's resolve.alias
configuration field to force imports to your-lib
be redirected to your-lib/mobile
.
Upvotes: 3