update
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 3.0.0 (2021-04-21)
|
||||
### Added
|
||||
- Excluding Webpack 5 module federation (automatically adding to allowlist)
|
||||
|
||||
### Changed
|
||||
- Better arguments handling for the exported function
|
||||
- Changed code syntax to ES6
|
||||
|
||||
### Removed
|
||||
- Removed support for Node < 6
|
||||
|
||||
## 2.5.2 (2020-08-24)
|
||||
### Changed
|
||||
- Changed exported function signature - to remove deprecation notice when used in Webpack 5
|
||||
|
||||
## 2.5.0 (2020-07-12)
|
||||
### Added
|
||||
- Options validation - throwing an error when using a mispell of one of the options
|
||||
+27
-9
@@ -18,7 +18,7 @@ npm install webpack-node-externals --save-dev
|
||||
|
||||
In your `webpack.config.js`:
|
||||
```js
|
||||
var nodeExternals = require('webpack-node-externals');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
...
|
||||
module.exports = {
|
||||
...
|
||||
@@ -29,6 +29,20 @@ module.exports = {
|
||||
```
|
||||
And that's it. All node modules will no longer be bundled but will be left as `require('module')`.
|
||||
|
||||
**Note**: For Webpack 5, replace `target: 'node'` with the `externalsPreset` object:
|
||||
```js
|
||||
// Webpack 5
|
||||
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
...
|
||||
module.exports = {
|
||||
...
|
||||
externalsPresets: { node: true }, // in order to ignore built-in modules like path, fs, etc.
|
||||
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
## Detailed overview
|
||||
### Description
|
||||
This library scans the `node_modules` folder for all node_modules names, and builds an *externals* function that tells Webpack not to bundle those modules, or any sub-modules of theirs.
|
||||
@@ -36,9 +50,9 @@ This library scans the `node_modules` folder for all node_modules names, and bui
|
||||
### Configuration
|
||||
This library accepts an `options` object.
|
||||
|
||||
#### `options.whitelist (=[])`
|
||||
An array for the `externals` to whitelist, so they **will** be included in the bundle. Can accept exact strings (`'module_name'`), regex patterns (`/^module_name/`), or a function that accepts the module name and returns whether it should be included.
|
||||
<br/>**Important** - if you have set aliases in your webpack config with the exact same names as modules in *node_modules*, you need to whitelist them so Webpack will know they should be bundled.
|
||||
#### `options.allowlist (=[])`
|
||||
An array for the `externals` to allow, so they **will** be included in the bundle. Can accept exact strings (`'module_name'`), regex patterns (`/^module_name/`), or a function that accepts the module name and returns whether it should be included.
|
||||
<br/>**Important** - if you have set aliases in your webpack config with the exact same names as modules in *node_modules*, you need to allowlist them so Webpack will know they should be bundled.
|
||||
|
||||
#### `options.importType (='commonjs')`
|
||||
The method in which unbundled modules will be required in the code. Best to leave as `commonjs` for node modules.
|
||||
@@ -52,6 +66,9 @@ options.importType = function (moduleName) {
|
||||
#### `options.modulesDir (='node_modules')`
|
||||
The folder in which to search for the node modules.
|
||||
|
||||
#### `options.additionalModuleDirs (='[]')`
|
||||
Additional folders to look for node modules.
|
||||
|
||||
#### `options.modulesFromFile (=false)`
|
||||
Read the modules from the `package.json` file instead of the `node_modules` folder.
|
||||
<br/>Accepts a boolean or a configuration object:
|
||||
@@ -60,8 +77,9 @@ Read the modules from the `package.json` file instead of the `node_modules` fold
|
||||
modulesFromFile: true,
|
||||
/* or */
|
||||
modulesFromFile: {
|
||||
exclude: [/* sections to exclude, i.e 'devDependencies' */],
|
||||
include: [/* sections to explicitly include, i.e only 'dependencies' */]
|
||||
fileName: /* path to package.json to read from */,
|
||||
includeInBundle: [/* whole sections to include in the bundle, i.e 'devDependencies' */],
|
||||
excludeFromBundle: [/* whole sections to explicitly exclude from the bundle, i.e only 'dependencies' */]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -75,7 +93,7 @@ module.exports = {
|
||||
target: 'node', // important in order not to bundle built-in modules like path, fs, etc.
|
||||
externals: [nodeExternals({
|
||||
// this WILL include `jquery` and `webpack/hot/dev-server` in the bundle, as well as `lodash/*`
|
||||
whitelist: ['jquery', 'webpack/hot/dev-server', /^lodash/]
|
||||
allowlist: ['jquery', 'webpack/hot/dev-server', /^lodash/]
|
||||
})],
|
||||
...
|
||||
};
|
||||
@@ -99,12 +117,12 @@ However, this will leave unbundled **all non-relative requires**, so it does not
|
||||
This library scans the `node_modules` folder, so it only leaves unbundled the actual node modules that are being used.
|
||||
|
||||
#### How can I bundle required assets (i.e css files) from node_modules?
|
||||
Using the `whitelist` option, this is possible. We can simply tell Webpack to bundle all files with extensions that are not js/jsx/json, using this [regex](https://regexper.com/#%5C.(%3F!(%3F%3Ajs%7Cjson)%24).%7B1%2C5%7D%24):
|
||||
Using the `allowlist` option, this is possible. We can simply tell Webpack to bundle all files with extensions that are not js/jsx/json, using this [regex](https://regexper.com/#%5C.(%3F!(%3F%3Ajs%7Cjson)%24).%7B1%2C5%7D%24):
|
||||
```js
|
||||
...
|
||||
nodeExternals({
|
||||
// load non-javascript files with extensions, presumably via loaders
|
||||
whitelist: [/\.(?!(?:jsx?|json)$).{1,5}$/i],
|
||||
allowlist: [/\.(?!(?:jsx?|json)$).{1,5}$/i],
|
||||
}),
|
||||
...
|
||||
```
|
||||
|
||||
+52
-18
@@ -1,10 +1,13 @@
|
||||
var utils = require('./utils');
|
||||
const utils = require('./utils');
|
||||
|
||||
var scopedModuleRegex = new RegExp('@[a-zA-Z0-9][\\w-.]+\/[a-zA-Z0-9][\\w-.]+([a-zA-Z0-9.\/]+)?', 'g');
|
||||
const scopedModuleRegex = new RegExp(
|
||||
'@[a-zA-Z0-9][\\w-.]+/[a-zA-Z0-9][\\w-.]+([a-zA-Z0-9./]+)?',
|
||||
'g'
|
||||
);
|
||||
|
||||
function getModuleName(request, includeAbsolutePaths) {
|
||||
var req = request;
|
||||
var delimiter = '/';
|
||||
let req = request;
|
||||
const delimiter = '/';
|
||||
|
||||
if (includeAbsolutePaths) {
|
||||
req = req.replace(/^.*?\/node_modules\//, '');
|
||||
@@ -20,12 +23,23 @@ function getModuleName(request, includeAbsolutePaths) {
|
||||
|
||||
module.exports = function nodeExternals(options) {
|
||||
options = options || {};
|
||||
var whitelist = [].concat(options.whitelist || []);
|
||||
var binaryDirs = [].concat(options.binaryDirs || ['.bin']);
|
||||
var importType = options.importType || 'commonjs';
|
||||
var modulesDir = options.modulesDir || 'node_modules';
|
||||
var modulesFromFile = !!options.modulesFromFile;
|
||||
var includeAbsolutePaths = !!options.includeAbsolutePaths;
|
||||
const mistakes = utils.validateOptions(options) || [];
|
||||
if (mistakes.length) {
|
||||
mistakes.forEach((mistake) => {
|
||||
utils.error(mistakes.map((mistake) => mistake.message));
|
||||
utils.log(mistake.message);
|
||||
});
|
||||
}
|
||||
const webpackInternalAllowlist = [/^webpack\/container\/reference\//];
|
||||
const allowlist = []
|
||||
.concat(webpackInternalAllowlist)
|
||||
.concat(options.allowlist || []);
|
||||
const binaryDirs = [].concat(options.binaryDirs || ['.bin']);
|
||||
const importType = options.importType || 'commonjs';
|
||||
const modulesDir = options.modulesDir || 'node_modules';
|
||||
const modulesFromFile = !!options.modulesFromFile;
|
||||
const includeAbsolutePaths = !!options.includeAbsolutePaths;
|
||||
const additionalModuleDirs = options.additionalModuleDirs || [];
|
||||
|
||||
// helper function
|
||||
function isNotBinary(x) {
|
||||
@@ -33,19 +47,39 @@ module.exports = function nodeExternals(options) {
|
||||
}
|
||||
|
||||
// create the node modules list
|
||||
var nodeModules = modulesFromFile ? utils.readFromPackageJson(options.modulesFromFile) : utils.readDir(modulesDir).filter(isNotBinary);
|
||||
let nodeModules = modulesFromFile
|
||||
? utils.readFromPackageJson(options.modulesFromFile)
|
||||
: utils.readDir(modulesDir).filter(isNotBinary);
|
||||
additionalModuleDirs.forEach(function (additionalDirectory) {
|
||||
nodeModules = nodeModules.concat(
|
||||
utils.readDir(additionalDirectory).filter(isNotBinary)
|
||||
);
|
||||
});
|
||||
|
||||
// return an externals function
|
||||
return function(context, request, callback){
|
||||
var moduleName = getModuleName(request, includeAbsolutePaths);
|
||||
if (utils.contains(nodeModules, moduleName) && !utils.containsPattern(whitelist, request)) {
|
||||
return function (...args) {
|
||||
const [arg1, arg2, arg3] = args;
|
||||
// let context = arg1;
|
||||
let request = arg2;
|
||||
let callback = arg3;
|
||||
// in case of webpack 5
|
||||
if (arg1 && arg1.context && arg1.request) {
|
||||
// context = arg1.context;
|
||||
request = arg1.request;
|
||||
callback = arg2;
|
||||
}
|
||||
const moduleName = getModuleName(request, includeAbsolutePaths);
|
||||
if (
|
||||
utils.contains(nodeModules, moduleName) &&
|
||||
!utils.containsPattern(allowlist, request)
|
||||
) {
|
||||
if (typeof importType === 'function') {
|
||||
return callback(null, importType(request));
|
||||
}
|
||||
// mark this module as external
|
||||
// https://webpack.js.org/configuration/externals/
|
||||
return callback(null, importType + " " + request);
|
||||
};
|
||||
return callback(null, importType + ' ' + request);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
+19
-14
@@ -1,32 +1,32 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"webpack-node-externals@1.7.2",
|
||||
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
|
||||
"webpack-node-externals@3.0.0",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "webpack-node-externals@1.7.2",
|
||||
"_id": "webpack-node-externals@1.7.2",
|
||||
"_from": "webpack-node-externals@3.0.0",
|
||||
"_id": "webpack-node-externals@3.0.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==",
|
||||
"_integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==",
|
||||
"_location": "/webpack-node-externals",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "webpack-node-externals@1.7.2",
|
||||
"raw": "webpack-node-externals@3.0.0",
|
||||
"name": "webpack-node-externals",
|
||||
"escapedName": "webpack-node-externals",
|
||||
"rawSpec": "1.7.2",
|
||||
"rawSpec": "3.0.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.7.2"
|
||||
"fetchSpec": "3.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@nuxt/webpack"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz",
|
||||
"_spec": "1.7.2",
|
||||
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
|
||||
"_resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz",
|
||||
"_spec": "3.0.0",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "Liad Yosef",
|
||||
"url": "https://github.com/liady"
|
||||
@@ -38,10 +38,15 @@
|
||||
"description": "Easily exclude node_modules in Webpack bundle",
|
||||
"devDependencies": {
|
||||
"chai": "^3.5.0",
|
||||
"eslint": "^7.7.0",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"mocha": "^2.5.3",
|
||||
"mock-fs": "^4.4.2",
|
||||
"mock-fs": "^4.12.0",
|
||||
"ncp": "^2.0.0",
|
||||
"webpack": "^1.13.1"
|
||||
"webpack": "^4.44.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
@@ -69,5 +74,5 @@
|
||||
"unit": "mocha --colors ./test/*.spec.js",
|
||||
"unit-watch": "mocha --colors -w ./test/*.spec.js"
|
||||
},
|
||||
"version": "1.7.2"
|
||||
"version": "3.0.0"
|
||||
}
|
||||
|
||||
+110
-43
@@ -1,79 +1,146 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
exports.contains = function contains(arr, val) {
|
||||
return arr && arr.indexOf(val) !== -1;
|
||||
}
|
||||
};
|
||||
|
||||
var atPrefix = new RegExp('^@', 'g');
|
||||
const atPrefix = new RegExp('^@', 'g');
|
||||
exports.readDir = function readDir(dirName) {
|
||||
if (!fs.existsSync(dirName)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
return fs.readdirSync(dirName).map(function(module) {
|
||||
if (atPrefix.test(module)) {
|
||||
// reset regexp
|
||||
atPrefix.lastIndex = 0;
|
||||
try {
|
||||
return fs.readdirSync(path.join(dirName, module)).map(function(scopedMod) {
|
||||
return module + '/' + scopedMod;
|
||||
});
|
||||
} catch (e) {
|
||||
return [module];
|
||||
return fs
|
||||
.readdirSync(dirName)
|
||||
.map(function (module) {
|
||||
if (atPrefix.test(module)) {
|
||||
// reset regexp
|
||||
atPrefix.lastIndex = 0;
|
||||
try {
|
||||
return fs
|
||||
.readdirSync(path.join(dirName, module))
|
||||
.map(function (scopedMod) {
|
||||
return module + '/' + scopedMod;
|
||||
});
|
||||
} catch (e) {
|
||||
return [module];
|
||||
}
|
||||
}
|
||||
}
|
||||
return module
|
||||
}).reduce(function(prev, next) {
|
||||
return prev.concat(next);
|
||||
}, []);
|
||||
return module;
|
||||
})
|
||||
.reduce(function (prev, next) {
|
||||
return prev.concat(next);
|
||||
}, []);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.readFromPackageJson = function readFromPackageJson(options) {
|
||||
if(typeof options !== 'object') {
|
||||
if (typeof options !== 'object') {
|
||||
options = {};
|
||||
}
|
||||
const includeInBundle = options.exclude || options.includeInBundle;
|
||||
const excludeFromBundle = options.include || options.excludeFromBundle;
|
||||
|
||||
// read the file
|
||||
var packageJson;
|
||||
let packageJson;
|
||||
try {
|
||||
var fileName = options.fileName || 'package.json';
|
||||
var packageJsonString = fs.readFileSync(path.join(process.cwd(), './' + fileName), 'utf8');
|
||||
const fileName = options.fileName || 'package.json';
|
||||
const packageJsonString = fs.readFileSync(
|
||||
path.resolve(process.cwd(), fileName),
|
||||
'utf8'
|
||||
);
|
||||
packageJson = JSON.parse(packageJsonString);
|
||||
} catch (e){
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
// sections to search in package.json
|
||||
var sections = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];
|
||||
if(options.include) {
|
||||
sections = [].concat(options.include);
|
||||
let sections = [
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
'peerDependencies',
|
||||
'optionalDependencies',
|
||||
];
|
||||
if (excludeFromBundle) {
|
||||
sections = [].concat(excludeFromBundle);
|
||||
}
|
||||
if(options.exclude) {
|
||||
sections = sections.filter(function(section){
|
||||
return [].concat(options.exclude).indexOf(section) === -1;
|
||||
if (includeInBundle) {
|
||||
sections = sections.filter(function (section) {
|
||||
return [].concat(includeInBundle).indexOf(section) === -1;
|
||||
});
|
||||
}
|
||||
// collect dependencies
|
||||
var deps = {};
|
||||
sections.forEach(function(section){
|
||||
Object.keys(packageJson[section] || {}).forEach(function(dep){
|
||||
const deps = {};
|
||||
sections.forEach(function (section) {
|
||||
Object.keys(packageJson[section] || {}).forEach(function (dep) {
|
||||
deps[dep] = true;
|
||||
});
|
||||
});
|
||||
return Object.keys(deps);
|
||||
}
|
||||
};
|
||||
|
||||
exports.containsPattern = function containsPattern(arr, val) {
|
||||
return arr && arr.some(function(pattern){
|
||||
if(pattern instanceof RegExp){
|
||||
return pattern.test(val);
|
||||
} else if (typeof pattern === 'function') {
|
||||
return pattern(val);
|
||||
} else {
|
||||
return pattern == val;
|
||||
return (
|
||||
arr &&
|
||||
arr.some(function (pattern) {
|
||||
if (pattern instanceof RegExp) {
|
||||
return pattern.test(val);
|
||||
} else if (typeof pattern === 'function') {
|
||||
return pattern(val);
|
||||
} else {
|
||||
return pattern == val;
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
exports.validateOptions = function (options) {
|
||||
options = options || {};
|
||||
const results = [];
|
||||
const mistakes = {
|
||||
allowlist: ['allowslist', 'whitelist', 'allow'],
|
||||
importType: ['import', 'importype', 'importtype'],
|
||||
modulesDir: ['moduledir', 'moduledirs'],
|
||||
modulesFromFile: ['modulesfile'],
|
||||
includeAbsolutePaths: ['includeAbsolutesPaths'],
|
||||
additionalModuleDirs: ['additionalModulesDirs', 'additionalModulesDir'],
|
||||
};
|
||||
const optionsKeys = Object.keys(options);
|
||||
const optionsKeysLower = optionsKeys.map(function (optionName) {
|
||||
return optionName && optionName.toLowerCase();
|
||||
});
|
||||
Object.keys(mistakes).forEach(function (correctTerm) {
|
||||
if (!options.hasOwnProperty(correctTerm)) {
|
||||
mistakes[correctTerm]
|
||||
.concat(correctTerm.toLowerCase())
|
||||
.forEach(function (mistake) {
|
||||
const ind = optionsKeysLower.indexOf(mistake.toLowerCase());
|
||||
if (ind > -1) {
|
||||
results.push({
|
||||
message: `Option '${optionsKeys[ind]}' is not supported. Did you mean '${correctTerm}'?`,
|
||||
wrongTerm: optionsKeys[ind],
|
||||
correctTerm: correctTerm,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.log = function (message) {
|
||||
console.log(`[webpack-node-externals] : ${message}`);
|
||||
};
|
||||
|
||||
exports.error = function (errors) {
|
||||
throw new Error(
|
||||
errors
|
||||
.map(function (error) {
|
||||
return `[webpack-node-externals] : ${error}`;
|
||||
})
|
||||
.join('\r\n')
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user