Skip to content

Commit

Permalink
refactor: linking direct dependencies (#5669)
Browse files Browse the repository at this point in the history
  • Loading branch information
zkochan committed Nov 23, 2022
1 parent a49788f commit d5496cc
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 81 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-otters-explode.md
@@ -0,0 +1,5 @@
---
"@pnpm/pkg-manager.direct-dep-linker": minor
---

Initial release.
1 change: 1 addition & 0 deletions pkg-manager/core/package.json
Expand Up @@ -41,6 +41,7 @@
"@pnpm/npm-package-arg": "^1.0.0",
"@pnpm/package-requester": "workspace:*",
"@pnpm/parse-wanted-dependency": "workspace:*",
"@pnpm/pkg-manager.direct-dep-linker": "workspace:*",
"@pnpm/prune-lockfile": "workspace:*",
"@pnpm/read-modules-dir": "workspace:*",
"@pnpm/read-package-json": "workspace:*",
Expand Down
84 changes: 45 additions & 39 deletions pkg-manager/core/src/install/link.ts
Expand Up @@ -3,13 +3,13 @@ import path from 'path'
import { calcDepState, DepsStateCache } from '@pnpm/calc-dep-state'
import {
progressLogger,
rootLogger,
stageLogger,
statsLogger,
} from '@pnpm/core-loggers'
import {
filterLockfileByImporters,
} from '@pnpm/filter-lockfile'
import { linkDirectDeps } from '@pnpm/pkg-manager.direct-dep-linker'
import { hoist } from '@pnpm/hoist'
import { Lockfile } from '@pnpm/lockfile-file'
import { logger } from '@pnpm/logger'
Expand All @@ -21,7 +21,7 @@ import {
LinkedDependency,
} from '@pnpm/resolve-dependencies'
import { StoreController } from '@pnpm/store-controller-types'
import { symlinkDependency, symlinkDirectRootDependency } from '@pnpm/symlink-dependency'
import { symlinkDependency } from '@pnpm/symlink-dependency'
import {
HoistedDependencies,
Registries,
Expand Down Expand Up @@ -160,43 +160,49 @@ export async function linkPackages (
})

if (opts.symlink) {
await Promise.all(projects.map(async ({ id, manifest, modulesDir, rootDir }) => {
const deps = opts.dependenciesByProjectId[id]
const importerFromLockfile = newCurrentLockfile.importers[id]
await Promise.all([
...Object.entries(deps)
.filter(([rootAlias]) => importerFromLockfile.specifiers[rootAlias])
.map(([rootAlias, depPath]) => ({ rootAlias, depGraphNode: depGraph[depPath] }))
.filter(({ depGraphNode }) => depGraphNode)
.map(async ({ rootAlias, depGraphNode }) => {
if (
(await symlinkDependency(depGraphNode.dir, modulesDir, rootAlias)).reused
) return

const isDev = Boolean(manifest.devDependencies?.[depGraphNode.name])
const isOptional = Boolean(manifest.optionalDependencies?.[depGraphNode.name])
rootLogger.debug({
added: {
dependencyType: isDev && 'dev' || isOptional && 'optional' || 'prod',
id: depGraphNode.id,
latest: opts.outdatedDependencies[depGraphNode.id],
name: rootAlias,
realName: depGraphNode.name,
version: depGraphNode.version,
},
prefix: rootDir,
})
}),
...opts.linkedDependenciesByProjectId[id].map(async (linkedDependency) => {
const depLocation = resolvePath(rootDir, linkedDependency.resolution.directory)
return symlinkDirectRootDependency(depLocation, modulesDir, linkedDependency.alias, {
fromDependenciesField: linkedDependency.dev && 'devDependencies' || linkedDependency.optional && 'optionalDependencies' || 'dependencies',
linkedPackage: linkedDependency,
prefix: rootDir,
})
}),
])
}))
const projectsToLink = await Promise.all(
projects.map(async ({ id, manifest, modulesDir, rootDir }) => {
const deps = opts.dependenciesByProjectId[id]
const importerFromLockfile = newCurrentLockfile.importers[id]
return {
dir: rootDir,
modulesDir,
dependencies: await Promise.all([
...Object.entries(deps)
.filter(([rootAlias]) => importerFromLockfile.specifiers[rootAlias])
.map(([rootAlias, depPath]) => ({ rootAlias, depGraphNode: depGraph[depPath] }))
.filter(({ depGraphNode }) => depGraphNode)
.map(async ({ rootAlias, depGraphNode }) => {
const isDev = Boolean(manifest.devDependencies?.[depGraphNode.name])
const isOptional = Boolean(manifest.optionalDependencies?.[depGraphNode.name])
return {
alias: rootAlias,
name: depGraphNode.name,
version: depGraphNode.version,
dir: depGraphNode.dir,
id: depGraphNode.id,
dependencyType: (isDev && 'dev' || isOptional && 'optional' || 'prod') as 'dev' | 'optional' | 'prod',
latest: opts.outdatedDependencies[depGraphNode.id],
isExternalLink: false,
}
}),
...opts.linkedDependenciesByProjectId[id].map(async (linkedDependency) => {
const dir = resolvePath(rootDir, linkedDependency.resolution.directory)
return {
alias: linkedDependency.alias,
name: linkedDependency.name,
version: linkedDependency.version,
dir,
id: linkedDependency.resolution.directory,
dependencyType: (linkedDependency.dev && 'dev' || linkedDependency.optional && 'optional' || 'prod') as 'dev' | 'optional' | 'prod',
isExternalLink: true,
}
}),
]),
}
})
)
await linkDirectDeps(projectsToLink)
}

let currentLockfile: Lockfile
Expand Down
3 changes: 3 additions & 0 deletions pkg-manager/core/tsconfig.json
Expand Up @@ -117,6 +117,9 @@
{
"path": "../client"
},
{
"path": "../direct-dep-linker"
},
{
"path": "../get-context"
},
Expand Down
13 changes: 13 additions & 0 deletions pkg-manager/direct-dep-linker/README.md
@@ -0,0 +1,13 @@
# @pnpm/pkg-manager.direct-dep-linker

> Links direct dependencies to projects
## Installation

```
pnpm install @pnpm/pkg-manager.direct-dep-linker
```

## License

[MIT](LICENSE)
44 changes: 44 additions & 0 deletions pkg-manager/direct-dep-linker/package.json
@@ -0,0 +1,44 @@
{
"name": "@pnpm/pkg-manager.direct-dep-linker",
"description": "Fast installation using only pnpm-lock.yaml",
"version": "0.0.0",
"bugs": {
"url": "https://github.com/pnpm/pnpm/issues"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"!*.map"
],
"peerDependencies": {
"@pnpm/logger": "^5.0.0"
},
"devDependencies": {
"@pnpm/pkg-manager.direct-dep-linker": "workspace:*"
},
"homepage": "https://github.com/pnpm/pnpm/blob/main/pkg-manager/direct-dep-linker#readme",
"keywords": [
"pnpm7",
"pnpm"
],
"license": "MIT",
"engines": {
"node": ">=14.6"
},
"repository": "https://github.com/pnpm/pnpm/blob/main/pkg-manager/direct-dep-linker",
"scripts": {
"lint": "eslint src/**/*.ts",
"test": "pnpm run compile",
"prepublishOnly": "pnpm run compile",
"compile": "tsc --build && pnpm run lint --fix"
},
"dependencies": {
"@pnpm/core-loggers": "workspace:*",
"@pnpm/symlink-dependency": "workspace:*"
},
"funding": "https://opencollective.com/pnpm",
"exports": {
".": "./lib/index.js"
}
}
1 change: 1 addition & 0 deletions pkg-manager/direct-dep-linker/src/index.ts
@@ -0,0 +1 @@
export * from './linkDirectDeps'
55 changes: 55 additions & 0 deletions pkg-manager/direct-dep-linker/src/linkDirectDeps.ts
@@ -0,0 +1,55 @@
import { rootLogger } from '@pnpm/core-loggers'
import { symlinkDependency, symlinkDirectRootDependency } from '@pnpm/symlink-dependency'

export interface LinkedDirectDep {
alias: string
name: string
version: string
dir: string
id: string
dependencyType: 'prod' | 'dev' | 'optional'
isExternalLink: boolean
latest?: string
}

export interface ProjectToLink {
dir: string
modulesDir: string
dependencies: LinkedDirectDep[]
}

export async function linkDirectDeps (
projects: ProjectToLink[]
) {
await Promise.all(projects.map(async (project) => {
await Promise.all(project.dependencies.map(async (dep) => {
if (dep.isExternalLink) {
await symlinkDirectRootDependency(dep.dir, project.modulesDir, dep.alias, {
fromDependenciesField: dep.dependencyType === 'dev' && 'devDependencies' ||
dep.dependencyType === 'optional' && 'optionalDependencies' ||
'dependencies',
linkedPackage: {
name: dep.name,
version: dep.version,
},
prefix: project.dir,
})
return
}
if ((await symlinkDependency(dep.dir, project.modulesDir, dep.alias)).reused) {
return
}
rootLogger.debug({
added: {
dependencyType: dep.dependencyType,
id: dep.id,
latest: dep.latest,
name: dep.alias,
realName: dep.name,
version: dep.version,
},
prefix: project.dir,
})
}))
}))
}
19 changes: 19 additions & 0 deletions pkg-manager/direct-dep-linker/tsconfig.json
@@ -0,0 +1,19 @@
{
"extends": "@pnpm/tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"include": [
"src/**/*.ts",
"../../__typings__/**/*.d.ts"
],
"references": [
{
"path": "../../fs/symlink-dependency"
},
{
"path": "../../packages/core-loggers"
}
]
}
8 changes: 8 additions & 0 deletions pkg-manager/direct-dep-linker/tsconfig.lint.json
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"test/**/*.ts",
"../../__typings__/**/*.d.ts"
]
}
1 change: 1 addition & 0 deletions pkg-manager/headless/package.json
Expand Up @@ -83,6 +83,7 @@
"@pnpm/modules-yaml": "workspace:*",
"@pnpm/package-is-installable": "workspace:*",
"@pnpm/package-requester": "workspace:*",
"@pnpm/pkg-manager.direct-dep-linker": "workspace:*",
"@pnpm/read-package-json": "workspace:*",
"@pnpm/read-project-manifest": "workspace:*",
"@pnpm/real-hoist": "workspace:*",
Expand Down

0 comments on commit d5496cc

Please sign in to comment.