UNPKG

6.19 kBMarkdownView Raw
1# Node File Trace
2
3[![CI Status](https://badgen.net/github/checks/vercel/node-file-trace?label=CI)](https://github.com/vercel/node-file-trace/actions?workflow=CI)
4[![Code Coverage](https://badgen.net/codecov/c/github/vercel/node-file-trace)](https://codecov.io/gh/vercel/node-file-trace)
5
6This package is used in [@vercel/node](https://npmjs.com/package/@vercel/node) and [@vercel/next](https://npmjs.com/package/@vercel/next) to determine exactly which files (including `node_modules`) are necessary for the application runtime.
7
8This is similar to [@zeit/ncc](https://npmjs.com/package/@zeit/ncc) except there is no bundling performed and therefore no reliance on webpack. This achieves the same tree-shaking benefits without moving any assets or binaries.
9
10## Usage
11
12### Installation
13```bash
14npm i @zeit/node-file-trace
15```
16
17### Usage
18
19Provide the list of source files as input:
20
21```js
22const nodeFileTrace = require('@zeit/node-file-trace');
23const files = ['./src/main.js', './src/second.js'];
24const { fileList } = await nodeFileTrace(files);
25```
26
27The list of files will include all `node_modules` modules and assets that may be needed by the application code.
28
29### Options
30
31#### Base
32
33The base path for the file list - all files will be provided as relative to this base.
34
35By default the `process.cwd()` is used:
36
37```js
38const { fileList } = await nodeFileTrace(files, {
39 base: process.cwd()
40}
41```
42
43Any files/folders above the `base` are ignored in the listing and analysis.
44
45#### Process Cwd
46
47When applying analysis certain functions rely on the `process.cwd()` value, such as `path.resolve('./relative')` or even a direct `process.cwd()`
48invocation.
49
50Setting the `processCwd` option allows this analysis to be guided to the right path to ensure that assets are correctly detected.
51
52```js
53const { fileList } = await nodeFileTrace(files, {
54 processCwd: path.resolve(__dirname)
55}
56```
57
58By default `processCwd` is the same as `base`.
59
60#### Exports
61
62By default tracing of the [Node.js "exports" field](https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_package_entry_points) is supported, with the `"node"`, `"require"`, `"import"` and `"default"` conditions traced as defined.
63
64Alternatively the explicit list of exports can be provided:
65
66```js
67const { fileList } = await nodeFileTrace(files, {
68 exports: ['node', 'production']
69});
70```
71
72Only the `"node"` export should be explicitly included (if needed) when specifying the exact export condition list. The `"require"`, `"import"` and `"default"` conditions will always be traced as defined, no matter what custom conditions are set.
73
74#### Exports Only
75
76When tracing exports the `"main"` / index field will still be traced for Node.js versions without `"exports"` support.
77
78This can be disabled with the `exportsOnly` option:
79
80```js
81const { fileList } = await nodeFileTrace(files, {
82 exportsOnly: true
83});
84```
85
86Any package with `"exports"` will then only have its exports traced, and the main will not be included at all. This can reduce the output size when targeting [Node.js 12.17.0)(https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V12.md#12.17.0) or newer.
87
88#### Paths
89
90> Status: Experimental. May change at any time.
91
92Custom resolution path definitions to use.
93
94```js
95const { fileList } = await nodeFileTrace(files, {
96 paths: {
97 'utils/': '/path/to/utils/'
98 }
99});
100```
101
102Trailing slashes map directories, exact paths map exact only.
103
104#### Hooks
105
106The following FS functions can be hooked by passing them as options:
107
108* `readFile(path): Promise<string>`
109* `stat(path): Promise<FS.Stats>`
110* `readlink(path): Promise<string>`
111
112#### TypeScript
113
114The internal resolution supports resolving `.ts` files in traces by default.
115
116By its nature of integrating into existing build systems, the TypeScript
117compiler is not included in this project - rather the TypeScript transform
118layer requires separate integration into the `readFile` hook.
119
120#### Analysis
121
122Analysis options allow customizing how much analysis should be performed to exactly work out the dependency list.
123
124By default as much analysis as possible is done to ensure no possibly needed files are left out of the trace.
125
126To disable all analysis, set `analysis: false`. Alternatively, individual analysis options can be customized via:
127
128```js
129const { fileList } = await nodeFileTrace(files, {
130 // default
131 analysis: {
132 // whether to glob any analysis like __dirname + '/dir/' or require('x/' + y)
133 // that might output any file in a directory
134 emitGlobs: true,
135 // whether __filename and __dirname style
136 // expressions should be analyzed as file references
137 computeFileReferences: true,
138 // evaluate known bindings to assist with glob and file reference analysis
139 evaluatePureExpressions: true,
140 }
141});
142```
143
144#### Ignore
145
146Custom ignores can be provided to skip file inclusion (and consequently analysis of the file for references in turn as well).
147
148```js
149const { fileList } = await nodeFileTrace(files, {
150 ignore: ['./node_modules/pkg/file.js']
151});
152```
153
154Ignore will also accept a function or globs.
155
156Note that the path provided to ignore is relative to `base`.
157
158#### Cache
159
160To persist the file cache between builds, pass an empty `cache` object:
161
162```js
163const cache = Object.create(null);
164const { fileList } = await nodeFileTrace(['index.ts'], { cache });
165// later:
166{
167 const { fileList } = await nodeFileTrace(['index.ts'], { cache });
168}
169```
170
171Note that cache invalidations are not supported so the assumption is that the file system is not changed between runs.
172
173#### Reasons
174
175To get the underlying reasons for individual files being included, a `reasons` object is also provided by the output:
176
177```js
178const { fileList, reasons } = await nodeFileTrace(files);
179```
180
181The `reasons` output will then be an object of the following form:
182
183```js
184{
185 [file: string]: {
186 type: 'dependency' | 'asset' | 'sharedlib',
187 ignored: true | false,
188 parents: string[]
189 }
190}
191```
192
193`reasons` also includes files that were ignored as `ignored: true`, with their `ignoreReason`.
194
195Every file is included because it is referenced by another file. The `parents` list will contain the list of all files that caused this file to be included.