Repo guidance: Use async import stubs
When dynamically importing code from another package, don't directly import it from your app code.
ts
// App.ts (don't do either of these)
const { other } = await import('other-package')
const { thing } = await import('other-package/lib/file')Problems:
- No tree shaking, since you're importing the entire entry point as an object and destructuring it at runtime. This is especially bad when importing the whole package (
import('other-package')), since any unused exports or future additions will bloat your bundle size. - A deep import (that isn't listed in the exports map) like
import('other-package/lib/file')is not a good workaround due to the general problems with deep imports.
Recommended pattern: local stub re-export
Create a local stub file which re-exports only the symbols you need from the dependency, and dynamically import that:
ts
// MyPackageThingLazy.ts
export { thing } from 'other-package'
// App.ts
const { thing } = await import('./MyPackageThingLazy')Benefits:
- Your async boundary contains only the needed exports.
- You control its dependencies explicitly; future additions to
other-packagedo not bloat this chunk. - Easier to refactor if the dependency changes layout.
Tips
- Co-locate stubs near primary usage for discoverability.
- If multiple lazy imports pull the same symbols, consolidate them into one stub to maximize caching.