Skip to content

Commit

Permalink
[workspace-resolve] Allow configuration of which resolvers to apply to (
Browse files Browse the repository at this point in the history
#5074)

* [workspace-resolve] Allow configuration
Monomorphic request object.

* Update default

---------

Co-authored-by: David Michon <[email protected]>
  • Loading branch information
dmichon-msft and dmichon-msft authored Jan 13, 2025
1 parent a15fef5 commit cca07c9
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/webpack-workspace-resolve-plugin",
"comment": "(BREAKING CHANGE) Switch constructor to an options object. Add option to specify which webpack resolvers to apply the plugin to. Improve performance by using an object literal instead of the spread operator when updating the resolve request. Upgrade compilation target to not polyfill optional chaining.",
"type": "minor"
}
],
"packageName": "@rushstack/webpack-workspace-resolve-plugin"
}
3 changes: 2 additions & 1 deletion common/reviews/api/webpack-workspace-resolve-plugin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface IWorkspaceLayoutCacheOptions {
// @beta
export interface IWorkspaceResolvePluginOptions {
cache: WorkspaceLayoutCache;
resolverNames?: Iterable<string>;
}

// @beta
Expand All @@ -58,7 +59,7 @@ export class WorkspaceLayoutCache {

// @beta
export class WorkspaceResolvePlugin implements WebpackPluginInstance {
constructor(cache: WorkspaceLayoutCache);
constructor(options: IWorkspaceResolvePluginOptions);
// (undocumented)
apply(compiler: Compiler): void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,27 @@ export class KnownDescriptionFilePlugin {
// Store the resolver context since a WeakMap lookup is cheaper than walking the tree again
contextForPackage.set(descriptionFileData, match);

// Using the object literal is an order of magnitude faster, at least on node 18.19.1
const obj: ResolveRequest = {
...request,
descriptionFileRoot,
path: request.path,
context: request.context,
descriptionFilePath,
descriptionFileRoot,
descriptionFileData,
relativePath
relativePath,
ignoreSymlinks: request.ignoreSymlinks,
fullySpecified: request.fullySpecified,
__innerRequest: request.__innerRequest,
__innerRequest_request: request.__innerRequest_request,
__innerRequest_relativePath: request.__innerRequest_relativePath,

request: request.request,
query: request.query,
fragment: request.fragment,
module: request.module,
directory: request.directory,
file: request.file,
internal: request.internal
};

// Delegate to the resolver step at `target`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,25 @@ export class KnownPackageDependenciesPlugin {
(remainingPath.length > 1 && cache.normalizeToSlash?.(remainingPath)) || remainingPath;
const { descriptionFileRoot } = dependency.value;
const obj: ResolveRequest = {
...request,
path: descriptionFileRoot,
context: request.context,
descriptionFilePath: `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`,
descriptionFileRoot,
descriptionFileData: undefined,
descriptionFilePath: `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`,
relativePath,
ignoreSymlinks: request.ignoreSymlinks,
fullySpecified,
__innerRequest: request.__innerRequest,
__innerRequest_request: request.__innerRequest_request,
__innerRequest_relativePath: request.__innerRequest_relativePath,

relativePath: relativePath,
request: relativePath,
fullySpecified,
module: false
query: request.query,
fragment: request.fragment,
module: false,
directory: request.directory,
file: request.file,
internal: request.internal
};
// eslint-disable-next-line @rushstack/no-new-null
resolver.doResolve(target, obj, null, resolveContext, callback);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import type { WebpackPluginInstance, Compiler } from 'webpack';
import type { WebpackPluginInstance, Compiler, ResolveOptions } from 'webpack';

import type { WorkspaceLayoutCache } from './WorkspaceLayoutCache';
import { KnownDescriptionFilePlugin } from './KnownDescriptionFilePlugin';
Expand All @@ -17,6 +17,12 @@ export interface IWorkspaceResolvePluginOptions {
* The cache of workspace layout information.
*/
cache: WorkspaceLayoutCache;

/**
* Which webpack resolvers to apply the plugin to.
* @defaultValue ['normal', 'context', 'loader']
*/
resolverNames?: Iterable<string>;
}

/**
Expand All @@ -26,48 +32,53 @@ export interface IWorkspaceResolvePluginOptions {
*/
export class WorkspaceResolvePlugin implements WebpackPluginInstance {
private readonly _cache: WorkspaceLayoutCache;
private readonly _resolverNames: Set<string>;

public constructor(cache: WorkspaceLayoutCache) {
this._cache = cache;
public constructor(options: IWorkspaceResolvePluginOptions) {
this._cache = options.cache;
this._resolverNames = new Set(options.resolverNames ?? ['normal', 'context', 'loader']);
}

public apply(compiler: Compiler): void {
compiler.resolverFactory.hooks.resolveOptions
.for('normal')
.tap(WorkspaceResolvePlugin.name, (resolveOptions) => {
// Omit default `node_modules`
if (resolveOptions.modules) {
resolveOptions.modules = resolveOptions.modules.filter((modulePath: string) => {
return modulePath !== 'node_modules';
});
} else {
resolveOptions.modules = [];
}
const cache: WorkspaceLayoutCache = this._cache;

const cache: WorkspaceLayoutCache = this._cache;
function handler(resolveOptions: ResolveOptions): ResolveOptions {
// Omit default `node_modules`
if (resolveOptions.modules) {
resolveOptions.modules = resolveOptions.modules.filter((modulePath: string) => {
return modulePath !== 'node_modules';
});
} else {
resolveOptions.modules = [];
}

resolveOptions.plugins ??= [];
resolveOptions.plugins.push(
// Optimize identifying the package.json file for the issuer
new KnownDescriptionFilePlugin(cache, 'before-parsed-resolve', 'described-resolve'),
// Optimize locating the installed dependencies of the current package
new KnownPackageDependenciesPlugin(cache, 'before-raw-module', 'resolve-as-module'),
// Optimize loading the package.json file for the destination package (bare specifier)
new KnownDescriptionFilePlugin(cache, 'before-resolve-as-module', 'resolve-in-package'),
// Optimize loading the package.json file for the destination package (relative path)
new KnownDescriptionFilePlugin(cache, 'before-relative', 'described-relative'),
// Optimize locating and loading nested package.json for a directory
new KnownDescriptionFilePlugin(
cache,
'before-undescribed-existing-directory',
'existing-directory',
true
),
// Optimize locating and loading nested package.json for a file
new KnownDescriptionFilePlugin(cache, 'before-undescribed-raw-file', 'raw-file')
);
resolveOptions.plugins ??= [];
resolveOptions.plugins.push(
// Optimize identifying the package.json file for the issuer
new KnownDescriptionFilePlugin(cache, 'before-parsed-resolve', 'described-resolve'),
// Optimize locating the installed dependencies of the current package
new KnownPackageDependenciesPlugin(cache, 'before-raw-module', 'resolve-as-module'),
// Optimize loading the package.json file for the destination package (bare specifier)
new KnownDescriptionFilePlugin(cache, 'before-resolve-as-module', 'resolve-in-package'),
// Optimize loading the package.json file for the destination package (relative path)
new KnownDescriptionFilePlugin(cache, 'before-relative', 'described-relative'),
// Optimize locating and loading nested package.json for a directory
new KnownDescriptionFilePlugin(
cache,
'before-undescribed-existing-directory',
'existing-directory',
true
),
// Optimize locating and loading nested package.json for a file
new KnownDescriptionFilePlugin(cache, 'before-undescribed-raw-file', 'raw-file')
);

return resolveOptions;
});
return resolveOptions;
}
for (const resolverName of this._resolverNames) {
compiler.resolverFactory.hooks.resolveOptions
.for(resolverName)
.tap(WorkspaceResolvePlugin.name, handler);
}
}
}
2 changes: 1 addition & 1 deletion webpack/webpack-workspace-resolve-plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json",
"compilerOptions": {
"target": "ES2019",
"target": "ES2020",
"types": ["heft-jest", "node"]
}
}

0 comments on commit cca07c9

Please sign in to comment.