teambit.bit/dependency-resolver
This extension is responsible for:
- detecting dependencies of components by static code analysis
- apply dependencies polices
- resolve dependencies versions
- calculate the final dependencies of a given component
Usage
workspace config
The extension's workspace configuration will have the following fields:
- policy
- packageManager
- strictPeerDependencies
- packageManagerArgs
Here is a full example of workspace config:
(For complete reference see DependencyResolverWorkspaceConfig type)
"teambit.bit/dependency-resolver": {
"policy" : {
"dependencies": {
"lodash": "1.2.3",
"teambit.bit/my-awesome-component": "1.1.1"
},
"peerDependencies": {
"react": ">15.0.1"
},
}
"packageManager": "pnpm",
"strictPeerDependencies": true,
"packageManagerArgs": []
}
variant config
The component configuration of the dependency resolver will store dependencies policy for the component.
This is similar to what used to be under the overrides.dependencies
in the old workspace config.
The component configuration will support "-"
sign as a value for dependency which means to remove it from the final dependency list.
The component configuration will support syntax to remove all dependencies (by type) in case the user wants full control. (syntax is open for discussion)
for example:
"dependencies": {
"*": "-",
"teambit.bit/my-awesome-component": "5.5.5"
},
}
for example, consider the following config (co-exist in the same workspace with the workspace configuration described above):
"teambit.bit/variants": {
"new-ui/*": {
"teambit.bit/dependency-resolver": {
"dependencies": {
"lodash": "-",
"teambit.bit/my-awesome-component": {
"version": "5.5.5",
"force": false,
},
"teambit.bit/some-other-package": {
"version": "5.5.5",
"force": true,
}
},
"peerDependencies": {
"react": ">16.0.1"
}
}
}
}
This tells the dependency-resolver that for all components under new-ui/*
- remove the loadash dependency.
- use version 5.5.5 of teambit.bit/my-awesome-component instead of 1.1.1 (for any component that require it)
- add "teambit.bit/some-other-package" to all component matching
new-ui/*
variant - use version 16.0.1 as peer instead of 15.0.1
commands
install
This extension will expose a bit install
command.
when running bit install
it will:
- Install the dependency on the workspace or the relevant component's capsules. (write them to the fs)
- Add a rule to the workspace / matching variant policy
examples:
When running bit install lodash 1.2.3
this will add the lodash: 1.2.3
into the workspace dependency policy configuration (proper flags for dev / peer will exist as well)
When running bit install lodash 4.5.6 [component id glob pattern]
(exact syntax will be determined as part of the install extension). it will add the lodash: 4.5.6
into the matching glob pattern (created if not exist), in the variants, under the dependency-resolver policy config.
(or in the matching components.json if exists)
Rational
Extended description, preferably with a specific use case where this extension is required to solve a real-world problem.
API Usage
Here we should explain (and demonstrate) how to use this extension programmatically.
It mainly need to serve other people who want to build extension that consume this extension.
Sections to consider here:
- Types - stuff that are not described by the type itself, like special fields, rational and meta-docs
- Methods - mainly example of how to use the methods, or general info about them. the signature and stuff like this should be covered by the code itself. do not write it here again to prevent the need to maintain both places.
- Hooks - same as methods, mainly about how to use them and examples, rather than stuff described by the code itself.
hooks
policy changes
The dependency resolver will provide a hook called @dependncies (name is open - see open question below) to enable 3rd party extension to add dependencies for a component.
here is an example:
import { Extension } from 'teambit.bit/bit';
import { DependencyResolver, Dependencies } from 'teambit.bit/dependency-resolver';
@Extension()
export class MyExtension {
constructor() {}
@Dependencies
addDependencies() {
return {
"dependencies": {
"underscore": "1.1.1"
},
"devDependencies": {
"types/underscore": "1.1.1"
}
}
}
}
file dependencies definitions - TBD
The dependency resolver will provide a hook called @FileDependencies (name is open - see open question below) to enable 3rd party extension analyze a file and return a list of dependencies from it.
here is an example:
import type {SomeType} from 'my-package';
import default from 'my-component';
console.log('do something');
import { Extension } from 'teambit.bit/bit';
import { DependencyResolver, FileDependencies } from 'teambit.bit/dependency-resolver';
@Extension()
export class MyExtension {
constructor() {}
getDepsForFile(filePath: string, fs: FS): FileDependenciesDefinition {
return [
{
dependencyPath: "my-package",
isType: true;
},
{
dependencyPath: "my-component"
}
]
}
}
Documentation
saved data
The dependency-resolver extension will store in its data (part of the component model), the final dependencies after all the calculations, and also the dependencies calculated by the workspace configuration (and require detection) - without putting the component config rules and dependencies added by extensions (via the hooks)
(see calculation flow below)
calculation flow
The dependency calculation will be triggered by external player (probably the workspace / scope extensions)
This player will pass to the dependency resolver
- "raw component" (exact type tbd), this will have in general the component files, the component config, and the component extensions at least.
- workspace config for the resolver (optional) - should be discussed, see the open question below
dependencies by code analysis (import / require detection)
The dependency resolver will start by analyzing the imports / require statements of the source code and intersect them with the dependencies from the workspace configuration -
If it detects for example a require('lodash');
it will search for lodash in the config. (if not found it will throw an error that the dependency is missing so it can't resolve its version)
(This part must be extendable by third part extensions, exact syntax TBD - see open question)
add the extensions themselves as dependencies
If a component has extension defined for it, this extension should be considered as a dev dependency.
dependencies added by extensions
An extension might provide more dependencies / remove dependencies (uses the hook - see API below).
The dependency resolver will take this dependencies configuration added by all the hook subscribers and merge them with themselves (2 extensions for the same component might add the same dependency in a different version) - exact strategy to be defined - see open question
Then it will merge the final result with the result of the previous steps (dependencies configured here are stronger than those from the code analysis)
dependencies added by component config
The dependency resolver will read special rules configured in the component config and will merge them into the previous results.
Since these rules added explicitly by the user, they are the strongest ones.
open issues
- names of the workspace configuration fields
- exact policy structure
- hooks syntax
- type that the calculation gets as input (the "raw component")
- how we extend the import / require analysis to enable 3rd party extension to extend it?
- What is the strategy to merge dependencies added by hooks between themselves (random / load order / alphabetically?)
- More methods that should be exposed via the API
- FileDependencies hook name