What You Need to Know About NPM
npm vs pnpm
What are Ghost Dependencies?
Ghost Dependencies are dependencies that are used in the project but not explicitly declared in package.json. This situation often occurs with npm and Yarn because their flattened dependency structure allows access to packages that are not directly declared.
Example
Suppose your project has a direct dependency on express:
{
"dependencies": {
"express": "4.17.1"
}
}
express depends on body-parser, so body-parser will also be installed in node_modules.
In your code, you can use body-parser directly, even though it’s not declared in package.json:
const bodyParser = require('body-parser');
This code will run, but body-parser is actually a ghost dependency.
Problems
Reliability Issues
Ifexpressno longer depends onbody-parserin the future, your code might suddenly break.Version Inconsistency
Different developers might install different versions of dependencies, leading to inconsistent project behavior.Maintenance Difficulty
Ghost dependencies make the project’s dependency relationships ambiguous, increasing maintenance costs.
Problems Solved by pnpm
pnpm addresses many issues found in traditional package managers (like npm and Yarn), including the problem of ghost dependencies, through its strict dependency tree structure and optimized storage mechanism.
1. Disk Space Efficiency
- Feature: pnpm uses hard links and symbolic links to share packages, avoiding duplicate installations of the same package.
- Problem Solved: Reduces disk space usage, which is especially significant in large projects.
2. Installation Speed
- Feature: pnpm is generally faster than npm, particularly when installing dependencies for large projects.
- Problem Solved: Speeds up the initial project setup and dependency update process, improving development efficiency.
3. Dependency Management
- Feature: pnpm uses a strict dependency tree structure, only allowing access to explicitly declared dependencies.
- Problem Solved: Eliminates the “ghost dependency” problem, enhancing project reliability and maintainability.
4. Single Store
- Feature: pnpm maintains a centralized package store (global store) on the system, and all projects share these packages.
- Problem Solved: Further saves disk space and speeds up package installation across multiple projects.
5. Parallel Installation
- Feature: pnpm installs packages in parallel by default, making full use of multi-core CPU performance.
- Problem Solved: Reduces dependency installation time for large projects, improving installation efficiency.
6. Better Lock File
- Feature: pnpm’s lock file (
pnpm-lock.yaml) is more concise and easier to manage in version control. - Problem Solved: Improves team collaboration and version consistency, ensuring identical dependency installation results across different environments.
Component Library TS Type Definitions
Component Export Declaration
Example: Component Export
In a component library, it’s common to provide a default export and type definitions for each component. For example:
// Button/index.ts
export { default as Button } from './Button';
export type { ButtonProps } from './Button';
The exports field in package.json
To support both CommonJS and ESM module systems while providing type definition files, you can use the exports field in package.json for fine-grained module export configuration.
{
"name": "my-component-library",
"version": "1.0.0",
"main": "cjs/index.js", // CommonJS entry point
"module": "esm/index.js", // ESM entry point
"types": "esm/types/index.d.ts", // Type definition file for the main entry point
"exports": {
"./button": {
"require": "./cjs/Button/index.js", // CommonJS import path
"import": "./esm/Button/index.js", // ESM import path
"types": "./esm/types/Button/index.d.ts" // Type definition for the Button component
},
"./modal": {
"require": "./cjs/Modal/index.js", // CommonJS import path
"import": "./dist/Modal/index.js", // ESM import path
"types": "./cjs/types/Modal/index.d.ts" // Type definition for the Modal component
}
}
}
TypeScript Configuration (tsconfig.json)
To ensure TypeScript can correctly resolve modules and generate type definition files, you need to configure tsconfig.json appropriately.
Example Configuration
{
"compilerOptions": {
"moduleResolution": "node16", // Supports ESM module resolution for Node.js 16+
"declaration": true, // Enable generation of type definition files
"declarationDir": "./esm/types", // Output directory for type definition files
"outDir": "./dist", // Output directory for compiled files
"target": "ESNext", // Target ECMAScript version
"module": "ESNext", // Use ES modules
"strict": true // Enable strict mode
}
}
Restart TypeScript Server
After modifying tsconfig.json, it is recommended to restart the TypeScript server to ensure the configuration takes effect:
- Open the VSCode command palette (
Ctrl + Shift + PorCmd + Shift + P). - Type
TypeScript: Restart TS Serverand press Enter.
Providing Type Definitions Based on TypeScript Version
To maintain compatibility with different versions of TypeScript, you can use the typesVersions field to specify corresponding type definition files for different TypeScript versions.
Example Configuration
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/cjs/index.js", // CommonJS entry point
"module": "dist/esm/index.js", // ESM entry point
"types": "dist/cjs/index.d.ts", // Default type definition file
"exports": {
".": {
"require": "./dist/cjs/index.js", // CommonJS import path
"import": "./dist/esm/index.js" // ESM import path
}
},
"typesVersions": {
"<4.5": { // Type definitions for TypeScript < 4.5
"*": ["dist/cjs/index.d.ts"]
},
">=4.5": { // Type definitions for TypeScript >= 4.5
"*": ["dist/esm/index.d.ts"]
}
}
}
Explanation
<4.5: For older versions of TypeScript, use CommonJS type definition files.>=4.5: For TypeScript 4.5 and higher, use ESM type definition files.
UNPKG
UNPKG is a content delivery network (CDN) based on npm that allows developers to directly access and load resources from npm packages via a browser. It provides a convenient way for front-end development to quickly include necessary libraries or tools without downloading or installing them.
Core Features of UNPKG
- Direct Access to npm Packages
UNPKG offers a simple way for developers to access any package published on npm directly through a URL. - Version Management Support
You can specify a specific version of an npm package to load, ensuring that the dependency versions used in your project are stable and consistent. - Real-time Package Content Browsing
UNPKG provides an online browsing feature for npm package contents, making it easy for developers to view the structure and files of a package. - Fast Resource Loading
As a CDN, UNPKG utilizes globally distributed nodes to accelerate resource loading, improving page performance.
How to Use UNPKG
Accessing Library Files
With UNPKG, you can directly include resources from npm packages in your HTML file. For example, to load the lodash library:
<script src="https://unpkg.com/lodash"></script>
The code above will load the latest version of lodash and attach it to the global variable _.
Loading a Specific Version of a Resource
To avoid compatibility issues caused by version updates, you can specify a particular version of a resource to load. For example, to load version 4.17.21 of lodash:
<script src="https://unpkg.com/[email protected]"></script>
Browsing Package Contents
UNPKG also supports browsing the contents of an npm package directly in the browser. Simply visit the following URL:
https://unpkg.com/<package-name>/
For example, to access the contents of the lodash package:
https://unpkg.com/lodash/
This will display the directory structure of the lodash package, including its files and subdirectories.
Advantages of UNPKG
- No Installation Required
Developers can directly include required libraries via a URL without manual downloading or installation. - Version Control
Supports specifying version numbers to ensure the stability of project dependencies. - Fast Loading
Leveraging the globally distributed nodes of a CDN, UNPKG provides efficient resource loading speeds. - Transparency
You can directly view the contents of an npm package to understand its file structure and dependencies. - Seamless Integration with the npm Ecosystem
All packages published to npm can be accessed through UNPKG, fully leveraging npm’s vast ecosystem.
Parsing package.json Fields
main
The main field specifies the default entry file when a package is loaded with require. For example, when using a package in umd format, you can specify the entry file with main.
{
"main": "dist/my-package.umd.js"
}
exports
The exports field can restrict how external modules access the package’s internal modules. For example:
{
"exports": {
".": "./index.js",
"./feature": "./feature.js"
}
}
With exports, you can explicitly specify which modules can be accessed externally, thereby enhancing the package’s security and controllability. It can define multiple file export declarations.
exports has a higher priority than main. For details, see the documentation.
sideEffects
The sideEffects field is used to identify which files or modules have side effects (a side effect is anything that affects the outside world).
sideEffects: falseindicates that no files have side effects.sideEffects: ["*.css"]indicates that CSS files have side effects.
{
"sideEffects": {
"es/index.js" // Specifies the entry file; typically, the entry file should not be removed
}
}
module
The module field is typically used to support import/export syntax, specifying an entry file that conforms to the ES Module specification. By distinguishing between main and module, you can support multiple import methods.
alias
alias supports multi-version management of npm packages, ensuring that different versions of dependencies can be loaded correctly.
package-lock.json
package-lock.json is npm’s lock file, used to lock the specific versions of dependencies in a project, ensuring that the installed dependencies are consistent across different environments.
Common Operations
- Deleting
node_modulesand re-runningnpm installwill generate a newpackage-lock.jsonfile. - Using
npm iornpm updatewill update thepackage-lock.jsonfile.
Case Studies
Case 1: Automatic Upgrade Causes Page Abnormalities
Problem Description
Due to an automatic upgrade of a component library package (like next), the page behaves abnormally, for example, setState causes an infinite loop. Moreover, the issue only appears for some users, making it difficult to locate.
Solution
By comparing the package-lock.json files, it was found that the next version had been upgraded. To avoid similar issues:
- Do not modify the
package-lock.jsonfile unless absolutely necessary. - If deleting
node_modulescauses some package versions to be automatically upgraded, only the specific package versions should be adjusted, not a wholesale update.
Case 2: Problem with tnpm’s resolutions Configuration
Problem Description
When using tnpm, after configuring the resolutions field, deleting node_modules does not automatically generate a package-lock.json file.
Solution
Change tnpm’s resolutions configuration to npm’s overrides configuration to ensure that the package-lock.json file can be generated correctly.
files
In package.json, the files field is used to specify which files or directories will be included in the content of an npm package when it is published. By explicitly listing the files to be included, developers can more precisely control the content of the published package and avoid including unnecessary files.
Official Documentation Link
For more information, you can refer to the npm official documentation.
Function and Purpose
Main Functions
- Control Packaging Scope:
- The
filesfield defines a whitelist of files or directories. Only the listed files and directories will be included in the npm published package. - Other unlisted files (unless they are default included files) will be excluded.
- The
- Reduce Package Size:
- By including only necessary files, you can effectively reduce the size of the npm package, improving download and installation speed.
- Protect Sensitive Information:
- Avoid accidentally publishing test files, configuration files, or other non-essential content to npm.
Default Behavior
Even if the files field is not defined, npm will default to including the following files or directories:
package.jsonREADME(supports various extensions, such as.md,.txt, etc.)CHANGELOG(supports various extensions, such as.md,.txt, etc.)LICENSE/LICENCE(supports various extensions, such as.md,.txt, etc.)index.jsor another entry file (as defined by themainfield) Additionally, the.npmignorefile will override the behavior of thefilesfield. If.npmignoreexists, it will further filter out unwanted files.
How to Use
Basic Syntax
In package.json, files is an array where each element is a string representing a file path or directory path. For example:
{
"files": [
"dist/",
"src/",
"index.js",
"README.md"
]
}
Example Explanation
"dist/": Includes the entiredistdirectory and all its sub-files."src/": Includes the entiresrcdirectory and all its sub-files."index.js": Includes only theindex.jsfile in the root directory."README.md": Includes only theREADME.mdfile in the root directory.
Points to Note
- Priority Rules:
- If both
.npmignoreandfilesare defined,fileshas higher priority. - The
.gitignorefile does not affect the behavior of thefilesfield.
- If both
- Excluding Specific Files:
- If you need to exclude certain files, you can use it in conjunction with
.npmignore. - For example, adding
*.logto.npmignorecan exclude all log files.
- If you need to exclude certain files, you can use it in conjunction with
- Debugging Packaged Content:
- Use the following command to see the actual packaged content:
npm pack - This command will generate a
.tgzfile, which you can decompress to see the finally included files.
- Use the following command to see the actual packaged content:
Example Configuration
The following is a complete package.json example showing how to use the files field:
{
"name": "example-package",
"version": "1.0.0",
"description": "An example package demonstrating the use of the 'files' field.",
"main": "dist/index.js",
"files": [
"dist/",
"src/",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"typescript": "^4.0.0"
}
}
Deleting node_modules
find . -name "node_modules" -type d -prune -print -exec rm -rf "{}" \;
npm link
1. Basic Usage of npm link
npm link is a convenient way to link a local package to a project, often used for development and debugging. However, you might encounter some issues during its use.
2. Common Problems and Solutions
2.1 Deleting Redundant node_modules Packages
- Problem Description:
- After running
npm link, you might find that the linked package cannot be found. - This could be due to redundant or incomplete dependency packages in
node_modules.
- After running
- Solution:
- Check if the packages under
node_modulesare complete. - If there’s an issue, you can try deleting the redundant
node_modulesand reinstalling dependencies:rm -rf node_modules package-lock.json npm install
- Check if the packages under
- Possible Cause:
- Different versions of
npmmight cause dependency resolution issues.
- Different versions of
2.2 Node.js Version Consistency
- Problem Description:
- If you switched the Node.js version using a command like
nvm use 14before runningnpm link, it might lead to an inconsistent linked directory structure.
- If you switched the Node.js version using a command like
- Solution:
- Ensure that both linked projects use the same Node.js version.
- You can check and switch versions with the following commands:
nvm list nvm use <version>
2.3 React Hooks Error Problem
- Problem Description:
- When using
npm link, you might encounter the following error:Hooks can only be called inside the body of a function component. - The reason is that there are multiple
reactinstances in the project (i.e., multiple versions ofreactandreact-dom).
- When using
- Solution:
- Move the
reactandreact-domdependencies topeerDependenciesto ensure the sub-project does not installreacton its own. - Link the parent project’s
reactandreact-dom. The specific steps are as follows:# 1. In the child project, remove the direct dependencies on react and react-dom npm uninstall react react-dom # 2. In the child project's package.json, add peerDependencies "peerDependencies": { "react": "^17.0.0", "react-dom": "^17.0.0" } # 3. Link the parent project's react and react-dom cd PARENT_PROJECT/node_modules/react npm link cd ../react-dom npm link # 4. In the child project, link the parent project's react and react-dom cd CHILD_PROJECT npm link react npm link react-dom
- Move the
1. Quickly View README
Quickly view the content of a README file via the command line:
readme net
2. Quickly Install npm Packages
Use npmi to quickly install npm packages:
npm install -g npmi
3. Explanation
readme net:- Used to quickly view the
READMEfile content of a project. - Ensure the relevant tool is correctly installed and configured.
- Used to quickly view the
npmi:- A simplified npm installation tool that improves installation efficiency.
- After installation, you can directly use
npmi <package-name>to install dependency packages.
npm version patch- Automatically updates to a new patch version.
Install two different versions of a package
"antdmo2": "npm:antd-mobile@^2.3.4",
"antdmo5": "npm:[email protected]",
References
- npm Documentation — Official npm registry and CLI documentation
- pnpm Documentation — Official pnpm documentation explaining its advantages over npm
- Node.js Package Manager Guide — Socket.dev — Comparison of npm, yarn, and pnpm package managers
Be the first to know when I post cool stuff
Subscribe to get my latest posts by email.
Thanks for signing up! Check your email to confirm your subscription.
Whoops, we weren't able to process your signup.