Skip to content

Conversation

gun-yu
Copy link

@gun-yu gun-yu commented Oct 11, 2025

This PR adds support for PnP resolution.

#1875 in the previous discussion, I have internalized pnp-go into the repository.

Please note that the PR has become quite large due to the inclusion of the PnP source and test code. I apologize for the length and appreciate your understanding.

what is pnp

Yarn Plug’n’Play (PnP) is a dependency resolution system that removes the need for a traditional node_modules folder.
describe at #460

how to support

add pnp resolution config in host

type host struct {
	orchestrator *Orchestrator
	host         compiler.CompilerHost
	// Caches that last only for build cycle and then cleared out
	extendedConfigCache tsc.ExtendedConfigCache
	sourceFiles         parseCache[ast.SourceFileParseOptions, *ast.SourceFile]
	configTimes         collections.SyncMap[tspath.Path, time.Duration]

	// caches that stay as long as they are needed
	resolvedReferences parseCache[tspath.Path, *tsoptions.ParsedCommandLine]
	mTimes             *collections.SyncMap[tspath.Path, time.Time]
	resolvedReferences  parseCache[tspath.Path, *tsoptions.ParsedCommandLine]
	mTimes              *collections.SyncMap[tspath.Path, time.Time]
	pnpResolutionConfig *pnp.ResolutionConfig
}

add pnp branch in resolver.go

// resolveTypeReferenceDirective
// skip typeRoots because PnP knows exactly where each @types is located.
	if r.resolver.pnpResolutionConfig != nil {
		if resolvedFromNearestNodeModulesDirectory := r.loadModuleFromNearestNodeModulesDirectory(true /*typesScopeOnly*/); !resolvedFromNearestNodeModulesDirectory.shouldContinueSearching() {
			return r.createResolvedTypeReferenceDirective(resolvedFromNearestNodeModulesDirectory, true /*primary*/)
		}
	} else {
		if len(typeRoots) > 0 {
			if r.tracer != nil {
				r.tracer.write(diagnostics.Resolving_with_primary_search_path_0.Format(strings.Join(typeRoots, ", ")))
			}
// loadModuleFromNearestNodeModulesDirectory
if r.resolver.pnpResolutionConfig != nil {
			if result := r.loadModuleFromPNP(priorityExtensions, typesScopeOnly); !result.shouldContinueSearching() {
				return result
			}
		} else {
			if result := r.loadModuleFromNearestNodeModulesDirectoryWorker(priorityExtensions, mode, typesScopeOnly); !result.shouldContinueSearching() {
				return result
			}
		}

logger.Log(fmt.Sprintf("ATA:: Installed typings %v", packageNames))
var installedTypingFiles []string
resolver := module.NewResolver(ti.host, &core.CompilerOptions{ModuleResolution: core.ModuleResolutionKindNodeNext}, "", "")
resolver := module.NewResolver(ti.host, &core.CompilerOptions{ModuleResolution: core.ModuleResolutionKindNodeNext}, "", "", nil)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: add pnp support later

@gun-yu gun-yu changed the title Feat/add pnp resolver support pnp resolver Oct 11, 2025
packageName, rest := ParsePackageName(moduleName)
packageDirectory := tspath.CombinePaths(nodeModulesDirectory, packageName)

func (r *resolutionState) loadModuleFromSpecificNodeModulesDirectory(ext extensions, candidate string, packageDirectory string, rest string, nodeModulesDirectoryExists bool) *resolved {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I change this function's interface

}

// need fixtures to be yarn install and make global cache
func TestGlobalCache(t *testing.T) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test cases were taken from pnp-rs, but since they are relatively complex to run and maintain.
I think it would be fine to remove them if they’re not considered necessary.
Please let me know your thoughts!

@gun-yu
Copy link
Author

gun-yu commented Oct 12, 2025

@microsoft-github-policy-service agree

pnpResolutionConfig := TryGetPnpResolutionConfig(currentDirectory)

if pnpResolutionConfig != nil {
fs = pnpvfs.From(fs)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, this way I wouldn’t be able to take advantage of the cached VFS, so I’m thinking of moving its location instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant