Skip to content

Commit

Permalink
feat: public-hoist-pattern
Browse files Browse the repository at this point in the history
close #2628
  • Loading branch information
zkochan committed Jun 13, 2020
1 parent e1ca9fc commit 66c5ae6
Show file tree
Hide file tree
Showing 23 changed files with 222 additions and 85 deletions.
1 change: 1 addition & 0 deletions packages/config/src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export interface Config {
pnpmfile: string,
packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone',
hoistPattern?: string[],
publicHoistPattern?: string[],
useStoreServer?: boolean,
useRunningStoreServer?: boolean,
workspaceConcurrency: number,
Expand Down
10 changes: 9 additions & 1 deletion packages/config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const types = Object.assign({
'prefer-frozen-shrinkwrap': Boolean,
'prefer-offline': Boolean,
'production': [null, true],
'public-hoist-pattern': Array,
'publish-branch': String,
'reporter': String,
'save-peer': Boolean,
Expand Down Expand Up @@ -149,7 +150,6 @@ export default async (
'registry': npmDefaults.registry,
'save-peer': false,
'save-workspace-protocol': true,
'shamefully-hoist': false,
'shared-workspace-lockfile': true,
'shared-workspace-shrinkwrap': true,
'shrinkwrap': npmDefaults.shrinkwrap,
Expand Down Expand Up @@ -311,6 +311,14 @@ export default async (
if (pnpmConfig['hoist'] === false) {
delete pnpmConfig.hoistPattern
}
switch (pnpmConfig.shamefullyHoist) {
case false:
delete pnpmConfig.publicHoistPattern
break
case true:
pnpmConfig.publicHoistPattern = ['*']
break
}
if (typeof pnpmConfig['color'] === 'boolean') {
switch (pnpmConfig['color']) {
case true:
Expand Down
59 changes: 32 additions & 27 deletions packages/get-context/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export interface PnpmContext<T> {
existsCurrentLockfile: boolean,
existsWantedLockfile: boolean,
extraBinPaths: string[],
hoistedAliases: {[depPath: string]: string[]}
hoistedAliases: {[depPath: string]: string[]},
publicHoistedAliases: Set<string>,
include: IncludedDependencies,
modulesFile: Modules | null,
pendingBuilds: string[],
Expand All @@ -38,9 +39,10 @@ export interface PnpmContext<T> {
rootModulesDir: string,
hoistPattern: string[] | undefined,
hoistedModulesDir: string,
publicHoistPattern: string[] | undefined,
publicHoistedModulesDir: string,
lockfileDir: string,
virtualStoreDir: string,
shamefullyHoist: boolean,
skipped: Set<string>,
storeDir: string,
wantedLockfile: Lockfile,
Expand Down Expand Up @@ -75,8 +77,8 @@ export default async function getContext<T> (
hoistPattern?: string[] | undefined,
forceHoistPattern?: boolean,

shamefullyHoist?: boolean,
forceShamefullyHoist?: boolean,
publicHoistPattern?: string[] | undefined,
forcePublicHoistPattern?: boolean,
}
): Promise<PnpmContext<T>> {
const modulesDir = opts.modulesDir ?? 'node_modules'
Expand All @@ -97,8 +99,8 @@ export default async function getContext<T> (
forceHoistPattern: opts.forceHoistPattern,
hoistPattern: opts.hoistPattern,

forceShamefullyHoist: opts.forceShamefullyHoist,
shamefullyHoist: opts.shamefullyHoist,
forcePublicHoistPattern: opts.forcePublicHoistPattern,
publicHoistPattern: opts.publicHoistPattern,
})
if (purged) {
importersContext = await readProjectsContext(projects, {
Expand Down Expand Up @@ -126,12 +128,10 @@ export default async function getContext<T> (
const extraBinPaths = [
...opts.extraBinPaths || [],
]
const shamefullyHoist = Boolean(typeof importersContext.shamefullyHoist === 'undefined' ? opts.shamefullyHoist : importersContext.shamefullyHoist)
if (opts.hoistPattern && !shamefullyHoist) {
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
const hoistedModulesDir = path.join(virtualStoreDir, 'node_modules')
if (opts.hoistPattern?.length) {
extraBinPaths.unshift(path.join(hoistedModulesDir, '.bin'))
}
const hoistedModulesDir = shamefullyHoist
? importersContext.rootModulesDir : path.join(virtualStoreDir, 'node_modules')
const ctx: PnpmContext<T> = {
extraBinPaths,
hoistedAliases: importersContext.hoistedAliases,
Expand All @@ -142,12 +142,14 @@ export default async function getContext<T> (
modulesFile: importersContext.modules,
pendingBuilds: importersContext.pendingBuilds,
projects: importersContext.projects,
publicHoistedAliases: importersContext.publicHoistedAliases,
publicHoistedModulesDir: importersContext.rootModulesDir,
publicHoistPattern: opts.publicHoistPattern,
registries: {
...opts.registries,
...importersContext.registries,
},
rootModulesDir: importersContext.rootModulesDir,
shamefullyHoist,
skipped: importersContext.skipped,
storeDir: opts.storeDir,
virtualStoreDir,
Expand Down Expand Up @@ -185,12 +187,12 @@ async function validateModules (
hoistPattern?: string[] | undefined,
forceHoistPattern?: boolean,

shamefullyHoist?: boolean | undefined,
forceShamefullyHoist?: boolean,
publicHoistPattern?: string[] | undefined,
forcePublicHoistPattern?: boolean,
}
): Promise<{ purged: boolean }> {
const rootProject = projects.find(({ id }) => id === '.')
if (opts.forceShamefullyHoist && modules.shamefullyHoist !== opts.shamefullyHoist) {
if (opts.forcePublicHoistPattern && !R.equals(modules.publicHoistPattern, opts.publicHoistPattern)) {
if (opts.forceNewModules && rootProject) {
await purgeModulesDirsOfImporter(rootProject)
return { purged: true }
Expand Down Expand Up @@ -307,11 +309,13 @@ export interface PnpmSingleContext {
include: IncludedDependencies,
modulesFile: Modules | null,
pendingBuilds: string[],
publicHoistedAliases: Set<string>,
publicHoistPattern: string[] | undefined,
publicHoistedModulesDir: string,
registries: Registries,
rootModulesDir: string,
lockfileDir: string,
virtualStoreDir: string,
shamefullyHoist: boolean,
skipped: Set<string>,
storeDir: string,
wantedLockfile: Lockfile,
Expand Down Expand Up @@ -339,20 +343,21 @@ export async function getContextForSingleImporter (
hoistPattern?: string[] | undefined,
forceHoistPattern?: boolean,

shamefullyHoist?: boolean,
forceShamefullyHoist?: boolean,
publicHoistPattern?: string[] | undefined,
forcePublicHoistPattern?: boolean,
},
alreadyPurged: boolean = false
): Promise<PnpmSingleContext> {
const {
currentHoistPattern,
currentPublicHoistPattern,
hoistedAliases,
projects,
publicHoistedAliases,
include,
modules,
pendingBuilds,
registries,
shamefullyHoist,
skipped,
rootModulesDir,
} = await readProjectsContext(
Expand Down Expand Up @@ -388,8 +393,8 @@ export async function getContextForSingleImporter (
forceHoistPattern: opts.forceHoistPattern,
hoistPattern: opts.hoistPattern,

forceShamefullyHoist: opts.forceShamefullyHoist,
shamefullyHoist: opts.shamefullyHoist,
forcePublicHoistPattern: opts.forcePublicHoistPattern,
publicHoistPattern: opts.publicHoistPattern,
})
if (purged) {
return getContextForSingleImporter(manifest, opts, true)
Expand All @@ -400,12 +405,10 @@ export async function getContextForSingleImporter (
const extraBinPaths = [
...opts.extraBinPaths || [],
]
const sHoist = Boolean(typeof shamefullyHoist === 'undefined' ? opts.shamefullyHoist : shamefullyHoist)
if (opts.hoistPattern && !sHoist) {
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
const hoistedModulesDir = path.join(virtualStoreDir, 'node_modules')
if (opts.hoistPattern?.length) {
extraBinPaths.unshift(path.join(hoistedModulesDir, '.bin'))
}
const hoistedModulesDir = sHoist
? rootModulesDir : path.join(virtualStoreDir, 'node_modules')
const ctx: PnpmSingleContext = {
extraBinPaths,
hoistedAliases,
Expand All @@ -419,12 +422,14 @@ export async function getContextForSingleImporter (
modulesFile: modules,
pendingBuilds,
prefix: opts.dir,
publicHoistedAliases,
publicHoistedModulesDir: rootModulesDir,
publicHoistPattern: opts.publicHoistPattern,
registries: {
...opts.registries,
...registries,
},
rootModulesDir,
shamefullyHoist: sHoist,
skipped,
storeDir,
virtualStoreDir,
Expand Down
27 changes: 19 additions & 8 deletions packages/headless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ export interface HeadlessOptions {
rootDir: string,
}>,
hoistedAliases: {[depPath: string]: string[]}
publicHoistedAliases: Set<string>,
hoistPattern?: string[],
publicHoistPattern?: string[],
lockfileDir: string,
modulesDir?: string,
virtualStoreDir?: string,
shamefullyHoist: boolean,
storeController: StoreController,
sideEffectsCacheRead: boolean,
sideEffectsCacheWrite: boolean,
Expand Down Expand Up @@ -128,8 +129,8 @@ export default async (opts: HeadlessOptions) => {
const rootModulesDir = await realpathMissing(path.join(lockfileDir, relativeModulesDir))
const virtualStoreDir = pathAbsolute(opts.virtualStoreDir ?? path.join(relativeModulesDir, '.pnpm'), lockfileDir)
const currentLockfile = opts.currentLockfile || await readCurrentLockfile(virtualStoreDir, { ignoreIncompatible: false })
const hoistedModulesDir = opts.shamefullyHoist
? rootModulesDir : path.join(virtualStoreDir, 'node_modules')
const hoistedModulesDir = path.join(virtualStoreDir, 'node_modules')
const publicHoistedModulesDir = rootModulesDir

for (const { id, manifest, rootDir } of opts.projects) {
if (!satisfiesPackageManifest(wantedLockfile, manifest, id)) {
Expand Down Expand Up @@ -167,6 +168,8 @@ export default async (opts: HeadlessOptions) => {
include: opts.include,
lockfileDir,
pruneStore: opts.pruneStore,
publicHoistedAliases: opts.publicHoistedAliases,
publicHoistedModulesDir: opts.publicHoistPattern && publicHoistedModulesDir || undefined,
registries: opts.registries,
skipped,
storeController: opts.storeController,
Expand Down Expand Up @@ -240,18 +243,25 @@ export default async (opts: HeadlessOptions) => {
})
}

const rootImporterWithFlatModules = opts.hoistPattern && opts.projects.find(({ id }) => id === '.')
const rootImporterWithFlatModules = (opts.hoistPattern || opts.publicHoistPattern) && opts.projects.find(({ id }) => id === '.')
let newHoistedAliases!: {[depPath: string]: string[]}
let newPubliclyHoistedAliases!: Set<string>
if (rootImporterWithFlatModules) {
newHoistedAliases = await hoist(matcher(opts.hoistPattern!), {
const hoistResult = await hoist({
lockfile: filteredLockfile,
lockfileDir,
modulesDir: hoistedModulesDir,
privateHoistDir: hoistedModulesDir,
privateHoistPattern: opts.hoistPattern ?? [],
publicHoistDir: publicHoistedModulesDir,
publicHoistPattern: opts.publicHoistPattern ?? [],
registries: opts.registries,
virtualStoreDir,
})
newHoistedAliases = hoistResult.hoistedDeps
newPubliclyHoistedAliases = hoistResult.publiclyHoistedAliases
} else {
newHoistedAliases = {}
newPubliclyHoistedAliases = new Set()
}

await Promise.all(opts.projects.map(async ({ rootDir, id, manifest, modulesDir }) => {
Expand Down Expand Up @@ -302,7 +312,7 @@ export default async (opts: HeadlessOptions) => {
})
}
const extraBinPaths = [...opts.extraBinPaths || []]
if (opts.hoistPattern && !opts.shamefullyHoist) {
if (opts.hoistPattern) {
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
}
await buildModules(graph, Array.from(directNodes), {
Expand Down Expand Up @@ -333,8 +343,9 @@ export default async (opts: HeadlessOptions) => {
layoutVersion: LAYOUT_VERSION,
packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
pendingBuilds: opts.pendingBuilds,
publicHoistedAliases: Array.from(newPubliclyHoistedAliases),
publicHoistPattern: opts.publicHoistPattern,
registries: opts.registries,
shamefullyHoist: opts.shamefullyHoist || false,
skipped: Array.from(skipped),
storeDir: opts.storeDir,
virtualStoreDir,
Expand Down
4 changes: 2 additions & 2 deletions packages/headless/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,12 @@ test('installing with hoistPattern=*', async (t) => {
t.end()
})

test('installing with hoistPattern=* and shamefullyHoist=true', async (t) => {
test('installing with publicHoistPattern=*', async (t) => {
const prefix = path.join(fixtures, 'simple-shamefully-flatten')
await rimraf(path.join(prefix, 'node_modules'))
const reporter = sinon.spy()

await headless(await testDefaults({ lockfileDir: prefix, reporter, hoistPattern: '*', shamefullyHoist: true }))
await headless(await testDefaults({ lockfileDir: prefix, reporter, publicHoistPattern: '*' }))

const project = assertProject(t, prefix)
t.ok(project.requireModule('is-positive'), 'prod dep installed')
Expand Down
1 change: 1 addition & 0 deletions packages/hoist/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@pnpm/lockfile-types": "workspace:2.0.1",
"@pnpm/lockfile-utils": "workspace:2.0.13",
"@pnpm/lockfile-walker": "workspace:3.0.1",
"@pnpm/matcher": "workspace:^1.0.2",
"@pnpm/pkgid-to-filename": "3.0.0",
"@pnpm/symlink-dependency": "workspace:3.0.6",
"@pnpm/types": "workspace:6.0.0",
Expand Down

0 comments on commit 66c5ae6

Please sign in to comment.