@rushstack/webpack-workspace-resolve-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +17 -0
- package/CHANGELOG.md +11 -0
- package/LICENSE +24 -0
- package/README.md +35 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/webpack-workspace-resolve-plugin.d.ts +130 -0
- package/lib/KnownDescriptionFilePlugin.d.ts +23 -0
- package/lib/KnownDescriptionFilePlugin.d.ts.map +1 -0
- package/lib/KnownDescriptionFilePlugin.js +95 -0
- package/lib/KnownDescriptionFilePlugin.js.map +1 -0
- package/lib/KnownPackageDependenciesPlugin.d.ts +22 -0
- package/lib/KnownPackageDependenciesPlugin.d.ts.map +1 -0
- package/lib/KnownPackageDependenciesPlugin.js +72 -0
- package/lib/KnownPackageDependenciesPlugin.js.map +1 -0
- package/lib/WorkspaceLayoutCache.d.ts +97 -0
- package/lib/WorkspaceLayoutCache.d.ts.map +1 -0
- package/lib/WorkspaceLayoutCache.js +86 -0
- package/lib/WorkspaceLayoutCache.js.map +1 -0
- package/lib/WorkspaceResolvePlugin.d.ts +24 -0
- package/lib/WorkspaceResolvePlugin.d.ts.map +1 -0
- package/lib/WorkspaceResolvePlugin.js +49 -0
- package/lib/WorkspaceResolvePlugin.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/package.json +40 -0
package/CHANGELOG.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rushstack/webpack-workspace-resolve-plugin",
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"tag": "@rushstack/webpack-workspace-resolve-plugin_v0.1.0",
|
|
7
|
+
"date": "Fri, 16 Aug 2024 00:11:49 GMT",
|
|
8
|
+
"comments": {
|
|
9
|
+
"minor": [
|
|
10
|
+
{
|
|
11
|
+
"comment": "Add plugin for more efficient import resolution in a monorepo with known structure. Optimizes lookup of the relevant `package.json` for a given path, and lookup of npm dependencies of the containing package."
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Change Log - @rushstack/webpack-workspace-resolve-plugin
|
|
2
|
+
|
|
3
|
+
This log was last generated on Fri, 16 Aug 2024 00:11:49 GMT and should not be manually modified.
|
|
4
|
+
|
|
5
|
+
## 0.1.0
|
|
6
|
+
Fri, 16 Aug 2024 00:11:49 GMT
|
|
7
|
+
|
|
8
|
+
### Minor changes
|
|
9
|
+
|
|
10
|
+
- Add plugin for more efficient import resolution in a monorepo with known structure. Optimizes lookup of the relevant `package.json` for a given path, and lookup of npm dependencies of the containing package.
|
|
11
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@rushstack/webpack-workspace-resolve-plugin
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
|
|
5
|
+
MIT License
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
8
|
+
a copy of this software and associated documentation files (the
|
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
13
|
+
the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be
|
|
16
|
+
included in all copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @rushstack/webpack-workspace-resolve-plugin
|
|
2
|
+
|
|
3
|
+
This package contains a plugin for webpack 5 that leverages a cache file generated from package manager metadata to greatly accelerate module resolution.
|
|
4
|
+
Local benchmarks have shown a savings of around 10% of build time for some fairly large closed source projects.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
`npm install @rushstack/webpack-workspace-resolve-plugin --save-dev`
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
This plugin is intended primarily for use in pnpm monorepos, but any tool that produces a strict package layout can be made compatible by generating the necessary cache file.
|
|
13
|
+
|
|
14
|
+
The cache file contains information about the locations of every `package.json` file known to the package manager (including those in subdirectories of packages), as well as the list of declared dependencies of each and where they can be found.
|
|
15
|
+
|
|
16
|
+
When using this plugin, the following options should be configured for your resolver:
|
|
17
|
+
- `symlinks: false` - Since the cache knows the symlinks for package dependencies, you can avoid the cost of testing for other symlinks unless you are using additional symlinks.
|
|
18
|
+
- `modules: []` - The cache should contain all information necessary to locate available dependencies for any arbitrary folder. If you need to allow resolution in other roots, you can add those, but omit `'node_modules'`.
|
|
19
|
+
|
|
20
|
+
## Limitations
|
|
21
|
+
|
|
22
|
+
This plugin depends on the presence of a cache file in the workspace to function. Data in this cache file is assumed not to change while the webpack process is running.
|
|
23
|
+
|
|
24
|
+
**Note:** Generating the cache file is not in the scope of this plugin.
|
|
25
|
+
|
|
26
|
+
This plugin does not currently support having subdirectory `package.json` files within workspace projects (e.g. for declaring `{ "type": "module" }` in mixed CommonJS/ESM packages).
|
|
27
|
+
This plugin does not work (well) with a hoisted node_modules installation layout.
|
|
28
|
+
|
|
29
|
+
## Links
|
|
30
|
+
|
|
31
|
+
- [CHANGELOG.md](
|
|
32
|
+
https://github.com/microsoft/rushstack/blob/main/webpack/webpack-workspace-resolve-plugin/CHANGELOG.md) - Find
|
|
33
|
+
out what's new in the latest version
|
|
34
|
+
|
|
35
|
+
`@rushstack/webpack5-workspace-resolve-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.47.6"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { Compiler } from 'webpack';
|
|
2
|
+
import { IPrefixMatch } from '@rushstack/lookup-by-path';
|
|
3
|
+
import { LookupByPath } from '@rushstack/lookup-by-path';
|
|
4
|
+
import type { WebpackPluginInstance } from 'webpack';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A function that normalizes a path to a platform-specific format (if needed).
|
|
8
|
+
* Will be undefined if the platform uses `/` as the path separator.
|
|
9
|
+
*
|
|
10
|
+
* @beta
|
|
11
|
+
*/
|
|
12
|
+
export declare type IPathNormalizationFunction = ((input: string) => string) | undefined;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A context for resolving dependencies in a workspace.
|
|
16
|
+
* @beta
|
|
17
|
+
*/
|
|
18
|
+
export declare interface IResolveContext {
|
|
19
|
+
/**
|
|
20
|
+
* The absolute path to the root folder of this context
|
|
21
|
+
*/
|
|
22
|
+
descriptionFileRoot: string;
|
|
23
|
+
/**
|
|
24
|
+
* Find the context that corresponds to a module specifier, when requested in the current context.
|
|
25
|
+
* @param request - The module specifier to resolve
|
|
26
|
+
*/
|
|
27
|
+
findDependency(request: string): IPrefixMatch<IResolveContext> | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The serialized form of the cache file. This file is expected to be generated by a separate tool from
|
|
32
|
+
* information known to the package manager. Namely, the dependency relationships between packages, and
|
|
33
|
+
* all the `package.json` files in the workspace (installed or local).
|
|
34
|
+
* @beta
|
|
35
|
+
*/
|
|
36
|
+
export declare interface IResolverCacheFile {
|
|
37
|
+
/**
|
|
38
|
+
* The ordered list of all contexts in the cache
|
|
39
|
+
*/
|
|
40
|
+
contexts: ISerializedResolveContext[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Information about a local or installed npm package.
|
|
45
|
+
* @beta
|
|
46
|
+
*/
|
|
47
|
+
export declare interface ISerializedResolveContext {
|
|
48
|
+
/**
|
|
49
|
+
* The path to the root folder of this context.
|
|
50
|
+
* This path is normalized to use `/` as the separator and should not end with a trailing `/`.
|
|
51
|
+
*/
|
|
52
|
+
root: string;
|
|
53
|
+
/**
|
|
54
|
+
* The name of this package. Used to inject a self-reference into the dependency map.
|
|
55
|
+
*/
|
|
56
|
+
name: string;
|
|
57
|
+
/**
|
|
58
|
+
* Map of declared dependencies to the ordinal of the corresponding context.
|
|
59
|
+
*/
|
|
60
|
+
deps: Record<string, number>;
|
|
61
|
+
/**
|
|
62
|
+
* Set of relative paths to nested `package.json` files within this context.
|
|
63
|
+
* These paths are normalized to use `/` as the separator and should not begin with a leading `./`.
|
|
64
|
+
*/
|
|
65
|
+
dirInfoFiles?: string[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Options for creating a `WorkspaceLayoutCache`.
|
|
70
|
+
* @beta
|
|
71
|
+
*/
|
|
72
|
+
export declare interface IWorkspaceLayoutCacheOptions {
|
|
73
|
+
/**
|
|
74
|
+
* The root folder of the workspace. All paths in the cache file are assumed to be relative to this folder.
|
|
75
|
+
*/
|
|
76
|
+
workspaceRoot: string;
|
|
77
|
+
/**
|
|
78
|
+
* The parsed cache data. File reading is left as an exercise for the caller.
|
|
79
|
+
*/
|
|
80
|
+
cacheData: IResolverCacheFile;
|
|
81
|
+
/**
|
|
82
|
+
* The directory separator used in the `path` field of the resolver inputs.
|
|
83
|
+
* Will usually be `path.sep`.
|
|
84
|
+
*/
|
|
85
|
+
resolverPathSeparator?: '/' | '\\';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Options for constructing a `WorkspaceResolvePlugin`.
|
|
90
|
+
*
|
|
91
|
+
* @beta
|
|
92
|
+
*/
|
|
93
|
+
export declare interface IWorkspaceResolvePluginOptions {
|
|
94
|
+
/**
|
|
95
|
+
* The cache of workspace layout information.
|
|
96
|
+
*/
|
|
97
|
+
cache: WorkspaceLayoutCache;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A cache of workspace layout information.
|
|
102
|
+
* @beta
|
|
103
|
+
*/
|
|
104
|
+
export declare class WorkspaceLayoutCache {
|
|
105
|
+
/**
|
|
106
|
+
* A lookup of context roots to their corresponding context objects
|
|
107
|
+
*/
|
|
108
|
+
readonly contextLookup: LookupByPath<IResolveContext>;
|
|
109
|
+
/**
|
|
110
|
+
* A weak map of package JSON contents to their corresponding context objects
|
|
111
|
+
*/
|
|
112
|
+
readonly contextForPackage: WeakMap<object, IResolveContext>;
|
|
113
|
+
readonly resolverPathSeparator: string;
|
|
114
|
+
readonly normalizeToSlash: IPathNormalizationFunction;
|
|
115
|
+
readonly normalizeToPlatform: IPathNormalizationFunction;
|
|
116
|
+
constructor(options: IWorkspaceLayoutCacheOptions);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* A Webpack plugin that optimizes package.json lookups and resolution of bare specifiers in a monorepo.
|
|
121
|
+
*
|
|
122
|
+
* @beta
|
|
123
|
+
*/
|
|
124
|
+
export declare class WorkspaceResolvePlugin implements WebpackPluginInstance {
|
|
125
|
+
private readonly _cache;
|
|
126
|
+
constructor(cache: WorkspaceLayoutCache);
|
|
127
|
+
apply(compiler: Compiler): void;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Resolver } from 'webpack';
|
|
2
|
+
import type { WorkspaceLayoutCache } from './WorkspaceLayoutCache';
|
|
3
|
+
/**
|
|
4
|
+
* A resolver plugin that optimizes locating the package.json file for a module.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare class KnownDescriptionFilePlugin {
|
|
9
|
+
readonly source: string;
|
|
10
|
+
readonly target: string;
|
|
11
|
+
private readonly _skipForContext;
|
|
12
|
+
private readonly _cache;
|
|
13
|
+
/**
|
|
14
|
+
* Constructs a new instance of `KnownDescriptionFilePlugin`.
|
|
15
|
+
* @param cache - The workspace layout cache
|
|
16
|
+
* @param source - The resolve step to hook into
|
|
17
|
+
* @param target - The resolve step to delegate to
|
|
18
|
+
* @param skipForContext - If true, don't apply this plugin if the resolver is configured to resolve to a context
|
|
19
|
+
*/
|
|
20
|
+
constructor(cache: WorkspaceLayoutCache, source: string, target: string, skipForContext?: boolean);
|
|
21
|
+
apply(resolver: Resolver): void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=KnownDescriptionFilePlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnownDescriptionFilePlugin.d.ts","sourceRoot":"","sources":["../src/KnownDescriptionFilePlugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,KAAK,EAAmB,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAIpF;;;;GAIG;AACH,qBAAa,0BAA0B;IACrC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAE9C;;;;;;OAMG;gBACgB,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO;IAOjG,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;CA2FvC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.KnownDescriptionFilePlugin = void 0;
|
|
6
|
+
/**
|
|
7
|
+
* A resolver plugin that optimizes locating the package.json file for a module.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
class KnownDescriptionFilePlugin {
|
|
12
|
+
/**
|
|
13
|
+
* Constructs a new instance of `KnownDescriptionFilePlugin`.
|
|
14
|
+
* @param cache - The workspace layout cache
|
|
15
|
+
* @param source - The resolve step to hook into
|
|
16
|
+
* @param target - The resolve step to delegate to
|
|
17
|
+
* @param skipForContext - If true, don't apply this plugin if the resolver is configured to resolve to a context
|
|
18
|
+
*/
|
|
19
|
+
constructor(cache, source, target, skipForContext) {
|
|
20
|
+
this.source = source;
|
|
21
|
+
this.target = target;
|
|
22
|
+
this._cache = cache;
|
|
23
|
+
this._skipForContext = !!skipForContext;
|
|
24
|
+
}
|
|
25
|
+
apply(resolver) {
|
|
26
|
+
var _a, _b;
|
|
27
|
+
if (this._skipForContext && resolver.options.resolveToContext) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const target = resolver.ensureHook(this.target);
|
|
31
|
+
const { fileSystem } = resolver;
|
|
32
|
+
function readDescriptionFileWithParse(descriptionFilePath, callback) {
|
|
33
|
+
fileSystem.readFile(descriptionFilePath, (err, data) => {
|
|
34
|
+
if (!(data === null || data === void 0 ? void 0 : data.length)) {
|
|
35
|
+
return callback(err);
|
|
36
|
+
}
|
|
37
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
38
|
+
callback(null, JSON.parse(data.toString()));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const readDescriptionFile = (_b = (_a = fileSystem.readJson) === null || _a === void 0 ? void 0 : _a.bind(fileSystem)) !== null && _b !== void 0 ? _b : readDescriptionFileWithParse;
|
|
42
|
+
resolver
|
|
43
|
+
.getHook(this.source)
|
|
44
|
+
.tapAsync(KnownDescriptionFilePlugin.name, (request, resolveContext, callback) => {
|
|
45
|
+
var _a, _b;
|
|
46
|
+
const { path } = request;
|
|
47
|
+
if (!path) {
|
|
48
|
+
// No request, nothing to do.
|
|
49
|
+
return callback();
|
|
50
|
+
}
|
|
51
|
+
const cache = this._cache;
|
|
52
|
+
const match = cache.contextLookup.findLongestPrefixMatch(path);
|
|
53
|
+
if (!match) {
|
|
54
|
+
// No description file available, proceed without.
|
|
55
|
+
return callback();
|
|
56
|
+
}
|
|
57
|
+
const remainingPath = path.slice(match.index);
|
|
58
|
+
const relativePath = `.${(_b = (_a = cache.normalizeToSlash) === null || _a === void 0 ? void 0 : _a.call(cache, remainingPath)) !== null && _b !== void 0 ? _b : remainingPath}`;
|
|
59
|
+
const descriptionFileRoot = `${path.slice(0, match.index)}`;
|
|
60
|
+
const descriptionFilePath = `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`;
|
|
61
|
+
const { contextForPackage } = cache;
|
|
62
|
+
readDescriptionFile(descriptionFilePath, (err, descriptionFileData) => {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
if (!descriptionFileData) {
|
|
65
|
+
(_a = resolveContext.missingDependencies) === null || _a === void 0 ? void 0 : _a.add(descriptionFilePath);
|
|
66
|
+
return callback(err);
|
|
67
|
+
}
|
|
68
|
+
(_b = resolveContext.fileDependencies) === null || _b === void 0 ? void 0 : _b.add(descriptionFilePath);
|
|
69
|
+
// Store the resolver context since a WeakMap lookup is cheaper than walking the tree again
|
|
70
|
+
contextForPackage.set(descriptionFileData, match.value);
|
|
71
|
+
// Since we don't allow any alternative processing of request, we can mutate it
|
|
72
|
+
// instead of cloning it.
|
|
73
|
+
request.descriptionFileRoot = descriptionFileRoot;
|
|
74
|
+
request.descriptionFilePath = descriptionFilePath;
|
|
75
|
+
request.descriptionFileData = descriptionFileData;
|
|
76
|
+
request.relativePath = relativePath;
|
|
77
|
+
// Delegate to the resolver step at `target`.
|
|
78
|
+
resolver.doResolve(target, request, 'using description file: ' + descriptionFilePath + ' (relative path: ' + relativePath + ')', resolveContext, (e, result) => {
|
|
79
|
+
if (e) {
|
|
80
|
+
return callback(e);
|
|
81
|
+
}
|
|
82
|
+
// Don't allow other processing
|
|
83
|
+
if (result === undefined) {
|
|
84
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
85
|
+
return callback(null, null);
|
|
86
|
+
}
|
|
87
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
88
|
+
callback(null, result);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.KnownDescriptionFilePlugin = KnownDescriptionFilePlugin;
|
|
95
|
+
//# sourceMappingURL=KnownDescriptionFilePlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnownDescriptionFilePlugin.js","sourceRoot":"","sources":["../src/KnownDescriptionFilePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { Resolver } from 'webpack';\nimport type { IPrefixMatch } from '@rushstack/lookup-by-path';\nimport type { IResolveContext, WorkspaceLayoutCache } from './WorkspaceLayoutCache';\n\ntype ResolveRequest = Parameters<Resolver['hooks']['resolveStep']['call']>[1];\n\n/**\n * A resolver plugin that optimizes locating the package.json file for a module.\n *\n * @internal\n */\nexport class KnownDescriptionFilePlugin {\n public readonly source: string;\n public readonly target: string;\n\n private readonly _skipForContext: boolean;\n private readonly _cache: WorkspaceLayoutCache;\n\n /**\n * Constructs a new instance of `KnownDescriptionFilePlugin`.\n * @param cache - The workspace layout cache\n * @param source - The resolve step to hook into\n * @param target - The resolve step to delegate to\n * @param skipForContext - If true, don't apply this plugin if the resolver is configured to resolve to a context\n */\n public constructor(cache: WorkspaceLayoutCache, source: string, target: string, skipForContext?: boolean) {\n this.source = source;\n this.target = target;\n this._cache = cache;\n this._skipForContext = !!skipForContext;\n }\n\n public apply(resolver: Resolver): void {\n if (this._skipForContext && resolver.options.resolveToContext) {\n return;\n }\n\n const target: ReturnType<Resolver['ensureHook']> = resolver.ensureHook(this.target);\n const { fileSystem } = resolver;\n\n function readDescriptionFileWithParse(\n descriptionFilePath: string,\n callback: (err: Error | null | undefined, data?: object) => void\n ): void {\n fileSystem.readFile(descriptionFilePath, (err: Error | null | undefined, data?: string | Buffer) => {\n if (!data?.length) {\n return callback(err);\n }\n // eslint-disable-next-line @rushstack/no-new-null\n callback(null, JSON.parse(data.toString()));\n });\n }\n\n const readDescriptionFile: (\n descriptionFilePath: string,\n cb: (err: Error | null | undefined, data?: object) => void\n ) => void = fileSystem.readJson?.bind(fileSystem) ?? readDescriptionFileWithParse;\n\n resolver\n .getHook(this.source)\n .tapAsync(KnownDescriptionFilePlugin.name, (request, resolveContext, callback) => {\n const { path } = request;\n if (!path) {\n // No request, nothing to do.\n return callback();\n }\n\n const cache: WorkspaceLayoutCache = this._cache;\n\n const match: IPrefixMatch<IResolveContext> | undefined =\n cache.contextLookup.findLongestPrefixMatch(path);\n if (!match) {\n // No description file available, proceed without.\n return callback();\n }\n\n const remainingPath: string = path.slice(match.index);\n const relativePath: string = `.${cache.normalizeToSlash?.(remainingPath) ?? remainingPath}`;\n const descriptionFileRoot: string = `${path.slice(0, match.index)}`;\n const descriptionFilePath: string = `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`;\n\n const { contextForPackage } = cache;\n\n readDescriptionFile(descriptionFilePath, (err, descriptionFileData) => {\n if (!descriptionFileData) {\n resolveContext.missingDependencies?.add(descriptionFilePath);\n return callback(err);\n }\n\n resolveContext.fileDependencies?.add(descriptionFilePath);\n // Store the resolver context since a WeakMap lookup is cheaper than walking the tree again\n contextForPackage.set(descriptionFileData, match.value);\n\n // Since we don't allow any alternative processing of request, we can mutate it\n // instead of cloning it.\n request.descriptionFileRoot = descriptionFileRoot;\n request.descriptionFilePath = descriptionFilePath;\n request.descriptionFileData = descriptionFileData;\n request.relativePath = relativePath;\n\n // Delegate to the resolver step at `target`.\n resolver.doResolve(\n target,\n request,\n 'using description file: ' + descriptionFilePath + ' (relative path: ' + relativePath + ')',\n resolveContext,\n (e: Error | undefined, result: ResolveRequest | undefined) => {\n if (e) {\n return callback(e);\n }\n\n // Don't allow other processing\n if (result === undefined) {\n // eslint-disable-next-line @rushstack/no-new-null\n return callback(null, null);\n }\n // eslint-disable-next-line @rushstack/no-new-null\n callback(null, result);\n }\n );\n });\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Resolver } from 'webpack';
|
|
2
|
+
import type { WorkspaceLayoutCache } from './WorkspaceLayoutCache';
|
|
3
|
+
/**
|
|
4
|
+
* A resolver plugin that optimizes resolving installed dependencies for the current package.
|
|
5
|
+
* Enforces strict resolution.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export declare class KnownPackageDependenciesPlugin {
|
|
10
|
+
readonly source: string;
|
|
11
|
+
readonly target: string;
|
|
12
|
+
private readonly _cache;
|
|
13
|
+
/**
|
|
14
|
+
* Constructs a new instance of `KnownPackageDependenciesPlugin`.
|
|
15
|
+
* @param cache - The workspace layout cache
|
|
16
|
+
* @param source - The resolve step to hook into
|
|
17
|
+
* @param target - The resolve step to delegate to
|
|
18
|
+
*/
|
|
19
|
+
constructor(cache: WorkspaceLayoutCache, source: string, target: string);
|
|
20
|
+
apply(resolver: Resolver): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=KnownPackageDependenciesPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnownPackageDependenciesPlugin.d.ts","sourceRoot":"","sources":["../src/KnownPackageDependenciesPlugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,KAAK,EAAmB,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAIpF;;;;;GAKG;AACH,qBAAa,8BAA8B;IACzC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAE9C;;;;;OAKG;gBACgB,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMvE,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;CAsDvC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.KnownPackageDependenciesPlugin = void 0;
|
|
6
|
+
/**
|
|
7
|
+
* A resolver plugin that optimizes resolving installed dependencies for the current package.
|
|
8
|
+
* Enforces strict resolution.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
class KnownPackageDependenciesPlugin {
|
|
13
|
+
/**
|
|
14
|
+
* Constructs a new instance of `KnownPackageDependenciesPlugin`.
|
|
15
|
+
* @param cache - The workspace layout cache
|
|
16
|
+
* @param source - The resolve step to hook into
|
|
17
|
+
* @param target - The resolve step to delegate to
|
|
18
|
+
*/
|
|
19
|
+
constructor(cache, source, target) {
|
|
20
|
+
this.source = source;
|
|
21
|
+
this.target = target;
|
|
22
|
+
this._cache = cache;
|
|
23
|
+
}
|
|
24
|
+
apply(resolver) {
|
|
25
|
+
const target = resolver.ensureHook(this.target);
|
|
26
|
+
resolver
|
|
27
|
+
.getHook(this.source)
|
|
28
|
+
.tapAsync(KnownPackageDependenciesPlugin.name, (request, resolveContext, callback) => {
|
|
29
|
+
var _a;
|
|
30
|
+
const { path, request: rawRequest } = request;
|
|
31
|
+
if (!path) {
|
|
32
|
+
return callback();
|
|
33
|
+
}
|
|
34
|
+
if (!rawRequest) {
|
|
35
|
+
return callback();
|
|
36
|
+
}
|
|
37
|
+
const { descriptionFileData } = request;
|
|
38
|
+
if (!descriptionFileData) {
|
|
39
|
+
return callback(new Error(`Expected descriptionFileData for ${path}`));
|
|
40
|
+
}
|
|
41
|
+
const cache = this._cache;
|
|
42
|
+
const context = cache.contextForPackage.get(descriptionFileData);
|
|
43
|
+
if (!context) {
|
|
44
|
+
return callback(new Error(`Expected context for ${request.descriptionFileRoot}`));
|
|
45
|
+
}
|
|
46
|
+
const match = context.findDependency(rawRequest);
|
|
47
|
+
if (!match) {
|
|
48
|
+
return callback();
|
|
49
|
+
}
|
|
50
|
+
const isPackageRoot = match.index === rawRequest.length;
|
|
51
|
+
const fullySpecified = isPackageRoot ? false : request.fullySpecified;
|
|
52
|
+
const remainingPath = isPackageRoot ? '.' : `.${rawRequest.slice(match.index)}`;
|
|
53
|
+
const relativePath = (remainingPath.length > 1 && ((_a = cache.normalizeToSlash) === null || _a === void 0 ? void 0 : _a.call(cache, remainingPath))) || remainingPath;
|
|
54
|
+
const { descriptionFileRoot } = match.value;
|
|
55
|
+
const obj = {
|
|
56
|
+
...request,
|
|
57
|
+
path: descriptionFileRoot,
|
|
58
|
+
descriptionFileRoot,
|
|
59
|
+
descriptionFileData: undefined,
|
|
60
|
+
descriptionFilePath: `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`,
|
|
61
|
+
relativePath: relativePath,
|
|
62
|
+
request: relativePath,
|
|
63
|
+
fullySpecified,
|
|
64
|
+
module: false
|
|
65
|
+
};
|
|
66
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
67
|
+
resolver.doResolve(target, obj, null, resolveContext, callback);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.KnownPackageDependenciesPlugin = KnownPackageDependenciesPlugin;
|
|
72
|
+
//# sourceMappingURL=KnownPackageDependenciesPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnownPackageDependenciesPlugin.js","sourceRoot":"","sources":["../src/KnownPackageDependenciesPlugin.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAQ3D;;;;;GAKG;AACH,MAAa,8BAA8B;IAMzC;;;;;OAKG;IACH,YAAmB,KAA2B,EAAE,MAAc,EAAE,MAAc;QAC5E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,KAAK,CAAC,QAAkB;QAC7B,MAAM,MAAM,GAAuC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEpF,QAAQ;aACL,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;aACpB,QAAQ,CAAC,8BAA8B,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE;;YACnF,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;YAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,QAAQ,EAAE,CAAC;YACpB,CAAC;YAED,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,OAAO,QAAQ,EAAE,CAAC;YACpB,CAAC;YAED,MAAM,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;YACxC,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACzB,OAAO,QAAQ,CAAC,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC,CAAC;YACzE,CAAC;YAED,MAAM,KAAK,GAAyB,IAAI,CAAC,MAAM,CAAC;YAEhD,MAAM,OAAO,GAAgC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YAC9F,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,QAAQ,CAAC,IAAI,KAAK,CAAC,wBAAwB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC;YACpF,CAAC;YAED,MAAM,KAAK,GAA8C,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;YAC5F,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,QAAQ,EAAE,CAAC;YACpB,CAAC;YAED,MAAM,aAAa,GAAY,KAAK,CAAC,KAAK,KAAK,UAAU,CAAC,MAAM,CAAC;YACjE,MAAM,cAAc,GAAwB,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;YAC3F,MAAM,aAAa,GAAW,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACxF,MAAM,YAAY,GAChB,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,KAAI,MAAA,KAAK,CAAC,gBAAgB,sDAAG,aAAa,CAAC,CAAA,CAAC,IAAI,aAAa,CAAC;YACzF,MAAM,EAAE,mBAAmB,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;YAC5C,MAAM,GAAG,GAAmB;gBAC1B,GAAG,OAAO;gBACV,IAAI,EAAE,mBAAmB;gBACzB,mBAAmB;gBACnB,mBAAmB,EAAE,SAAS;gBAC9B,mBAAmB,EAAE,GAAG,mBAAmB,GAAG,KAAK,CAAC,qBAAqB,cAAc;gBAEvF,YAAY,EAAE,YAAY;gBAC1B,OAAO,EAAE,YAAY;gBACrB,cAAc;gBACd,MAAM,EAAE,KAAK;aACd,CAAC;YACF,kDAAkD;YAClD,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACP,CAAC;CACF;AAxED,wEAwEC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { Resolver } from 'webpack';\nimport type { IPrefixMatch } from '@rushstack/lookup-by-path';\nimport type { IResolveContext, WorkspaceLayoutCache } from './WorkspaceLayoutCache';\n\ntype ResolveRequest = Parameters<Resolver['hooks']['resolveStep']['call']>[1];\n\n/**\n * A resolver plugin that optimizes resolving installed dependencies for the current package.\n * Enforces strict resolution.\n *\n * @internal\n */\nexport class KnownPackageDependenciesPlugin {\n public readonly source: string;\n public readonly target: string;\n\n private readonly _cache: WorkspaceLayoutCache;\n\n /**\n * Constructs a new instance of `KnownPackageDependenciesPlugin`.\n * @param cache - The workspace layout cache\n * @param source - The resolve step to hook into\n * @param target - The resolve step to delegate to\n */\n public constructor(cache: WorkspaceLayoutCache, source: string, target: string) {\n this.source = source;\n this.target = target;\n this._cache = cache;\n }\n\n public apply(resolver: Resolver): void {\n const target: ReturnType<Resolver['ensureHook']> = resolver.ensureHook(this.target);\n\n resolver\n .getHook(this.source)\n .tapAsync(KnownPackageDependenciesPlugin.name, (request, resolveContext, callback) => {\n const { path, request: rawRequest } = request;\n if (!path) {\n return callback();\n }\n\n if (!rawRequest) {\n return callback();\n }\n\n const { descriptionFileData } = request;\n if (!descriptionFileData) {\n return callback(new Error(`Expected descriptionFileData for ${path}`));\n }\n\n const cache: WorkspaceLayoutCache = this._cache;\n\n const context: IResolveContext | undefined = cache.contextForPackage.get(descriptionFileData);\n if (!context) {\n return callback(new Error(`Expected context for ${request.descriptionFileRoot}`));\n }\n\n const match: IPrefixMatch<IResolveContext> | undefined = context.findDependency(rawRequest);\n if (!match) {\n return callback();\n }\n\n const isPackageRoot: boolean = match.index === rawRequest.length;\n const fullySpecified: boolean | undefined = isPackageRoot ? false : request.fullySpecified;\n const remainingPath: string = isPackageRoot ? '.' : `.${rawRequest.slice(match.index)}`;\n const relativePath: string =\n (remainingPath.length > 1 && cache.normalizeToSlash?.(remainingPath)) || remainingPath;\n const { descriptionFileRoot } = match.value;\n const obj: ResolveRequest = {\n ...request,\n path: descriptionFileRoot,\n descriptionFileRoot,\n descriptionFileData: undefined,\n descriptionFilePath: `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`,\n\n relativePath: relativePath,\n request: relativePath,\n fullySpecified,\n module: false\n };\n // eslint-disable-next-line @rushstack/no-new-null\n resolver.doResolve(target, obj, null, resolveContext, callback);\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { LookupByPath, type IPrefixMatch } from '@rushstack/lookup-by-path';
|
|
2
|
+
/**
|
|
3
|
+
* Information about a local or installed npm package.
|
|
4
|
+
* @beta
|
|
5
|
+
*/
|
|
6
|
+
export interface ISerializedResolveContext {
|
|
7
|
+
/**
|
|
8
|
+
* The path to the root folder of this context.
|
|
9
|
+
* This path is normalized to use `/` as the separator and should not end with a trailing `/`.
|
|
10
|
+
*/
|
|
11
|
+
root: string;
|
|
12
|
+
/**
|
|
13
|
+
* The name of this package. Used to inject a self-reference into the dependency map.
|
|
14
|
+
*/
|
|
15
|
+
name: string;
|
|
16
|
+
/**
|
|
17
|
+
* Map of declared dependencies to the ordinal of the corresponding context.
|
|
18
|
+
*/
|
|
19
|
+
deps: Record<string, number>;
|
|
20
|
+
/**
|
|
21
|
+
* Set of relative paths to nested `package.json` files within this context.
|
|
22
|
+
* These paths are normalized to use `/` as the separator and should not begin with a leading `./`.
|
|
23
|
+
*/
|
|
24
|
+
dirInfoFiles?: string[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The serialized form of the cache file. This file is expected to be generated by a separate tool from
|
|
28
|
+
* information known to the package manager. Namely, the dependency relationships between packages, and
|
|
29
|
+
* all the `package.json` files in the workspace (installed or local).
|
|
30
|
+
* @beta
|
|
31
|
+
*/
|
|
32
|
+
export interface IResolverCacheFile {
|
|
33
|
+
/**
|
|
34
|
+
* The ordered list of all contexts in the cache
|
|
35
|
+
*/
|
|
36
|
+
contexts: ISerializedResolveContext[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A context for resolving dependencies in a workspace.
|
|
40
|
+
* @beta
|
|
41
|
+
*/
|
|
42
|
+
export interface IResolveContext {
|
|
43
|
+
/**
|
|
44
|
+
* The absolute path to the root folder of this context
|
|
45
|
+
*/
|
|
46
|
+
descriptionFileRoot: string;
|
|
47
|
+
/**
|
|
48
|
+
* Find the context that corresponds to a module specifier, when requested in the current context.
|
|
49
|
+
* @param request - The module specifier to resolve
|
|
50
|
+
*/
|
|
51
|
+
findDependency(request: string): IPrefixMatch<IResolveContext> | undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Options for creating a `WorkspaceLayoutCache`.
|
|
55
|
+
* @beta
|
|
56
|
+
*/
|
|
57
|
+
export interface IWorkspaceLayoutCacheOptions {
|
|
58
|
+
/**
|
|
59
|
+
* The root folder of the workspace. All paths in the cache file are assumed to be relative to this folder.
|
|
60
|
+
*/
|
|
61
|
+
workspaceRoot: string;
|
|
62
|
+
/**
|
|
63
|
+
* The parsed cache data. File reading is left as an exercise for the caller.
|
|
64
|
+
*/
|
|
65
|
+
cacheData: IResolverCacheFile;
|
|
66
|
+
/**
|
|
67
|
+
* The directory separator used in the `path` field of the resolver inputs.
|
|
68
|
+
* Will usually be `path.sep`.
|
|
69
|
+
*/
|
|
70
|
+
resolverPathSeparator?: '/' | '\\';
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A function that normalizes a path to a platform-specific format (if needed).
|
|
74
|
+
* Will be undefined if the platform uses `/` as the path separator.
|
|
75
|
+
*
|
|
76
|
+
* @beta
|
|
77
|
+
*/
|
|
78
|
+
export type IPathNormalizationFunction = ((input: string) => string) | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* A cache of workspace layout information.
|
|
81
|
+
* @beta
|
|
82
|
+
*/
|
|
83
|
+
export declare class WorkspaceLayoutCache {
|
|
84
|
+
/**
|
|
85
|
+
* A lookup of context roots to their corresponding context objects
|
|
86
|
+
*/
|
|
87
|
+
readonly contextLookup: LookupByPath<IResolveContext>;
|
|
88
|
+
/**
|
|
89
|
+
* A weak map of package JSON contents to their corresponding context objects
|
|
90
|
+
*/
|
|
91
|
+
readonly contextForPackage: WeakMap<object, IResolveContext>;
|
|
92
|
+
readonly resolverPathSeparator: string;
|
|
93
|
+
readonly normalizeToSlash: IPathNormalizationFunction;
|
|
94
|
+
readonly normalizeToPlatform: IPathNormalizationFunction;
|
|
95
|
+
constructor(options: IWorkspaceLayoutCacheOptions);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=WorkspaceLayoutCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceLayoutCache.d.ts","sourceRoot":"","sources":["../src/WorkspaceLayoutCache.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,QAAQ,EAAE,yBAAyB,EAAE,CAAC;CACvC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;CAC5E;AAED;;;GAGG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,SAAS,EAAE,kBAAkB,CAAC;IAC9B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;CACpC;AAED;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;AAUjF;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B;;OAEG;IACH,SAAgB,aAAa,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC;IAC7D;;OAEG;IACH,SAAgB,iBAAiB,EAAE,OAAO,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAEpE,SAAgB,qBAAqB,EAAE,MAAM,CAAC;IAC9C,SAAgB,gBAAgB,EAAE,0BAA0B,CAAC;IAC7D,SAAgB,mBAAmB,EAAE,0BAA0B,CAAC;gBAE7C,OAAO,EAAE,4BAA4B;CAoFzD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.WorkspaceLayoutCache = void 0;
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const lookup_by_path_1 = require("@rushstack/lookup-by-path");
|
|
8
|
+
function backslashToSlash(path) {
|
|
9
|
+
return path.replace(/\\/g, '/');
|
|
10
|
+
}
|
|
11
|
+
function slashToBackslash(path) {
|
|
12
|
+
return path.replace(/\//g, '\\');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A cache of workspace layout information.
|
|
16
|
+
* @beta
|
|
17
|
+
*/
|
|
18
|
+
class WorkspaceLayoutCache {
|
|
19
|
+
constructor(options) {
|
|
20
|
+
const { workspaceRoot, cacheData, resolverPathSeparator = node_path_1.sep } = options;
|
|
21
|
+
if (resolverPathSeparator !== '/' && resolverPathSeparator !== '\\') {
|
|
22
|
+
throw new Error(`Unsupported directory separator: ${resolverPathSeparator}`);
|
|
23
|
+
}
|
|
24
|
+
const resolveContexts = [];
|
|
25
|
+
const contextLookup = new lookup_by_path_1.LookupByPath(undefined, resolverPathSeparator);
|
|
26
|
+
this.contextLookup = contextLookup;
|
|
27
|
+
this.contextForPackage = new WeakMap();
|
|
28
|
+
const normalizeToSlash = resolverPathSeparator === '\\' ? backslashToSlash : undefined;
|
|
29
|
+
const normalizeToPlatform = resolverPathSeparator === '\\' ? slashToBackslash : undefined;
|
|
30
|
+
this.resolverPathSeparator = resolverPathSeparator;
|
|
31
|
+
this.normalizeToSlash = normalizeToSlash;
|
|
32
|
+
this.normalizeToPlatform = normalizeToPlatform;
|
|
33
|
+
// Internal class due to coupling to `resolveContexts`
|
|
34
|
+
class ResolveContext {
|
|
35
|
+
constructor(serialized) {
|
|
36
|
+
this._serialized = serialized;
|
|
37
|
+
this._descriptionFileRoot = undefined;
|
|
38
|
+
this._dependencies = undefined;
|
|
39
|
+
}
|
|
40
|
+
get descriptionFileRoot() {
|
|
41
|
+
var _a;
|
|
42
|
+
if (!this._descriptionFileRoot) {
|
|
43
|
+
this._descriptionFileRoot = `${workspaceRoot}${resolverPathSeparator}${(_a = normalizeToPlatform === null || normalizeToPlatform === void 0 ? void 0 : normalizeToPlatform(this._serialized.root)) !== null && _a !== void 0 ? _a : this._serialized.root}`;
|
|
44
|
+
}
|
|
45
|
+
return this._descriptionFileRoot;
|
|
46
|
+
}
|
|
47
|
+
findDependency(request) {
|
|
48
|
+
if (!this._dependencies) {
|
|
49
|
+
// Lazy initialize this object since most packages won't be requested.
|
|
50
|
+
const dependencies = new lookup_by_path_1.LookupByPath(undefined, '/');
|
|
51
|
+
// Handle the self-reference scenario
|
|
52
|
+
dependencies.setItem(this._serialized.name, this);
|
|
53
|
+
for (const [key, ordinal] of Object.entries(this._serialized.deps)) {
|
|
54
|
+
// This calls into the array of instances that is owned by WorkpaceLayoutCache
|
|
55
|
+
dependencies.setItem(key, resolveContexts[ordinal]);
|
|
56
|
+
}
|
|
57
|
+
this._dependencies = dependencies;
|
|
58
|
+
}
|
|
59
|
+
return this._dependencies.findLongestPrefixMatch(request);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
for (const serialized of cacheData.contexts) {
|
|
63
|
+
const resolveContext = new ResolveContext(serialized);
|
|
64
|
+
resolveContexts.push(resolveContext);
|
|
65
|
+
const descriptionFileRoot = resolveContext.descriptionFileRoot;
|
|
66
|
+
contextLookup.setItem(descriptionFileRoot, resolveContext);
|
|
67
|
+
// Handle nested package.json files. These may modify some properties, but the dependency resolution
|
|
68
|
+
// will match the original package root. Typically these are used to set the `type` field to `module`.
|
|
69
|
+
if (serialized.dirInfoFiles) {
|
|
70
|
+
for (const file of serialized.dirInfoFiles) {
|
|
71
|
+
contextLookup.setItemFromSegments(concat(
|
|
72
|
+
// Root is normalized to platform slashes
|
|
73
|
+
lookup_by_path_1.LookupByPath.iteratePathSegments(descriptionFileRoot, resolverPathSeparator),
|
|
74
|
+
// Subpaths are platform-agnostic
|
|
75
|
+
lookup_by_path_1.LookupByPath.iteratePathSegments(file, '/')), resolveContext);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.WorkspaceLayoutCache = WorkspaceLayoutCache;
|
|
82
|
+
function* concat(a, b) {
|
|
83
|
+
yield* a;
|
|
84
|
+
yield* b;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=WorkspaceLayoutCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceLayoutCache.js","sourceRoot":"","sources":["../src/WorkspaceLayoutCache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { sep as directorySeparator } from 'node:path';\n\nimport { LookupByPath, type IPrefixMatch } from '@rushstack/lookup-by-path';\n\n/**\n * Information about a local or installed npm package.\n * @beta\n */\nexport interface ISerializedResolveContext {\n /**\n * The path to the root folder of this context.\n * This path is normalized to use `/` as the separator and should not end with a trailing `/`.\n */\n root: string;\n /**\n * The name of this package. Used to inject a self-reference into the dependency map.\n */\n name: string;\n /**\n * Map of declared dependencies to the ordinal of the corresponding context.\n */\n deps: Record<string, number>;\n /**\n * Set of relative paths to nested `package.json` files within this context.\n * These paths are normalized to use `/` as the separator and should not begin with a leading `./`.\n */\n dirInfoFiles?: string[];\n}\n\n/**\n * The serialized form of the cache file. This file is expected to be generated by a separate tool from\n * information known to the package manager. Namely, the dependency relationships between packages, and\n * all the `package.json` files in the workspace (installed or local).\n * @beta\n */\nexport interface IResolverCacheFile {\n /**\n * The ordered list of all contexts in the cache\n */\n contexts: ISerializedResolveContext[];\n}\n\n/**\n * A context for resolving dependencies in a workspace.\n * @beta\n */\nexport interface IResolveContext {\n /**\n * The absolute path to the root folder of this context\n */\n descriptionFileRoot: string;\n /**\n * Find the context that corresponds to a module specifier, when requested in the current context.\n * @param request - The module specifier to resolve\n */\n findDependency(request: string): IPrefixMatch<IResolveContext> | undefined;\n}\n\n/**\n * Options for creating a `WorkspaceLayoutCache`.\n * @beta\n */\nexport interface IWorkspaceLayoutCacheOptions {\n /**\n * The root folder of the workspace. All paths in the cache file are assumed to be relative to this folder.\n */\n workspaceRoot: string;\n /**\n * The parsed cache data. File reading is left as an exercise for the caller.\n */\n cacheData: IResolverCacheFile;\n /**\n * The directory separator used in the `path` field of the resolver inputs.\n * Will usually be `path.sep`.\n */\n resolverPathSeparator?: '/' | '\\\\';\n}\n\n/**\n * A function that normalizes a path to a platform-specific format (if needed).\n * Will be undefined if the platform uses `/` as the path separator.\n *\n * @beta\n */\nexport type IPathNormalizationFunction = ((input: string) => string) | undefined;\n\nfunction backslashToSlash(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\nfunction slashToBackslash(path: string): string {\n return path.replace(/\\//g, '\\\\');\n}\n\n/**\n * A cache of workspace layout information.\n * @beta\n */\nexport class WorkspaceLayoutCache {\n /**\n * A lookup of context roots to their corresponding context objects\n */\n public readonly contextLookup: LookupByPath<IResolveContext>;\n /**\n * A weak map of package JSON contents to their corresponding context objects\n */\n public readonly contextForPackage: WeakMap<object, IResolveContext>;\n\n public readonly resolverPathSeparator: string;\n public readonly normalizeToSlash: IPathNormalizationFunction;\n public readonly normalizeToPlatform: IPathNormalizationFunction;\n\n public constructor(options: IWorkspaceLayoutCacheOptions) {\n const { workspaceRoot, cacheData, resolverPathSeparator = directorySeparator } = options;\n\n if (resolverPathSeparator !== '/' && resolverPathSeparator !== '\\\\') {\n throw new Error(`Unsupported directory separator: ${resolverPathSeparator}`);\n }\n\n const resolveContexts: IResolveContext[] = [];\n const contextLookup: LookupByPath<IResolveContext> = new LookupByPath(undefined, resolverPathSeparator);\n\n this.contextLookup = contextLookup;\n this.contextForPackage = new WeakMap<object, IResolveContext>();\n\n const normalizeToSlash: IPathNormalizationFunction =\n resolverPathSeparator === '\\\\' ? backslashToSlash : undefined;\n const normalizeToPlatform: IPathNormalizationFunction =\n resolverPathSeparator === '\\\\' ? slashToBackslash : undefined;\n\n this.resolverPathSeparator = resolverPathSeparator;\n this.normalizeToSlash = normalizeToSlash;\n this.normalizeToPlatform = normalizeToPlatform;\n\n // Internal class due to coupling to `resolveContexts`\n class ResolveContext implements IResolveContext {\n private readonly _serialized: ISerializedResolveContext;\n private _descriptionFileRoot: string | undefined;\n private _dependencies: LookupByPath<IResolveContext> | undefined;\n\n public constructor(serialized: ISerializedResolveContext) {\n this._serialized = serialized;\n this._descriptionFileRoot = undefined;\n this._dependencies = undefined;\n }\n\n public get descriptionFileRoot(): string {\n if (!this._descriptionFileRoot) {\n this._descriptionFileRoot = `${workspaceRoot}${resolverPathSeparator}${\n normalizeToPlatform?.(this._serialized.root) ?? this._serialized.root\n }`;\n }\n return this._descriptionFileRoot;\n }\n\n public findDependency(request: string): IPrefixMatch<IResolveContext> | undefined {\n if (!this._dependencies) {\n // Lazy initialize this object since most packages won't be requested.\n const dependencies: LookupByPath<IResolveContext> = new LookupByPath(undefined, '/');\n // Handle the self-reference scenario\n dependencies.setItem(this._serialized.name, this);\n for (const [key, ordinal] of Object.entries(this._serialized.deps)) {\n // This calls into the array of instances that is owned by WorkpaceLayoutCache\n dependencies.setItem(key, resolveContexts[ordinal]);\n }\n this._dependencies = dependencies;\n }\n\n return this._dependencies.findLongestPrefixMatch(request);\n }\n }\n\n for (const serialized of cacheData.contexts) {\n const resolveContext: IResolveContext = new ResolveContext(serialized);\n resolveContexts.push(resolveContext);\n\n const descriptionFileRoot: string = resolveContext.descriptionFileRoot;\n contextLookup.setItem(descriptionFileRoot, resolveContext);\n\n // Handle nested package.json files. These may modify some properties, but the dependency resolution\n // will match the original package root. Typically these are used to set the `type` field to `module`.\n if (serialized.dirInfoFiles) {\n for (const file of serialized.dirInfoFiles) {\n contextLookup.setItemFromSegments(\n concat<string>(\n // Root is normalized to platform slashes\n LookupByPath.iteratePathSegments(descriptionFileRoot, resolverPathSeparator),\n // Subpaths are platform-agnostic\n LookupByPath.iteratePathSegments(file, '/')\n ),\n resolveContext\n );\n }\n }\n }\n }\n}\n\nfunction* concat<T>(a: Iterable<T>, b: Iterable<T>): IterableIterator<T> {\n yield* a;\n yield* b;\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { WebpackPluginInstance, Compiler } from 'webpack';
|
|
2
|
+
import type { WorkspaceLayoutCache } from './WorkspaceLayoutCache';
|
|
3
|
+
/**
|
|
4
|
+
* Options for constructing a `WorkspaceResolvePlugin`.
|
|
5
|
+
*
|
|
6
|
+
* @beta
|
|
7
|
+
*/
|
|
8
|
+
export interface IWorkspaceResolvePluginOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The cache of workspace layout information.
|
|
11
|
+
*/
|
|
12
|
+
cache: WorkspaceLayoutCache;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A Webpack plugin that optimizes package.json lookups and resolution of bare specifiers in a monorepo.
|
|
16
|
+
*
|
|
17
|
+
* @beta
|
|
18
|
+
*/
|
|
19
|
+
export declare class WorkspaceResolvePlugin implements WebpackPluginInstance {
|
|
20
|
+
private readonly _cache;
|
|
21
|
+
constructor(cache: WorkspaceLayoutCache);
|
|
22
|
+
apply(compiler: Compiler): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=WorkspaceResolvePlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceResolvePlugin.d.ts","sourceRoot":"","sources":["../src/WorkspaceResolvePlugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAInE;;;;GAIG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,KAAK,EAAE,oBAAoB,CAAC;CAC7B;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,qBAAqB;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;gBAE3B,KAAK,EAAE,oBAAoB;IAIvC,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;CAgCvC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.WorkspaceResolvePlugin = void 0;
|
|
6
|
+
const KnownDescriptionFilePlugin_1 = require("./KnownDescriptionFilePlugin");
|
|
7
|
+
const KnownPackageDependenciesPlugin_1 = require("./KnownPackageDependenciesPlugin");
|
|
8
|
+
/**
|
|
9
|
+
* A Webpack plugin that optimizes package.json lookups and resolution of bare specifiers in a monorepo.
|
|
10
|
+
*
|
|
11
|
+
* @beta
|
|
12
|
+
*/
|
|
13
|
+
class WorkspaceResolvePlugin {
|
|
14
|
+
constructor(cache) {
|
|
15
|
+
this._cache = cache;
|
|
16
|
+
}
|
|
17
|
+
apply(compiler) {
|
|
18
|
+
compiler.resolverFactory.hooks.resolveOptions
|
|
19
|
+
.for('normal')
|
|
20
|
+
.tap(WorkspaceResolvePlugin.name, (resolveOptions) => {
|
|
21
|
+
var _a;
|
|
22
|
+
// Omit default `node_modules`
|
|
23
|
+
if (resolveOptions.modules) {
|
|
24
|
+
resolveOptions.modules = resolveOptions.modules.filter((modulePath) => {
|
|
25
|
+
return modulePath !== 'node_modules';
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
resolveOptions.modules = [];
|
|
30
|
+
}
|
|
31
|
+
const cache = this._cache;
|
|
32
|
+
(_a = resolveOptions.plugins) !== null && _a !== void 0 ? _a : (resolveOptions.plugins = []);
|
|
33
|
+
resolveOptions.plugins.push(
|
|
34
|
+
// Optimize identifying the package.json file for the issuer
|
|
35
|
+
new KnownDescriptionFilePlugin_1.KnownDescriptionFilePlugin(cache, 'parsed-resolve', 'described-resolve'),
|
|
36
|
+
// Optimize locating the installed dependencies of the current package
|
|
37
|
+
new KnownPackageDependenciesPlugin_1.KnownPackageDependenciesPlugin(cache, 'raw-module', 'resolve-as-module'),
|
|
38
|
+
// Optimize loading the package.json file for the destination package
|
|
39
|
+
new KnownDescriptionFilePlugin_1.KnownDescriptionFilePlugin(cache, 'relative', 'described-relative'),
|
|
40
|
+
// Optimize locating and loading nested package.json for a directory
|
|
41
|
+
new KnownDescriptionFilePlugin_1.KnownDescriptionFilePlugin(cache, 'undescribed-existing-directory', 'existing-directory', true),
|
|
42
|
+
// Optimize locating and loading nested package.json for a file
|
|
43
|
+
new KnownDescriptionFilePlugin_1.KnownDescriptionFilePlugin(cache, 'undescribed-raw-file', 'raw-file'));
|
|
44
|
+
return resolveOptions;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.WorkspaceResolvePlugin = WorkspaceResolvePlugin;
|
|
49
|
+
//# sourceMappingURL=WorkspaceResolvePlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceResolvePlugin.js","sourceRoot":"","sources":["../src/WorkspaceResolvePlugin.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAK3D,6EAA0E;AAC1E,qFAAkF;AAclF;;;;GAIG;AACH,MAAa,sBAAsB;IAGjC,YAAmB,KAA2B;QAC5C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,KAAK,CAAC,QAAkB;QAC7B,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,cAAc;aAC1C,GAAG,CAAC,QAAQ,CAAC;aACb,GAAG,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC,cAAc,EAAE,EAAE;;YACnD,8BAA8B;YAC9B,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;gBAC3B,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,UAAkB,EAAE,EAAE;oBAC5E,OAAO,UAAU,KAAK,cAAc,CAAC;gBACvC,CAAC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC;YAC9B,CAAC;YAED,MAAM,KAAK,GAAyB,IAAI,CAAC,MAAM,CAAC;YAEhD,MAAA,cAAc,CAAC,OAAO,oCAAtB,cAAc,CAAC,OAAO,GAAK,EAAE,EAAC;YAC9B,cAAc,CAAC,OAAO,CAAC,IAAI;YACzB,4DAA4D;YAC5D,IAAI,uDAA0B,CAAC,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,CAAC;YAC5E,sEAAsE;YACtE,IAAI,+DAA8B,CAAC,KAAK,EAAE,YAAY,EAAE,mBAAmB,CAAC;YAC5E,qEAAqE;YACrE,IAAI,uDAA0B,CAAC,KAAK,EAAE,UAAU,EAAE,oBAAoB,CAAC;YACvE,oEAAoE;YACpE,IAAI,uDAA0B,CAAC,KAAK,EAAE,gCAAgC,EAAE,oBAAoB,EAAE,IAAI,CAAC;YACnG,+DAA+D;YAC/D,IAAI,uDAA0B,CAAC,KAAK,EAAE,sBAAsB,EAAE,UAAU,CAAC,CAC1E,CAAC;YAEF,OAAO,cAAc,CAAC;QACxB,CAAC,CAAC,CAAC;IACP,CAAC;CACF;AAvCD,wDAuCC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { WebpackPluginInstance, Compiler } from 'webpack';\n\nimport type { WorkspaceLayoutCache } from './WorkspaceLayoutCache';\nimport { KnownDescriptionFilePlugin } from './KnownDescriptionFilePlugin';\nimport { KnownPackageDependenciesPlugin } from './KnownPackageDependenciesPlugin';\n\n/**\n * Options for constructing a `WorkspaceResolvePlugin`.\n *\n * @beta\n */\nexport interface IWorkspaceResolvePluginOptions {\n /**\n * The cache of workspace layout information.\n */\n cache: WorkspaceLayoutCache;\n}\n\n/**\n * A Webpack plugin that optimizes package.json lookups and resolution of bare specifiers in a monorepo.\n *\n * @beta\n */\nexport class WorkspaceResolvePlugin implements WebpackPluginInstance {\n private readonly _cache: WorkspaceLayoutCache;\n\n public constructor(cache: WorkspaceLayoutCache) {\n this._cache = cache;\n }\n\n public apply(compiler: Compiler): void {\n compiler.resolverFactory.hooks.resolveOptions\n .for('normal')\n .tap(WorkspaceResolvePlugin.name, (resolveOptions) => {\n // Omit default `node_modules`\n if (resolveOptions.modules) {\n resolveOptions.modules = resolveOptions.modules.filter((modulePath: string) => {\n return modulePath !== 'node_modules';\n });\n } else {\n resolveOptions.modules = [];\n }\n\n const cache: WorkspaceLayoutCache = this._cache;\n\n resolveOptions.plugins ??= [];\n resolveOptions.plugins.push(\n // Optimize identifying the package.json file for the issuer\n new KnownDescriptionFilePlugin(cache, 'parsed-resolve', 'described-resolve'),\n // Optimize locating the installed dependencies of the current package\n new KnownPackageDependenciesPlugin(cache, 'raw-module', 'resolve-as-module'),\n // Optimize loading the package.json file for the destination package\n new KnownDescriptionFilePlugin(cache, 'relative', 'described-relative'),\n // Optimize locating and loading nested package.json for a directory\n new KnownDescriptionFilePlugin(cache, 'undescribed-existing-directory', 'existing-directory', true),\n // Optimize locating and loading nested package.json for a file\n new KnownDescriptionFilePlugin(cache, 'undescribed-raw-file', 'raw-file')\n );\n\n return resolveOptions;\n });\n }\n}\n"]}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { WorkspaceResolvePlugin, type IWorkspaceResolvePluginOptions } from './WorkspaceResolvePlugin';
|
|
2
|
+
export { WorkspaceLayoutCache, type IPathNormalizationFunction, type IWorkspaceLayoutCacheOptions, type IResolveContext, type ISerializedResolveContext, type IResolverCacheFile } from './WorkspaceLayoutCache';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,KAAK,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AACvG,OAAO,EACL,oBAAoB,EACpB,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,EACjC,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.WorkspaceLayoutCache = exports.WorkspaceResolvePlugin = void 0;
|
|
6
|
+
var WorkspaceResolvePlugin_1 = require("./WorkspaceResolvePlugin");
|
|
7
|
+
Object.defineProperty(exports, "WorkspaceResolvePlugin", { enumerable: true, get: function () { return WorkspaceResolvePlugin_1.WorkspaceResolvePlugin; } });
|
|
8
|
+
var WorkspaceLayoutCache_1 = require("./WorkspaceLayoutCache");
|
|
9
|
+
Object.defineProperty(exports, "WorkspaceLayoutCache", { enumerable: true, get: function () { return WorkspaceLayoutCache_1.WorkspaceLayoutCache; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,mEAAuG;AAA9F,gIAAA,sBAAsB,OAAA;AAC/B,+DAOgC;AAN9B,4HAAA,oBAAoB,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nexport { WorkspaceResolvePlugin, type IWorkspaceResolvePluginOptions } from './WorkspaceResolvePlugin';\nexport {\n WorkspaceLayoutCache,\n type IPathNormalizationFunction,\n type IWorkspaceLayoutCacheOptions,\n type IResolveContext,\n type ISerializedResolveContext,\n type IResolverCacheFile\n} from './WorkspaceLayoutCache';\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rushstack/webpack-workspace-resolve-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "This plugin leverages workspace-level metadata to greatly accelerate module resolution.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "dist/webpack-workspace-resolve-plugin.d.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/microsoft/rushstack.git",
|
|
11
|
+
"directory": "webpack/webpack-workspace-resolve-plugin"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18.19.0"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"webpack": "^5.68.0",
|
|
18
|
+
"@types/node": "*"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@rushstack/lookup-by-path": "0.1.1"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"memfs": "3.4.3",
|
|
25
|
+
"webpack": "~5.82.1",
|
|
26
|
+
"@rushstack/heft": "0.66.26",
|
|
27
|
+
"local-node-rig": "1.0.0"
|
|
28
|
+
},
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"peerDependenciesMeta": {
|
|
31
|
+
"@types/node": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "heft build --clean",
|
|
37
|
+
"_phase:build": "heft run --only build -- --clean",
|
|
38
|
+
"_phase:test": "heft run --only test -- --clean"
|
|
39
|
+
}
|
|
40
|
+
}
|