Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[workspace-resolve] Allow configuration of which resolvers to apply to #5074

Merged
merged 2 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}
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"]
}
}
Loading