A Webpack loader to restrict imports in ES and TypeScript
npm install restrict-imports-loaderA Webpack loader to restrict imports in ES and TypeScript.
```
npm install --save-dev restrict-imports-loader
NOTE: Only static imports are supported; see _Limitations_.
_See also the complete example repo._
Configuration example (webpack.config.js):
`javascript`
module.exports = {
// ...
module: {
rules: [
{
test: /\.tsx?$/,
include: path.resolve(__dirname, "src"),
use: [
{
loader: "ts-loader", // or babel-loader, etc
},
{
loader: "restrict-imports-loader",
options: {
severity: "error",
rules: [
{
restricted: /^lodash$/,
},
],
},
},
],
},
],
},
}
Source code (e.g. src/index.ts):
`typescript`
import * as ts from "typescript"; // OK
import * as _ from "lodash"; // error
import * as fp from "lodash/fp"; // OK (see "Restricting an entire package" for more info)
Webpack output:
`
ERROR in ./src/index.ts
Module build failed (from ../restrict-imports-loader/dist/index.js):
Found restricted imports:
• "lodash", imported on line 2:
import * as _ from "lodash";
`
#### severity
You can control what happens if a restricted import is found by setting the severity option to either "fatal" (stop compilation), "error" (emit error) or "warning" (emit warning).
The severity level can be overridden for individual rules; see below.
#### rules
Must be a list in which each element has a restricted property with a RegExp or function value.severity
Each rule can also override the defined for the loader.
Example:
`javascript`
{
loader: "restrict-imports-loader",
options: {
severity: "error",
rules: [
{
restricted: /^lodash$/,
// inherits severity: "error"
info: "Please import submodules instead of the full lodash package.",
},
{
restricted: /^typescript$/,
severity: "warning",
// no info specified; default is "Found restricted imports:"
},
],
},
},
##### Using a function as decider
If you provide a function as the restricted value, it must have the type
`typescript`
(string, webpack.loader.LoaderContext) => Promise
where the string parameter represents the import path in each import statement, e.g. typescript in import * as ts from "typescript";.
This way, you can use any algorithm you want to determine if an import should be restricted, possibly depending on the loader context.
In the example below (written in TypeScript), if decider is used as the restricted value, all imports from outside the project root directory are restricted.context
(The "project root directory" is whatever directory you've specified using Webpack's option, or, if not specified, the "current working directory" as seen from Webpack's perspective.)
`typescript
import { LoaderDecider } from "restrict-imports-loader";
const decider: LoaderDecider = (importPath, loaderContext) => new Promise((resolve, reject) => {
loaderContext.resolve(loaderContext.context, importPath, (err, result) => {
if (err === null) {
resolve(false === result.startsWith(loaderContext.rootContext));
} else {
reject(err.message);
}
});
});
`
#### detailedErrorMessages
By default, error messages include the faulty import statements exactly as written, as well as any extra info provided by the decider, for example:
`
Found restricted imports:
• "typescript", imported on line 1:
import * as _ from "typescript";
(resolved: node_modules/typescript/lib/typescript.js)
`
Setting detailedErrorMessages to false means that error messages will only include the import path and line number:
`
Found restricted imports:
• "typescript", imported on line 1
`
Note that Webpack will always show the file name (e.g. ERROR in ./src/main.ts).
If you want to restrict an entire package, including its submodules, you can use everythingInPackage for convenience and readability:
`javascript
const { everythingInPackage } = require("restrict-imports-loader");
module.exports = {
// ...
{
loader: "restrict-imports-loader",
options: {
severity: "error",
rules: [
{
restricted: everythingInPackage("lodash"),
},
],
},
},
};
`
Code:
`typescript`
import * as ts from "typescript"; // OK
import * as ld from "lodasher"; // OK
import * as _ from "lodash"; // error
import * as fp from "lodash/fp"; // error
Note: everythingInPackage is RegExp-based, so it can't prevent the programmer from importing the restricted package using a relative import:
`typescript`
import * as _ from "../node_modules/lodash"; // OK
You must use a function as decider if you want to prevent that.
See _Blacklisting or whitelisting directories_ for a convenient approach.
You can use everythingInside or everythingOutside to blacklist or whitelist, respectively, a set of absolute directories:
`typescript
const { everythingOutside } = require("restrict-imports-loader");
module.exports = {
// ...
{
loader: "restrict-imports-loader",
options: {
severity: "warning",
rules: [
{
restricted: everythingOutside([
path.resolve(__dirname, "node_modules"),
path.resolve(__dirname, "src"),
]),
info: Imports should resolve to 'node_modules' or 'src'. These do not:,`
},
],
},
},
};
You can restrict the number of consecutive ../s an import may contain..././../
( counts as two consecutive ../s.)
`typescript
const { climbingUpwardsMoreThan } = require("restrict-imports-loader");
module.exports = {
// ...
{
loader: "restrict-imports-loader",
options: {
severity: "warning",
rules: [
{
restricted: climbingUpwardsMoreThan(1),
info: These imports climb the directory tree excessively:,`
},
],
},
},
};
This example allows "../foo" but restricts "../../foo".
Only static ES2015 (ES6) imports are supported, for example:
* import {} from "typescript";import as ts from "typescript";
import ts from "typescript";
* import "typescript";
* export {} from "typescript";
* import ts = require("typescript");
* _(works only in TypeScript)_
Dynamic imports are not supported:
* const ts = require("typescript");const ts = import("typescript");
*
`bash``
npm install
npm run verify # build, lint and test