UNPKG

20.3 kBMarkdownView Raw
1# fyn
2
3**A fast node package manager for better productivity and efficiency**
4
5[![NPM version][npm-image]][npm-url]
6[![Apache 2.0 License][apache-2.0-blue-image]][apache-2.0-url]
7[![Build Status][travis-image]][travis-url]
8[![Coverage Status][coveralls-image]][coveralls-url]
9[![Dependency Status][daviddm-image]][daviddm-url] [![devDependency Status][daviddm-dev-image]][daviddm-dev-url]
10
11`fyn` is a super fast node package manager with some unique features:
12
13- enhanced [npm link] with [fynlocal mode](#fynlocal-mode)
14- efficient disk space usage with [central storage](#central-storage)
15- smaller `node_modules` with [guaranteed single copy of a package](#smaller-node_modules)
16- flexible dependencies lock by using a [lock time stamp](#locking-dependencies-by-time)
17- and [more](#features)
18
19![fyn demo][fyn-demo-gif]
20
21## Quick Start
22
23Interested in giving it a quick test? Just install and run it on your project:
24
25```sh
26npm i -g fyn
27cd <your-project>
28fyn
29```
30
31- It can read and use some settings from your `.npmrc`.
32- It can use `npm-shrinkwrap.json` or `package-lock.json` files.
33
34## Table Of Contents
35
36- [fyn](#fyn)
37 - [Quick Start](#quick-start)
38 - [Table Of Contents](#table-of-contents)
39 - [Features](#features)
40 - [Unique](#unique)
41 - [General](#general)
42 - [Overview](#overview)
43 - [Rationale](#rationale)
44 - [Enhanced `npm link`](#enhanced-npm-link)
45 - [`fynlocal` mode](#fynlocal-mode)
46 - [Smaller `node_modules`](#smaller-node_modules)
47 - [Easier Debugging `node_modules`](#easier-debugging-node_modules)
48 - [Using fyn](#using-fyn)
49 - [Installing `fyn`](#installing-fyn)
50 - [Installing Your Dependencies](#installing-your-dependencies)
51 - [Running npm scripts](#running-npm-scripts)
52 - [The `stat` command](#the-stat-command)
53 - [Locking Dependencies by Time](#locking-dependencies-by-time)
54 - [Refreshing Optional Dependencies](#refreshing-optional-dependencies)
55 - [Using with Lerna](#using-with-lerna)
56 - [Configuring fyn](#configuring-fyn)
57 - [Command Line Option to RC Mapping](#command-line-option-to-rc-mapping)
58 - [Other RC Options](#other-rc-options)
59 - [Scope registry](#scope-registry)
60 - [Central Storage](#central-storage)
61 - [Other Info](#other-info)
62 - [Compatibility](#compatibility)
63 - [Package Resolution and Layout](#package-resolution-and-layout)
64 - [Thank you `npm`](#thank-you-npm)
65 - [License](#license)
66
67## Features
68
69### Unique
70
71- Focus on improving workflow and productivity.
72- Very comprehensive and proper handling of `optionalDependencies`.
73- A new `devOptDependencies` allows optional `devDependencies`.
74- [Guaranteed single copy of a package](#flatten-nodemodules) => smaller `node_modules`.
75- The best at installing and linking local packages - better [npm link].
76- Install local packages like they are published (`fynlocal` mode)
77- Works particularly well with [lerna] monorepos.
78- Shows detailed stats of your dependencies.
79- Efficient disk space usage with optional [central storage](#central-storage).
80- Central storage mode is fast (and very fast on Linux) once cache is hot.
81- Install dependencies with a time stamp lock.
82
83### General
84
85- A super fast node package manager for installing modules.
86- Production quality with a lot of unit tests and verified on real applications.
87- 100% compatible with Node.js and its ecosystem.
88- A flat and simple dependency lock file that can be diffed and edited.
89- Always deterministic `node_modules` installation.
90- Compatible with [npm] by internally using the same modules as [npm].
91- Maintains as much of [npm]'s behaviors as possible.
92- Able to use [npm]'s `npm-shrinkwrap.json` or `package-lock.json`.
93
94## Overview
95
96`fyn` is the result of a long pursuit to make developing and managing large and complex software in Node.js easier.
97To realize that, it ultimately ends up being a node package manager.
98
99It started out as small experiments for a single goal of better local package installing and linking, ie: better [npm link], but has gradually grown to a fully functional node package manager for the [flat node_modules design]. It is fast, production quality, and maintains [100% compatibility](#compatibility).
100
101While it has all the bells and whistles to make it an extremely fast and efficient package manager, it's not just another [npm].
102
103It comes with two unique features that are very useful when you are working on a large Node.js application that consists of many packages.
104
105## Rationale
106
107So why would you want to use this?
108
109`fyn`'s `node_modules` structure is the smallest possible in size because there are no multiple copies of the exact same package installed.
110
111It also has a special `fynlocal` mode that's a better [npm link] for handling local packages.
112
113If your development in Node.js are typically simple and involves only a single module or small applications, then `fyn`'s advantage may not be apparent to you, but if your Node.js project is large and complex, then fyn may be helpful to you. Please read further to learn more.
114
115## Enhanced `npm link`
116
117`fyn` has a `fynlocal` mode that's designed specifically to be a much better [npm link]. It treats packages on your local disk like they've been published. You can install and use them directly, and quickly test changes iteratively. It would be very useful if you've ever done any of these:
118
119- Debug your application by inspecting code inside `node_modules`.
120- Live edit your package that's installed to `node_modules`, and then have to copy the changes out to commit.
121- Use [lerna] to maintain and develop multiple packages. `fyn` works particularly well with a [lerna] repo.
122- Or just have to juggle a lot of packages as part of your development.
123
124### `fynlocal` mode
125
126What is this? Think [npm link], but better. `fyn` subjects local packages to the same dependency resolution logic as those from the npm registry. Then you can test changes to any module locally as if they were published.
127
128To enable, use the path to your local modules as semver in your package.json, or you can use the `fyn add` command.
129
130For example:
131
132```sh
133fyn add ../my-awesome-module
134```
135
136That will install `my-awesome-module` into your node_modules. You can continue to develop and test `my-awesome-module` in its own directory and have the changes within existing files reflected in your app directly. Unlike `npm link`, your app resolves dependencies for `my-awesome-module` instead of relying on having them installed under `my-awesome-module/node_modules`.
137
138If you add/remove files/directories in your local package, then running `fyn` install would take only seconds to update.
139
140`fyn` will also save a file `package-fyn.json` with local dependencies in a section called `fyn`. You should not commit this file and `.gitignore` it. `fyn` will automatically check this file when installing, but you can turn off `fynlocal` mode with with the flag `--no-fynlocal` easily.
141
142## Smaller `node_modules`
143
144As a package manager, `fyn` employs a different approach that installs only one copy of every required versions of a package in a flat node_modules structure. Hence the name `fyn`, which stands for Flatten Your Node_modules.
145
146At the top level, it installs a chosen version of each package. All other versions are installed under the directory `node_modules/__fv_/<version>/<package_name>`.
147
148When necessary, packages have their own `node_modules` with symlinks/junctions inside pointing to dependencies under `__fv_`.
149
150This approach has the benefit of guaranteeing a single copy of a package installed and therefore slightly smaller size `node_modules`.
151
152## Easier Debugging `node_modules`
153
154With a guaranteed single copy of a package, it makes debugging easier when you have to reach into code under `node_modules`.
155
156`node_modules` installed by [npm] could potentially have multiple copies of an identical package. So even if you've identified the module under `node_modules` to investigate your issue, you may still need to figure which copy.
157
158With `fyn`'s flat `node_modules` design, there is only one copy of any version so it's easier for you to set your breakpoint.
159
160## Using fyn
161
162### Installing `fyn`
163
164Please install `fyn` to your Node.js setup globally.
165
166```sh
167npm install -g fyn
168```
169
170### Installing Your Dependencies
171
172Change into the directory for your project with the `package.json` file, and run:
173
174```sh
175fyn
176```
177
178- Which is a shorthand for `fyn install` since `install` is the default command.
179
180Depending on the size of your dependencies and your network speed, this could take anywhere from a few seconds to a few minutes.
181
182### Running npm scripts
183
184As a convenience, `fyn` implements `npm run` by utilizing the same modules from [npm]. You can run your [npm scripts] in `package.json`. An alias command `fun` is available also:
185
186- `test` - `fyn test` or `fun test`
187- any script - `fyn run <script-name>` or `fun <script-name>`
188- list scripts - `fyn run -l` or `fun -l`
189
190### The `stat` command
191
192If you have a lockfile, then `fyn` takes sub seconds to regenerate the entire dependency tree even on very large applications. This makes it very fast to probe what's installed.
193
194It has a `stat` command that's very fast and can let you know all copies of a package installed and all others that depend on it.
195
196For example:
197
198```sh
199$ fyn stat chalk
200> loaded lockfile ~/fyn
201> done resolving dependencies 0.113secs
202> chalk matched these installed versions chalk@2.4.1, chalk@1.1.3(fv)
203> chalk@2.4.1 has these dependents eslint@4.19.1, inquirer@3.3.0, table@4.0.2, visual-exec@0.1.0, visual-logger@0.1.8, webpack-bundle-analyzer@2.13.1, xclap@0.2.24, ~package.json
204> chalk@1.1.3 has these dependents babel-code-frame@6.26.0, electrode-server@1.5.1
205```
206
207#### Locking Dependencies by Time
208
209Ever want to install your dependencies only consider packages published up to a certain date in the past? `fyn`'s got you covered with the `--lock-time` option.
210
211- First rename or remove `fyn-lock.yaml` file.
212- Then run install like this:
213
214```sh
215rm fyn-lock.yaml
216fyn install --lock-time "12/01/2018"
217```
218
219Or
220
221```sh
222fyn install --lock-time "dec 01, 2018"
223```
224
225And `fyn` will only consider packages published up to Dec 01, 2018 when installing.
226
227### Refreshing Optional Dependencies
228
229If you have any optional dependencies, then they will not be re-evaluated if you have a lock file.
230
231You can re-evaluate optional dependencies with `--refresh-optionals` option:
232
233```sh
234fyn install --refresh-optionals
235```
236
237#### Using with Lerna
238
239[lerna] actually implements its own internal `npm link` like feature to support a monorepo with packages that depend on each other.
240
241`fyn` works particularly well with a [lerna] monorepo, but since it offers an enhanced `npm link`, it replaces [lerna]'s bootstrap feature.
242
243To bootstrap a [lerna] repo with `fyn`'s enhanced `npm link`, please use the module [fynpo].
244
245`fyn` also has a [central storage](#central-storage) option that would saves you a lot of disk space when working with [lerna] repos.
246
247You can use [fynpo]'s `local` command to update and commit your monorepo's packages' `package.json`, and you can run `fyn` to install and update their dependencies without having to do it through bootstrap.
248
249For example:
250
251```sh
252fynpo local
253cd packages/my-awesome-package
254fyn
255```
256
257## Configuring fyn
258
259fyn options can be listed in help:
260
261```sh
262fyn --help
263```
264
265fyn loads config from `CWD/.fynrc`, `CWD/.npmrc`, `~/.fynrc`, and `~/.npmrc` in this specified order, from highest to lowest priority.
266
267From `.npmrc`, only fields `registry`, `@<scope>:registry`,`email`, and `_auth` are read.
268
269`.fynrc` file can be an [ini] or `YAML` format. For the `YAML` format, the first line must be `---`.
270
271Below is an `YAML` example, with all the options set to their default values:
272
273```yml
274---
275registry: https://registry.npmjs.org
276"@scope:registry": https://registry.custom.com
277offline: false
278forceCache: false
279lockOnly: false
280progress: normal
281logLevel: info
282production: false
283centralStore: false
284```
285
286Or as an ini:
287
288```ini
289registry=https://registry.npmjs.org
290@scope:registry=https://registry.custom.com
291offline=false
292forceCache=false
293lockOnly=false
294progress=normal
295logLevel=info
296production=false
297centralStore=false
298```
299
300### Command Line Option to RC Mapping
301
302> Any command line option can be converted to an option in the RC file by changing the name to camelCase form.
303
304If there's no RC file or command line override, then these defaults are used:
305
306- `registry` - `https://registry.npmjs.org`
307- `progress` - `normal`
308- `logLevel` - `info`
309
310### Other RC Options
311
312#### Scope registry
313
314Scope registry can be specified in the RC files, the same as `.npmrc`.
315
316For example, in Yaml format:
317
318```yml
319---
320"@scope:registry": https://registry.custom.com
321```
322
323In ini format:
324
325```ini
326@scope:registry=https://registry.custom.com
327```
328
329### Central Storage
330
331Inspired by [pnpm], `fyn` supports storing a single copy of all packages at a central location, and use hardlinks to install them into your `node_modules`.
332
333The main advantage of this is to save disk space and slightly faster install if the storage is primed.
334
335However, this feature is not enabled by default due to the following drawbacks:
336
3371. Creating hardlinks actually could take a lot more than trivial time.
338
339 - What this means is the first time you install with `fyn`, when nothing is cached in the storage, central store mode will actually take noticeably more time, but subsequent installs could be faster.
340
341 - In particular, very bad on MacOS (High Sierra). For example, using hardlinks to replicate the module `nyc` actually takes longer than untaring the tgz file. It improves somewhat with concurrency, but still significant.
342
343 - On Linux with ext4 hardlinking appears to be more than 10 times more efficient than MacOS.
344
3452. You can't do your debugging and development by modifying code that's installed into `node_modules` directly.
346
347 - Reason being that any change you make will affect the central copy, and therefore any other `node_modules` that's linked to it.
348
349 - If you do this, then even after you blow away your `node_modules` and reinstall it, your "debugging" changes will be there again.
350
351 - I imagine that this is actually a fairly big drawback for a lot of people.
352
353 - However, the primary design goal of `fyn` is to make your module development easier with its local linking install feature. You should use that to develop and debug multiple modules locally.
354
3553. Similar to 2, but if any package has `postinstall` script that modifies its own files, then those modifications would affect all installations.
356
357 - There should not be a lot of packages like this, but if you happen to use one, it's unlikely a central storage would work.
358
359In general if disk space is not an issue for you, then it's better to avoid this and the issues that will likely creep up on you when you least expect it.
360
361If you do have a use of this feature despite the drawbacks, then you can enable it with the `--central-store` CLI option.
362
363The recommendation is to add the following to `.fynrc` because then you don't have to remember to specify the option in the CLI every time.
364
365```ini
366centralStore=true
367```
368
369You can also set the env variable `FYN_CENTRAL_DIR` to `1` to enable it.
370If you set it to point to a directory then it will be used as the central store directory.
371
372And to work around the issues, `fyn` does the following:
373
374- issue 2: `fyn` has a `--copy` option that allows you to force any package to install with copying instead of hardlinking.
375- issue 3: `fyn` will not hard link packages from central store if they have `preinstall`, `install`, or `postinstall` npm scripts.
376
377## Other Info
378
379### Compatibility
380
381- `fyn`'s top level `node_modules` is 100% compatible with Node.js and 3rd party tools and modules. No special updates or changes needed.
382
383- `fyn` uses npm's [pacote] to do data retrieval. That means its package data handling is the same as npm and it can use npm's cache directly.
384
385- The way `fyn` uses symlinks to resolve nested dependencies is also fully compatible with Node.js. The only caveat is Node.js module loader always resolve a package's path to its real path.
386
387 For example, if `A` depends on `B@1.0.0` that's not at the top level, then `node_modules/A/node_modules/B` is a symlink to `node_modules/B/__fv_/1.0.0/B`.
388
389 Without preserve symlinks, `B`'s path would be resolved to the real path `node_modules/B/__fv_/1.0.0/B`, instead of the symlink path `node_modules/A/node_modules/B`.
390
391 If you want to keep the symlink path, then set the environment variable [NODE_PRESERVE_SYMLINKS] to `1`. It doesn't affect normal operations either way unless you have code that explicitly depend on the path, which should be avoided. The subtle difference is that with preserve symlink, each symlink path of the same module will be loaded as its own instance by Node's module system.
392
393- `fyn` will take [npm]'s `npm-shrinkwrap.json` or `package-lock.json` if its own `fyn-lock.yaml` file doesn't exist, but will save `fyn-lock.yaml` after.
394
395### Package Resolution and Layout
396
397As a package manager, the top level `node_modules` installed by `fyn` is a flat list of all the modules your application needs. It's easier to view and smaller in size. Extra versions of a module will be installed under a directory `__fv_` and linked with symlink or dir junction on Windows.
398
399`fyn` has an asynchronous and concurrent dependency resolution engine that is 100% compatible with node's nesting design, and properly handles `optionalDependencies`.
400
401### Thank you `npm`
402
403Node Package Manager is a very large and complex piece of software. Developing `fyn` was 10 times easier because of the generous open source software from the community, especially the individual packages that are part of `npm`.
404
405Other than benefiting from the massive package ecosystem and all the documents from `npm`, these are the concrete packages from `npm` that `fyn` is using directly.
406
407- [node-tar] - for untaring `tgz` files.
408- [semver] - for handling Semver versions.
409- [pacote] - for retrieving `npm` package data.
410- [ini] - for handling `ini` config files.
411- [npm-packlist] - for filtering files according to npm ignore rules.
412- [npm-lifecycle] - for npm_config env and offering `run` as a convenience.
413- [npmlog] - for offering the `run` command as a convenience.
414- And all the other packages they depend on.
415
416## License
417
418Copyright (c) 2015-present, WalmartLabs
419
420Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0).
421
422[node_options]: https://nodejs.org/dist/latest-v8.x/docs/api/cli.html#cli_node_options_options
423[`-r` option]: https://nodejs.org/docs/latest-v6.x/api/cli.html#cli_r_require_module
424[fyn-demo-gif]: ./images/fyn-demo.gif
425[ini]: https://www.npmjs.com/package/ini
426[node_preserve_symlinks]: https://nodejs.org/docs/latest-v8.x/api/cli.html#cli_node_preserve_symlinks_1
427[require-at]: https://www.npmjs.com/package/require-at
428[travis-image]: https://travis-ci.org/electrode-io/fyn.svg?branch=master
429[travis-url]: https://travis-ci.org/electrode-io/fyn
430[npm-image]: https://badge.fury.io/js/fyn.svg
431[npm-url]: https://npmjs.org/package/fyn
432[coveralls-image]: https://coveralls.io/repos/github/electrode-io/fyn/badge.svg?branch=master
433[coveralls-url]: https://coveralls.io/github/electrode-io/fyn?branch=master
434[daviddm-image]: https://david-dm.org/electrode-io/fyn/status.svg
435[daviddm-url]: https://david-dm.org/electrode-io/fyn
436[daviddm-dev-image]: https://david-dm.org/electrode-io/fyn/dev-status.svg
437[daviddm-dev-url]: https://david-dm.org/electrode-io/fyn?type=dev
438[apache-2.0-blue-image]: https://img.shields.io/badge/License-Apache%202.0-blue.svg
439[apache-2.0-url]: https://www.apache.org/licenses/LICENSE-2.0
440[npm scripts]: https://docs.npmjs.com/misc/scripts
441[node-tar]: https://www.npmjs.com/package/tar
442[semver]: https://www.npmjs.com/package/semver
443[pacote]: https://www.npmjs.com/package/pacote
444[ini]: https://www.npmjs.com/package/ini
445[npm-packlist]: https://www.npmjs.com/package/npm-packlist
446[pnpm]: https://www.npmjs.com/package/pnpm
447[npm]: https://www.npmjs.com/package/npm
448[lerna]: https://www.npmjs.com/package/lerna
449[fynpo]: https://www.npmjs.com/package/fynpo
450[npm link]: https://docs.npmjs.com/cli/link.html
451[npm-lifecycle]: https://www.npmjs.com/package/npm-lifecycle
452[npmlog]: https://www.npmjs.com/package/npmlog