Install dependencies
jko
allows you to install dependencies
and devDependencies
.
$ jko install
It will install dependencies from jko.js
or package.json
.
jko.js
takes precedence over package.json
.
Install dependencies from a File
$ jko install --config-file=./path/to/config.js
or
$ jko install -c=./path/to/config.js
Install dependencies from a Package
$ jko install --config-file=somePackageName
or
$ jko install -c=somePackageName
The package must be available, i.e. It must be installed first.
Using a Specific Package Manager to Install Dependencies
jko
supports the following package managers:
- npm (Default)
- pnpm
- yarn
$ jko install --package-manager=npm
or
$ jko install --p=npm
or by using the jko.js
file (package.json
or any other file specified with the --config-file
option):
export default {
dependencies: {
packageName1: "#.#.#",
packageNameN: "#.#.#"
},
devDependencies: {
devPackageName1: "#.#.#",
devPackageNameN: "#.#.#"
},
packageManager: 'npm',
}
$ jko install
How Are Dependencies Installed
- Before installation begins,
$pre (install)
is run if it exists. - Dependencies are installed as follows:
-
Using a non-package.json file (e.g.
jko.js
): Each dependency is processed independently using the selected package manager command. For example:npm install some0@"4.0.0" && npm install -D some1@"5.0.0" some2@"6.0.0"
pnpm add some1@"5.0.0" some2@"6.0.0"
Additionally, if a
package.json
file does not exist, it will be created; otherwise, it will be updated. -
Using
package.json
for installation: All dependencies are processed at once (e.g. by runningnpm install
oryarn install
).
- If everything completes successfully,
$post (install)
is run if it exists. If an error occurs,$catch (install)
is run if defined.
When installing from a non-package.json file, the packageManager
doesn't "lock" its version to a fixed package in your lock file.
Instead, it treats the package as a new dependency and updates the lock file accordingly.
What happens is:
- The
packageManager
determines which version of the package to install based on the semver range (defaulting to the latest version if none is provided). - It downloads that version and either adds a new entry or updates the existing one in
package.json
. - It deletes any packages that have been removed from
package.json
. - It updates or creates
package-lock.json
with the resolved version.
In this process, the package-lock file isn't "enforcing" a previously locked version for the dependency—It is just updated with the new resolution if any changes occur.
While this approach is often beneficial, it also means you need to manage your semver ranges carefully. For instance, to pin a version, use some@">=1.50.0 && <1.51.0"
. This guarantees that only version 1.50.x
will be installed (with x
representing bug fixes), which can be advantageous.
If an install
task already exists, jko
completely ignores it.
How Dependencies Are Deleted
There are two scenarios to consider:
- Managing dependencies solely via
package.json
. - Using a custom configuration file, e.g.
jko.js
.
Using only package.json
By relying exclusively on package.json as the single source of truth for dependencies, you lose the ability to import shared dependencies definition.
When you remove a dependency from package.json
and run jko install
, the specified dependency is removed as expected.
Using a custom configuration file
When dependencies are defined in both package.json
and a shared configuration file, e.g. jko.js
, you have multiple sources of truth.
Consequently, removing a dependency requires updating both locations:
- Remove the dependency from
package.json
. - Remove the dependency from the shared configuration file, e.g.
jko.js
.
This occurs because when you define shared dependencies in a file like jko.js
, running jko install
will always update package.json
via the package manager behind the scenes, resulting in at least two sources of truth.
Example:
jko.js
export default {
dependencies: {
packageName1: "#.#.#",
packageNameN: "#.#.#"
},
devDependencies: {
devPackageName1: "#.#.#",
devPackageNameN: "#.#.#"
},
packageManager: 'npm',
}
When you run jko install
, the package.json
file is updated to:
{
"dependencies": {
"packageName1": "#.#.#",
"packageNameN": "#.#.#"
},
"devDependencies": {
"devPackageName1": "#.#.#",
"devPackageNameN": "#.#.#"
},
}
To remove "packageName1": "#.#.#"
, delete it from both jko.js
and package.json
:
jko.js
export default {
dependencies: {
packageNameN: "#.#.#"
},
devDependencies: {
devPackageName1: "#.#.#",
devPackageNameN: "#.#.#"
},
packageManager: 'npm',
}
package.json
:
{
"dependencies": {
"packageNameN": "#.#.#"
},
"devDependencies": {
"devPackageName1": "#.#.#",
"devPackageNameN": "#.#.#"
},
}
Then, you can run jko install
.
If a dependency is defined in multiple files, it must be removed from each one to ensure it’s completely deleted. For example:
jko.js
import dependencies1 from 'somePackage'
import dependencies2 from './moreDependencies.js'
export default {
dependencies: {
...dependencies1
...dependencies2
}
}
Then remove the package from both dependencies1
and dependencies2
before running jko install
, or remove it prior to exporting:
jko.js
import dependencies1 from 'somePackage'
import dependencies2 from './moreDependencies.js'
const dependencies = {
...dependencies1
...dependencies2
}
delete dependencies."some package"
export default {
dependencies
}
Mixing jko.js
and JSON
If you want to use jko.js
and store dependencies in a JSON file (e.g., package.json
), import JSON file into jko.js
:
jko.js
import scripts from 'somePackage'
import packageJson from './package.json' with { type: 'json' }
export default {
...packageJson,
scripts: {
...scripts.scripts,
yourScript1: "someCommand1",
yourScript2: "someCommand2",
}
}
This is especially useful when using shared scripts from a local package.