Skip to content

Commit 2091c42

Browse files
authored
Merge pull request #182 from webpack/next
Improvements for new major version
2 parents 0529632 + 8d34198 commit 2091c42

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2499
-2127
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = {
1111
es6: true
1212
},
1313
parserOptions: {
14-
ecmaVersion: 2017
14+
ecmaVersion: 2018
1515
},
1616
rules: {
1717
"prettier/prettier": "error",

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/node_modules
22
/coverage
3+
/.nyc_output
34
*.log
45
.eslintcache

.travis.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
sudo: false
22
language: node_js
33
node_js:
4+
- "12"
5+
- "10"
46
- "8"
5-
- "6"
67
script: npm run travis
78

89
after_success:
9-
- cat ./coverage/lcov.info | node_modules/.bin/coveralls --verbose
10-
- cat ./coverage/coverage.json | node_modules/codecov.io/bin/codecov.io.js
11-
- rm -rf ./coverage
10+
- bash <(curl -s https://codecov.io/bash) -X gcov

README.md

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ Offers an async require.resolve function. It's highly configurable.
44

55
## Features
66

7-
* plugin system
8-
* provide a custom filesystem
9-
* sync and async node.js filesystems included
10-
7+
- plugin system
8+
- provide a custom filesystem
9+
- sync and async node.js filesystems included
1110

1211
## Getting Started
12+
1313
### Install
14+
1415
```sh
1516
# npm
1617
npm install enhanced-resolve
@@ -19,90 +20,96 @@ yarn add enhanced-resolve
1920
```
2021

2122
### Creating a Resolver
23+
2224
The easiest way to create a resolver is to use the `createResolver` function on `ResolveFactory`, along with one of the supplied File System implementations.
25+
2326
```js
24-
const {
25-
NodeJsInputFileSystem,
26-
CachedInputFileSystem,
27-
ResolverFactory
28-
} = require('enhanced-resolve');
27+
const fs = require("fs");
28+
const { CachedInputFileSystem, ResolverFactory } = require("enhanced-resolve");
2929

3030
// create a resolver
3131
const myResolver = ResolverFactory.createResolver({
32-
// Typical usage will consume the `NodeJsInputFileSystem` + `CachedInputFileSystem`, which wraps the Node.js `fs` wrapper to add resilience + caching.
33-
fileSystem: new CachedInputFileSystem(new NodeJsInputFileSystem(), 4000),
34-
extensions: ['.js', '.json']
35-
/* any other resolver options here. Options/defaults can be seen below */
32+
// Typical usage will consume the `fs` + `CachedInputFileSystem`, which wraps Node.js `fs` to add caching.
33+
fileSystem: new CachedInputFileSystem(fs, 4000),
34+
extensions: [".js", ".json"]
35+
/* any other resolver options here. Options/defaults can be seen below */
3636
});
3737

3838
// resolve a file with the new resolver
3939
const context = {};
4040
const resolveContext = {};
41-
const lookupStartPath = '/Users/webpack/some/root/dir';
42-
const request = './path/to-look-up.js';
43-
myResolver.resolve({}, lookupStartPath, request, resolveContext, (err/*Error*/, filepath/*string*/) => {
44-
// Do something with the path
41+
const lookupStartPath = "/Users/webpack/some/root/dir";
42+
const request = "./path/to-look-up.js";
43+
myResolver.resolve({}, lookupStartPath, request, resolveContext, (
44+
err /*Error*/,
45+
filepath /*string*/
46+
) => {
47+
// Do something with the path
4548
});
4649
```
4750

4851
For more examples creating different types resolvers (sync/async, context, etc) see `lib/node.js`.
52+
4953
#### Resolver Options
50-
| Field | Default | Description |
51-
| ------------------------ | --------------------------- | ---------------------------------------------------------------------------------- |
52-
| alias | [] | A list of module alias configurations or an object which maps key to value |
53-
| aliasFields | [] | A list of alias fields in description files |
54-
| cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key |
55-
| descriptionFiles | ["package.json"] | A list of description files to read from |
56-
| enforceExtension | false | Enforce that a extension from extensions must be used |
57-
| enforceModuleExtension | false | Enforce that a extension from moduleExtensions must be used |
58-
| extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files |
59-
| mainFields | ["main"] | A list of main fields in description files |
60-
| mainFiles | ["index"] | A list of main files in directories |
61-
| modules | ["node_modules"] | A list of directories to resolve modules from, can be absolute path or folder name |
62-
| unsafeCache | false | Use this cache object to unsafely cache the successful requests |
63-
| plugins | [] | A list of additional resolve plugins which should be applied |
64-
| symlinks | true | Whether to resolve symlinks to their symlinked location |
65-
| cachePredicate | function() { return true }; | A function which decides whether a request should be cached or not. An object is passed to the function with `path` and `request` properties. |
66-
| moduleExtensions | [] | A list of module extensions which should be tried for modules |
67-
| resolveToContext | false | Resolve to a context instead of a file |
68-
| fileSystem | | The file system which should be used |
69-
| resolver | undefined | A prepared Resolver to which the plugins are attached |
54+
55+
| Field | Default | Description |
56+
| ---------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
57+
| alias | [] | A list of module alias configurations or an object which maps key to value |
58+
| aliasFields | [] | A list of alias fields in description files |
59+
| cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key |
60+
| descriptionFiles | ["package.json"] | A list of description files to read from |
61+
| enforceExtension | false | Enforce that a extension from extensions must be used |
62+
| extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files |
63+
| mainFields | ["main"] | A list of main fields in description files |
64+
| mainFiles | ["index"] | A list of main files in directories |
65+
| modules | ["node_modules"] | A list of directories to resolve modules from, can be absolute path or folder name |
66+
| unsafeCache | false | Use this cache object to unsafely cache the successful requests |
67+
| plugins | [] | A list of additional resolve plugins which should be applied |
68+
| symlinks | true | Whether to resolve symlinks to their symlinked location |
69+
| cachePredicate | function() { return true }; | A function which decides whether a request should be cached or not. An object is passed to the function with `path` and `request` properties. |
70+
| resolveToContext | false | Resolve to a context instead of a file |
71+
| fileSystem | | The file system which should be used |
72+
| resolver | undefined | A prepared Resolver to which the plugins are attached |
7073

7174
## Plugins
75+
7276
Similar to `webpack`, the core of `enhanced-resolve` functionality is implemented as individual plugins that are executed using [`Tapable`](https://github.com/webpack/tapable). These plugins can extend the functionality of the library, adding other ways for files/contexts to be resolved.
7377

7478
A plugin should be a `class` (or its ES5 equivalent) with an `apply` method. The `apply` method will receive a `resolver` instance, that can be used to hook in to the event system.
7579

7680
### Plugin Boilerplate
81+
7782
```js
7883
class MyResolverPlugin {
79-
constructor(source, target) {
80-
this.source = source;
81-
this.target = target;
82-
}
83-
84-
apply(resolver) {
85-
const target = resolver.ensureHook(this.target);
86-
resolver.getHook(this.source).tapAsync("MyResolverPlugin", (request, resolveContext, callback) => {
87-
// Any logic you need to create a new `request` can go here
88-
resolver.doResolve(target, request, null, resolveContext, callback);
89-
});
90-
}
84+
constructor(source, target) {
85+
this.source = source;
86+
this.target = target;
87+
}
88+
89+
apply(resolver) {
90+
const target = resolver.ensureHook(this.target);
91+
resolver
92+
.getHook(this.source)
93+
.tapAsync("MyResolverPlugin", (request, resolveContext, callback) => {
94+
// Any logic you need to create a new `request` can go here
95+
resolver.doResolve(target, request, null, resolveContext, callback);
96+
});
97+
}
9198
}
9299
```
93100

94101
Plugins are executed in a pipeline, and register which event they should be executed before/after. In the example above, `source` is the name of the event that starts the pipeline, and `target` is what event this plugin should fire, which is what continues the execution of the pipeline. For an example of how these different plugin events create a chain, see `lib/ResolverFactory.js`, in the `//// pipeline ////` section.
95102

96103
## Tests
97104

98-
``` javascript
105+
```javascript
99106
npm test
100107
```
101108

102109
[![Build Status](https://secure.travis-ci.org/webpack/enhanced-resolve.png?branch=master)](http://travis-ci.org/webpack/enhanced-resolve)
103110

104-
105111
## Passing options from webpack
112+
106113
If you are using `webpack`, and you want to pass custom options to `enhanced-resolve`, the options are passed from the `resolve` key of your webpack configuration e.g.:
107114

108115
```

lib/AliasFieldPlugin.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ module.exports = class AliasFieldPlugin {
4141
if (data === innerRequest) return callback();
4242
if (data === undefined) return callback();
4343
if (data === false) {
44-
const ignoreObj = Object.assign({}, request, {
44+
const ignoreObj = {
45+
...request,
4546
path: false
46-
});
47+
};
4748
return callback(null, ignoreObj);
4849
}
49-
const obj = Object.assign({}, request, {
50+
const obj = {
51+
...request,
5052
path: request.descriptionFileRoot,
5153
request: data
52-
});
54+
};
5355
resolver.doResolve(
5456
target,
5557
obj,

lib/AliasPlugin.js

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,7 @@
44
*/
55
"use strict";
66

7-
function startsWith(string, searchString) {
8-
const stringLength = string.length;
9-
const searchLength = searchString.length;
10-
11-
// early out if the search length is greater than the search string
12-
if (searchLength > stringLength) {
13-
return false;
14-
}
15-
let index = -1;
16-
while (++index < searchLength) {
17-
if (string.charCodeAt(index) !== searchString.charCodeAt(index)) {
18-
return false;
19-
}
20-
}
21-
return true;
22-
}
7+
const forEachBail = require("./forEachBail");
238

249
module.exports = class AliasPlugin {
2510
constructor(source, options, target) {
@@ -35,43 +20,68 @@ module.exports = class AliasPlugin {
3520
.tapAsync("AliasPlugin", (request, resolveContext, callback) => {
3621
const innerRequest = request.request || request.path;
3722
if (!innerRequest) return callback();
38-
for (const item of this.options) {
39-
if (
40-
innerRequest === item.name ||
41-
(!item.onlyModule && startsWith(innerRequest, item.name + "/"))
42-
) {
23+
forEachBail(
24+
this.options,
25+
(item, callback) => {
26+
let shouldStop = false;
4327
if (
44-
innerRequest !== item.alias &&
45-
!startsWith(innerRequest, item.alias + "/")
28+
innerRequest === item.name ||
29+
(!item.onlyModule && innerRequest.startsWith(item.name + "/"))
4630
) {
47-
const newRequestStr =
48-
item.alias + innerRequest.substr(item.name.length);
49-
const obj = Object.assign({}, request, {
50-
request: newRequestStr
51-
});
52-
return resolver.doResolve(
53-
target,
54-
obj,
55-
"aliased with mapping '" +
56-
item.name +
57-
"': '" +
58-
item.alias +
59-
"' to '" +
60-
newRequestStr +
61-
"'",
62-
resolveContext,
63-
(err, result) => {
64-
if (err) return callback(err);
65-
66-
// Don't allow other aliasing or raw request
67-
if (result === undefined) return callback(null, null);
68-
callback(null, result);
31+
const remainingRequest = innerRequest.substr(item.name.length);
32+
const resolveWithAlias = (alias, callback) => {
33+
if (
34+
innerRequest !== alias &&
35+
!innerRequest.startsWith(alias + "/")
36+
) {
37+
shouldStop = true;
38+
const newRequestStr = alias + remainingRequest;
39+
const obj = {
40+
...request,
41+
request: newRequestStr
42+
};
43+
return resolver.doResolve(
44+
target,
45+
obj,
46+
"aliased with mapping '" +
47+
item.name +
48+
"': '" +
49+
alias +
50+
"' to '" +
51+
newRequestStr +
52+
"'",
53+
resolveContext,
54+
(err, result) => {
55+
if (err) return callback(err);
56+
if (result) return callback(null, result);
57+
return callback();
58+
}
59+
);
6960
}
70-
);
61+
return callback();
62+
};
63+
const stoppingCallback = (err, result) => {
64+
if (err) return callback(err);
65+
66+
if (result) return callback(null, result);
67+
// Don't allow other aliasing or raw request
68+
if (shouldStop) return callback(null, null);
69+
return callback();
70+
};
71+
if (Array.isArray(item.alias)) {
72+
return forEachBail(
73+
item.alias,
74+
resolveWithAlias,
75+
stoppingCallback
76+
);
77+
} else {
78+
return resolveWithAlias(item.alias, stoppingCallback);
79+
}
7180
}
72-
}
73-
}
74-
return callback();
81+
return callback();
82+
},
83+
callback
84+
);
7585
});
7686
}
7787
};

lib/AppendPlugin.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ module.exports = class AppendPlugin {
1616
resolver
1717
.getHook(this.source)
1818
.tapAsync("AppendPlugin", (request, resolveContext, callback) => {
19-
const obj = Object.assign({}, request, {
19+
const obj = {
20+
...request,
2021
path: request.path + this.appending,
2122
relativePath:
2223
request.relativePath && request.relativePath + this.appending
23-
});
24+
};
2425
resolver.doResolve(
2526
target,
2627
obj,

lib/CloneBasenamePlugin.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ module.exports = class CloneBasenamePlugin {
1919
.tapAsync("CloneBasenamePlugin", (request, resolveContext, callback) => {
2020
const filename = basename(request.path);
2121
const filePath = resolver.join(request.path, filename);
22-
const obj = Object.assign({}, request, {
22+
const obj = {
23+
...request,
2324
path: filePath,
2425
relativePath:
2526
request.relativePath &&
2627
resolver.join(request.relativePath, filename)
27-
});
28+
};
2829
resolver.doResolve(
2930
target,
3031
obj,

0 commit comments

Comments
 (0)