Using scoped packages with jspm install
jspm install
Section titled “jspm install”jspm install is a fast package manager & npm client.
jspm install can be configured via bunfig.toml, environment variables, and CLI flags.
Configuring jspm install with bunfig.toml
Section titled “Configuring jspm install with bunfig.toml”bunfig.toml is searched for in the following paths on jspm install, jspm remove, and jspm add:
$XDG_CONFIG_HOME/.bunfig.tomlor$HOME/.bunfig.toml./bunfig.toml
If both are found, the results are merged together.
Configuring with bunfig.toml is optional. JSTime tries to be zero configuration in general, but that’s not always possible.
# Using scoped packages with jspm install[install.scopes]
# Scope name The value can be a URL string or an object"@mybigcompany" = { token = "123456", url = "https://registry.mybigcompany.com" }# URL is optional and fallsback to the default registry
# The "@" in the scope is optionalmybigcompany2 = { token = "123456" }
# Environment variables can be referenced as a string that starts with $ and it will be replacedmybigcompany3 = { token = "$npm_config_token" }
# Setting username and password turns it into a Basic Auth header by taking base64("username:password")mybigcompany4 = { username = "myusername", password = "$npm_config_password", url = "https://registry.yarnpkg.com/" }# You can set username and password in the registry URL. This is the same as above.mybigcompany5 = "https://username:password@registry.yarnpkg.com/"
# You can set a token for a registry URL:mybigcompany6 = "https://:$NPM_CONFIG_TOKEN@registry.yarnpkg.com/"
[install]# Default registry# can be a URL string or an objectregistry = "https://registry.yarnpkg.com/"# as an object#registry = { url = "https://registry.yarnpkg.com/", token = "123456" }
# Install for production? This is the equivalent to the "--production" CLI argumentproduction = false
# Disallow changes to lockfile? This is the equivalent to the "--fozen-lockfile" CLI argumentfrozenLockfile = false
# Don't actually installdryRun = true
# Install optionalDependencies (default: true)optional = true
# Install local devDependencies (default: true)dev = true
# Install peerDependencies (default: false)peer = false
# When using `jspm install -g`, install packages hereglobalDir = "~/.jstime/install/global"
# When using `jspm install -g`, link package bins hereglobalBinDir = "~/.jstime/bin"
# cache-related configuration[install.cache]# The directory to use for the cachedir = "~/.jstime/install/cache"
# Don't load from the global cache.# Note: JSTime may still write to node_modules/.cachedisable = false
# Always resolve the latest versions from the registrydisableManifest = false
# Lockfile-related configuration[install.lockfile]
# Print a yarn v1 lockfile# Note: it does not load the lockfile, it just converts jspm.lockb into a yarn.lockprint = "yarn"
# Path to read jspm.lockb frompath = "jspm.lockb"
# Path to save jspm.lockb tosavePath = "jspm.lockb"
# Save the lockfile to disksave = trueIf it’s easier to read as TypeScript types:
export interface Root { install: Install;}
export interface Install { scopes: Scopes; registry: Registry; production: boolean; frozenLockfile: boolean; dryRun: boolean; optional: boolean; dev: boolean; peer: boolean; globalDir: string; globalBinDir: string; cache: Cache; lockfile: Lockfile; logLevel: "debug" | "error" | "warn";}
type Registry = | string | { url?: string; token?: string; username?: string; password?: string; };
type Scopes = Record<string, Registry>;
export interface Cache { dir: string; disable: boolean; disableManifest: boolean;}
export interface Lockfile { print?: "yarn"; path: string; savePath: string; save: boolean;}Configuring with environment variables
Section titled “Configuring with environment variables”Environment variables have a higher priority than bunfig.toml.
| Name | Description |
| -------------------------------- | ------------------------------------------------------------- |
| JSTIME_CONFIG_REGISTRY | Set an npm registry (default: ) |
| JSTIME_CONFIG_TOKEN | Set an auth token (currently does nothing) |
| JSTIME_CONFIG_LOCKFILE_SAVE_PATH | File path to save the lockfile to (default: jspm.lockb) |
| JSTIME_CONFIG_YARN_LOCKFILE | Save a Yarn v1-style yarn.lock |
| JSTIME_CONFIG_LINK_NATIVE_BINS | Point bin in package.json to a platform-specific dependency |
| JSTIME_CONFIG_SKIP_SAVE_LOCKFILE | Don’t save a lockfile |
| JSTIME_CONFIG_SKIP_LOAD_LOCKFILE | Don’t load a lockfile |
| JSTIME_CONFIG_SKIP_INSTALL_PACKAGES | Don’t install any packages |
JSTime always tries to use the fastest available installation method for the target platform. On macOS, that’s clonefile and on Linux, that’s hardlink. You can change which installation method is used with the --backend flag. When unavailable or on error, clonefile and hardlink fallsback to a platform-specific implementation of copying files.
JSTime stores installed packages from npm in ~/.jstime/install/cache/${name}@${version}. Note that if the semver version has a build or a pre tag, it is replaced with a hash of that value instead. This is to reduce the chances of errors from long file paths, but unfortunately complicates figuring out where a package was installed on disk.
When the node_modules folder exists, before installing, JSTime checks if the "name" and "version" in package/package.json in the expected node_modules folder matches the expected name and version. This is how it determines whether it should install. It uses a custom JSON parser which stops parsing as soon as it finds "name" and "version".
When a jspm.lockb doesn’t exist or package.json has changed dependencies, tarballs are downloaded & extracted eagerly while resolving.
When a jspm.lockb exists and package.json hasn’t changed, JSTime downloads missing dependencies lazily. If the package with a matching name & version already exists in the expected location within node_modules, JSTime won’t attempt to download the tarball.
Platform-specific dependencies?
Section titled “Platform-specific dependencies?”jstime stores normalized cpu and os values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won’t change between platforms/architectures even if the packages ultimately installed do change.
Peer dependencies?
Section titled “Peer dependencies?”Peer dependencies are handled similarly to yarn. jspm install does not automatically install peer dependencies and will try to choose an existing dependency.
Lockfile
Section titled “Lockfile”jspm.lockb is JSTime’s binary lockfile format.
Why is it binary?
Section titled “Why is it binary?”In a word: Performance. JSTime’s lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles.
How do I inspect it?
Section titled “How do I inspect it?”For now, the easiest thing is to run jspm install -y. That prints a Yarn v1-style yarn.lock file.
What does the lockfile store?
Section titled “What does the lockfile store?”Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to and which version (or equivalent).
Why is it fast?
Section titled “Why is it fast?”It uses linear arrays for all data. Packages are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order.
To delete the cache:
$ rm -rf ~/.jstime/install/cachePlatform-specific backends
Section titled “Platform-specific backends”jspm install uses different system calls to install dependencies depending on the platform. This is a performance optimization. You can force a specific backend with the --backend flag.
hardlink is the default backend on Linux. Benchmarking showed it to be the fastest on Linux.
$ rm -rf node_modules$ jspm install --backend hardlinkclonefile is the default backend on macOS. Benchmarking showed it to be the fastest on macOS. It is only available on macOS.
$ rm -rf node_modules$ jspm install --backend clonefileclonefile_each_dir is similar to clonefile, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than clonefile. Unlike clonefile, this does not recursively clone subdirectories in one system call.
$ rm -rf node_modules$ jspm install --backend clonefile_each_dircopyfile is the fallback used when any of the above fail, and is the slowest. on macOS, it uses fcopyfile() and on linux it uses copy_file_range().
$ rm -rf node_modules$ jspm install --backend copyfilesymlink is typically only used for file: dependencies (and eventually link:) internally. To prevent infinite loops, it skips symlinking the node_modules folder.
If you install with --backend=symlink, Node.js won’t resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass --preserve-symlinks to node. See Node.js documentation on --preserve-symlinks.
$ rm -rf node_modules$ jspm install --backend symlink$ node --preserve-symlinks ./my-file.js # https://nodejs.org/api/cli.html#--preserve-symlinksJSTime’s runtime does not currently expose an equivalent of --preserve-symlinks, though the code for it does exist.
npm registry metadata
Section titled “npm registry metadata”jstime uses a binary format for caching NPM registry responses. This loads much faster than JSON and tends to be smaller on disk.
You will see these files in ~/.jstime/install/cache/*.npm. The filename pattern is ${hash(packageName)}.npm. It’s a hash so that extra directories don’t need to be created for scoped packages.
JSTime’s usage of Cache-Control ignores Age. This improves performance, but means jstime may be about 5 minutes out of date to receive the latest package version metadata from npm.