├── test ├── test-rollup │ ├── modules │ │ ├── module-a │ │ │ └── index.js │ │ └── module-b │ │ │ └── index.js │ └── index.js ├── webpack.spec.js ├── test-utils.js └── library.spec.js ├── .travis.yml ├── .gitignore ├── LICENSE ├── package.json ├── README.md └── index.js /test/test-rollup/modules/module-a/index.js: -------------------------------------------------------------------------------- 1 | function a() { 2 | console.log('module-a:bundled'); 3 | } 4 | 5 | module.exports = a; -------------------------------------------------------------------------------- /test/test-rollup/modules/module-b/index.js: -------------------------------------------------------------------------------- 1 | function b() { 2 | console.log('module-b:bundled'); 3 | } 4 | 5 | module.exports = b; -------------------------------------------------------------------------------- /test/test-rollup/index.js: -------------------------------------------------------------------------------- 1 | var x = require('module-a'); 2 | var y = require('module-b'); 3 | 4 | module.exports = { 5 | x: x, 6 | y: y 7 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | before_install: 3 | - "npm install npm -g" 4 | node_js: 5 | - "0.12" 6 | - 5 7 | - 6 8 | env: 9 | - TEST_SUITE=unit 10 | script: 11 | - npm run $TEST_SUITE 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /test/webpack.spec.js: -------------------------------------------------------------------------------- 1 | var nodeExternals = require('../index.js'); 2 | var testUtils = require('./test-utils.js'); 3 | var rollupAssertion = testUtils.rollupAssertion 4 | 5 | // Test actual rollup output 6 | describe('actual rollup bundling', function() { 7 | 8 | before(function() { 9 | return testUtils.copyModules(['module-a', 'module-b']); 10 | }); 11 | // 12 | describe('basic tests', function() { 13 | it('should output modules without bundling', rollupAssertion({}, ['module-a', 'module-b'], [])); 14 | it('should honor a whitelist', rollupAssertion({ whitelist: ['module-a'] }, ['module-b'], ['module-a'])); 15 | }); 16 | 17 | after(function() { 18 | testUtils.removeModules(['module-a', 'module-b']); 19 | }); 20 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Liad Yosef 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yelo/rollup-node-external", 3 | "version": "1.0.1", 4 | "description": "Easily exclude node_modules in Rollup bundle, forked from webpack-node-externals", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/imyelo/rollup-node-external.git" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "chai": "^3.5.0", 13 | "mocha": "^2.5.3", 14 | "mock-fs-require-fix": "^1.0.1", 15 | "ncp": "^2.0.0", 16 | "rollup": "^0.50.0", 17 | "rollup-plugin-commonjs": "^8.2.1", 18 | "rollup-plugin-node-resolve": "^3.0.0" 19 | }, 20 | "scripts": { 21 | "unit": "mocha --colors ./test/*.spec.js", 22 | "unit-watch": "mocha --colors -w ./test/*.spec.js", 23 | "test": "npm run unit-watch" 24 | }, 25 | "keywords": [ 26 | "rollup", 27 | "node_modules", 28 | "node", 29 | "bundle", 30 | "external" 31 | ], 32 | "author": { 33 | "name": "Liad Yosef", 34 | "url": "https://github.com/liady" 35 | }, 36 | "contributors": [ 37 | "yelo (https://github.com/imyelo)" 38 | ], 39 | "files": [ 40 | "LICENSE", 41 | "README.md", 42 | "index.js" 43 | ], 44 | "bugs": { 45 | "url": "https://github.com/imyelo/rollup-node-external/issues" 46 | }, 47 | "homepage": "https://github.com/imyelo/rollup-node-external", 48 | "license": "MIT" 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rollup node modules external 2 | ============================== 3 | > Easily exclude node modules in rollup, forked from webpack-node-externals 4 | 5 | [![Version](https://img.shields.io/npm/v/@yelo/rollup-node-external.svg)](https://www.npmjs.org/package/@yelo/rollup-node-external) 6 | [![Downloads](https://img.shields.io/npm/dm/@yelo/rollup-node-external.svg)](https://www.npmjs.org/package/@yelo/rollup-node-external) 7 | 8 | rollup allows you to define [*external*](https://rollupjs.org/#peer-dependencies) - modules that should not be bundled. 9 | 10 | When bundling with rollup for the backend - you usually don't want to bundle its `node_modules` dependencies. 11 | This library creates an *external* function that ignores `node_modules` when bundling in rollup. 12 | 13 | **Forked from [liady/webpack-node-externals](https://github.com/liady/webpack-node-externals)** 14 | 15 | ## Quick usage 16 | ```sh 17 | npm install @yelo/rollup-node-external --save-dev 18 | ``` 19 | 20 | In your `rollup.config.js`: 21 | ```js 22 | var external = require('@yelo/rollup-node-external'); 23 | ... 24 | module.exports = { 25 | ... 26 | external: external(), // in order to ignore all modules in node_modules folder 27 | plugins: [ 28 | ... 29 | // import node-resolve plugin 30 | require('rollup-plugin-node-resovle')(), 31 | ... 32 | ], 33 | ... 34 | }; 35 | ``` 36 | And that's it. All node modules will no longer be bundled but will be left as `require('module')`. 37 | 38 | ## Detailed overview 39 | ### Description 40 | This library scans the `node_modules` folder for all node_modules names, and builds an *external* function that tells rollup not to bundle those modules, or any sub-modules of theirs. 41 | 42 | ### Configuration 43 | This library accepts an `options` object. 44 | 45 | #### `options.whitelist (=[])` 46 | An array for the `external` 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. 47 |
**Important** - if you have set aliases in your rollup config with the exact same names as modules in *node_modules*, you need to whitelist them so rollup will know they should be bundled. 48 | 49 | #### `options.importType (='commonjs')` 50 | The method in which unbundled modules will be required in the code. Best to leave as `commonjs` for node modules. 51 | 52 | #### `options.modulesDir (='node_modules')` 53 | The folder in which to search for the node modules. 54 | 55 | #### `options.modulesFromFile (=false)` 56 | Read the modules from the `package.json` file instead of the `node_modules` folder. 57 | 58 | #### Example 59 | ```js 60 | var external = require('@yelo/rollup-node-external'); 61 | ... 62 | module.exports = { 63 | ... 64 | external: external({ 65 | // this WILL include `jquery` in the bundle, as well as `lodash/*` 66 | whitelist: ['jquery', /^lodash/] 67 | }), 68 | plugins: [ 69 | ... 70 | require('rollup-plugin-node-resovle')(), 71 | ... 72 | ], 73 | ... 74 | }; 75 | ``` 76 | 77 | For most use cases, the defaults of `importType` and `modulesDir` should be used. 78 | 79 | ### Test 80 | ```sh 81 | npm run test 82 | ``` 83 | 84 | ## License 85 | MIT 86 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | 4 | var scopedModuleRegex = new RegExp('@[a-zA-Z0-9][\\w-.]+\/[a-zA-Z0-9][\\w-.]+([a-zA-Z0-9.\/]+)?', 'g'); 5 | var atPrefix = new RegExp('^@', 'g'); 6 | function contains(arr, val) { 7 | return arr && arr.indexOf(val) !== -1; 8 | } 9 | 10 | function readDir(dirName) { 11 | try { 12 | return fs.readdirSync(dirName).map(function(module) { 13 | if (atPrefix.test(module)) { 14 | // reset regexp 15 | atPrefix.lastIndex = 0; 16 | try { 17 | return fs.readdirSync(path.join(dirName, module)).map(function(scopedMod) { 18 | return module + '/' + scopedMod; 19 | }); 20 | } catch (e) { 21 | return [module]; 22 | } 23 | } 24 | return module 25 | }).reduce(function(prev, next) { 26 | return prev.concat(next); 27 | }, []); 28 | } catch (e) { 29 | console.log(e); 30 | return []; 31 | } 32 | } 33 | 34 | function readFromPackageJson() { 35 | var packageJson; 36 | try { 37 | var packageJsonString = fs.readFileSync(path.join(process.cwd(), './package.json'), 'utf8'); 38 | packageJson = JSON.parse(packageJsonString); 39 | } catch (e){ 40 | return []; 41 | } 42 | var sections = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']; 43 | var deps = {}; 44 | sections.forEach(function(section){ 45 | Object.keys(packageJson[section] || {}).forEach(function(dep){ 46 | deps[dep] = true; 47 | }); 48 | }); 49 | return Object.keys(deps); 50 | } 51 | 52 | function containsPattern(arr, val) { 53 | return arr && arr.some(function(pattern){ 54 | if(pattern instanceof RegExp){ 55 | return pattern.test(val); 56 | } else if (typeof pattern === 'function') { 57 | return pattern(val); 58 | } else { 59 | return pattern == val; 60 | } 61 | }); 62 | } 63 | 64 | function getModuleName(request, includeAbsolutePaths) { 65 | var req = request; 66 | var delimiter = '/'; 67 | 68 | if (includeAbsolutePaths) { 69 | req = req.replace(/^.*?\/node_modules\//, ''); 70 | } 71 | // check if scoped module 72 | if (scopedModuleRegex.test(req)) { 73 | // reset regexp 74 | scopedModuleRegex.lastIndex = 0; 75 | return req.split(delimiter, 2).join(delimiter); 76 | } 77 | return req.split(delimiter)[0]; 78 | } 79 | 80 | module.exports = function nodeExternals(options) { 81 | options = options || {}; 82 | var whitelist = [].concat(options.whitelist || []); 83 | var binaryDirs = [].concat(options.binaryDirs || ['.bin']); 84 | var importType = options.importType || 'commonjs'; 85 | var modulesDir = options.modulesDir || 'node_modules'; 86 | var modulesFromFile = !!options.modulesFromFile; 87 | var includeAbsolutePaths = !!options.includeAbsolutePaths; 88 | 89 | // helper function 90 | function isNotBinary(x) { 91 | return !contains(binaryDirs, x); 92 | } 93 | 94 | // create the node modules list 95 | var nodeModules = modulesFromFile ? readFromPackageJson() : readDir(modulesDir).filter(isNotBinary); 96 | 97 | // return an externals function 98 | return function(request){ 99 | var moduleName = getModuleName(request, includeAbsolutePaths); 100 | return contains(nodeModules, moduleName) && !containsPattern(whitelist, request); 101 | } 102 | } -------------------------------------------------------------------------------- /test/test-utils.js: -------------------------------------------------------------------------------- 1 | var mockDir = require('mock-fs-require-fix'); 2 | var nodeExternals = require('../index.js'); 3 | var rollup = require('rollup').rollup; 4 | var nodeResolve = require('rollup-plugin-node-resolve') 5 | var commonjs = require('rollup-plugin-commonjs') 6 | var fs = require('fs'); 7 | var ncp = require('ncp').ncp; 8 | var path = require('path'); 9 | var relative = path.join.bind(path, __dirname); 10 | var chai = require('chai'); 11 | var expect = chai.expect; 12 | 13 | /** 14 | * Creates an assertion function that makes sure to output expectedResult when given moduleName 15 | * @param {object} context context object that holds the instance 16 | * @param {string} moduleName given module name 17 | * @param {string} expectedResult expected external module string 18 | * @return {function} the assertion function 19 | */ 20 | exports.buildAssertion = function buildAssertion(context, moduleName, expectedResult){ 21 | return function() { 22 | expect(context.instance(moduleName), expectedResult) 23 | }; 24 | } 25 | 26 | /** 27 | * Mocks the fs module to output a desired structure 28 | * @param {object} structure the requested structure 29 | * @return {void} 30 | */ 31 | exports.mockNodeModules = function mockNodeModules(structure){ 32 | structure = structure || { 33 | 'moduleA' : { 34 | 'sub-module':{}, 35 | 'another-sub':{ 36 | 'index.js' : '' 37 | }, 38 | }, 39 | 'moduleB' : { 40 | 'sub-module':{} 41 | }, 42 | 'moduleC' : {}, 43 | 'moduleD' : { 44 | 'sub-module':{} 45 | }, 46 | 'moduleF' : {}, 47 | '@organisation/moduleA':{}, 48 | '@organisation/base-node':{}, 49 | }; 50 | 51 | mockDir({ 52 | 'node_modules' : structure, 53 | 'package.json': JSON.stringify({ 54 | dependencies: { 55 | 'moduleE': '1.0.0', 56 | 'moduleF': '1.0.0', 57 | '@organisation/moduleE': '1.0.0', 58 | }, 59 | devDependencies: { 60 | 'moduleG': '1.0.0', 61 | '@organisation/moduleG': '1.0.0', 62 | }, 63 | }) 64 | }); 65 | } 66 | 67 | /** 68 | * Restores the fs module 69 | * @return {void} 70 | */ 71 | exports.restoreMock = function restoreMock(){ 72 | mockDir.restore(); 73 | } 74 | 75 | exports.copyModules = function(moduleNames) { 76 | return Promise.all(moduleNames.map(function(moduleName) { 77 | return copyDir(relative('test-rollup', 'modules', moduleName), relative('../node_modules', moduleName)); 78 | })); 79 | } 80 | 81 | exports.removeModules = function(moduleNames) { 82 | moduleNames.forEach(function(moduleName){ 83 | removeDir(relative('../node_modules', moduleName)); 84 | }); 85 | } 86 | 87 | /** 88 | * Creates an assertion function that makes sure the result contains/doesnt contain expected modules 89 | * @param {object} nodeExternalsConfig The node externals configuration 90 | * @param {object} externals expected externals 91 | * @param {object} nonExternals expected non externals 92 | * @return {function} the assertion function 93 | */ 94 | exports.rollupAssertion = function rollupAssertion(nodeExternalsConfig, externals, nonExternals){ 95 | return function() { 96 | return generateWithRollup(nodeExternalsConfig).then(function(result) { 97 | assertExternals(result, externals, nonExternals); 98 | }, function (err) { console.log(err) }); 99 | }; 100 | } 101 | 102 | /** 103 | * Generates the result file with rollup, using our nodeExternals 104 | * @param {object} context The context object to hang the result on 105 | * @param {object} nodeExternalsConfig The node externals configuration 106 | * @return {Promise} 107 | */ 108 | function generateWithRollup(nodeExternalsConfig) { 109 | var testDir = relative('test-rollup'); 110 | var outputFileName = 'bundle.js'; 111 | var outputFile = path.join(testDir, outputFileName); 112 | return rollup({ 113 | input: path.join(testDir, 'index.js'), 114 | external: nodeExternals(nodeExternalsConfig), 115 | plugins: [ 116 | nodeResolve(), 117 | commonjs() 118 | ] 119 | }).then(function (bundle) { 120 | return bundle.generate({ 121 | format: 'cjs' 122 | }); 123 | }).then(function (output) { 124 | return output.code; 125 | }); 126 | } 127 | 128 | function assertExternals(result , externals, nonExternals) { 129 | externals.forEach(function(moduleName) { 130 | expect(result).to.not.contain(bundled(moduleName)); 131 | expect(result).to.contain(external(moduleName)); 132 | }); 133 | nonExternals.forEach(function(moduleName) { 134 | expect(result).to.not.contain(external(moduleName)); 135 | expect(result).to.contain(bundled(moduleName)); 136 | }); 137 | } 138 | 139 | function bundled(moduleName) { 140 | return moduleName + ':bundled'; 141 | } 142 | 143 | function external(moduleName) { 144 | return 'require(\''+ moduleName +'\')'; 145 | } 146 | 147 | function removeDir(dirName) { 148 | if(fs.existsSync(dirName) ) { 149 | fs.readdirSync(dirName).forEach(function(file, index){ 150 | fs.unlinkSync(path.join(dirName, file)); 151 | }); 152 | fs.rmdirSync(dirName); 153 | } 154 | } 155 | 156 | function copyDir(source, dest) { 157 | return new Promise(function(resolve, reject) { 158 | ncp(source, dest, function(err) { 159 | if(err) { 160 | reject(err) 161 | } else { 162 | resolve() 163 | } 164 | }) 165 | }) 166 | } -------------------------------------------------------------------------------- /test/library.spec.js: -------------------------------------------------------------------------------- 1 | var nodeExternals = require('../index.js'); 2 | var testUtils = require('./test-utils.js'); 3 | var mockNodeModules = testUtils.mockNodeModules; 4 | var restoreMock = testUtils.restoreMock; 5 | var context={}; 6 | var assertResult = testUtils.buildAssertion.bind(null, context); 7 | 8 | // Test basic functionality 9 | describe('invocation with no settings', function() { 10 | 11 | before(function(){ 12 | mockNodeModules(); 13 | context.instance = nodeExternals(); 14 | }); 15 | 16 | describe('should invoke a commonjs callback', function(){ 17 | it('when given an existing module', assertResult('moduleA', 'commonjs moduleA')); 18 | it('when given another existing module', assertResult('moduleB', 'commonjs moduleB')); 19 | it('when given another existing module for scoped package', assertResult('@organisation/moduleA', 'commonjs @organisation/moduleA')); 20 | it('when given an existing sub-module', assertResult('moduleA/sub-module', 'commonjs moduleA/sub-module')); 21 | it('when given an existing file in a sub-module', assertResult('moduleA/another-sub/index.js', 'commonjs moduleA/another-sub/index.js')); 22 | it('when given an existing file in a scoped package', assertResult('@organisation/moduleA/index.js', 'commonjs @organisation/moduleA/index.js')) 23 | it('when given an another existing file in a scoped package', assertResult('@organisation/base-node/vs/base/common/paths', 'commonjs @organisation/base-node/vs/base/common/paths')) 24 | 25 | }); 26 | 27 | describe('should invoke an empty callback', function(){ 28 | it('when given a non-node module', assertResult('non-node-module', undefined)); 29 | it('when given a module in the file but not in folder', assertResult('moduleE', undefined)); 30 | it('when given a relative path', assertResult('./src/index.js', undefined)); 31 | it('when given a different absolute path', assertResult('/test/node_modules/non-node-module', undefined)); 32 | it('when given a complex different absolute path', assertResult('/test/node_modules/non-node-module/node_modules/moduleA', undefined)); 33 | it('when given an absolute path', assertResult('/test/node_modules/moduleA', undefined)); 34 | it('when given an existing sub-module inside node_modules', assertResult('/moduleA/node_modules/moduleB', undefined)); 35 | }); 36 | 37 | after(function(){ 38 | restoreMock() 39 | }); 40 | }); 41 | 42 | // Test different "importType" 43 | describe('invocation with a different importType', function() { 44 | 45 | before(function(){ 46 | mockNodeModules(); 47 | context.instance = nodeExternals({importType: 'var'}); 48 | }); 49 | 50 | describe('should invoke a var callback', function(){ 51 | it('when given an existing module', assertResult('moduleA', 'var moduleA')); 52 | it('when given another existing module', assertResult('moduleB', 'var moduleB')); 53 | it('when given another existing module for scoped package', assertResult('@organisation/moduleA', 'var @organisation/moduleA')); 54 | it('when given an existing sub-module', assertResult('moduleA/sub-module', 'var moduleA/sub-module')); 55 | it('when given an existing file in a sub-module', assertResult('moduleA/another-sub/index.js', 'var moduleA/another-sub/index.js')); 56 | it('when given an existing file in a scoped package', assertResult('@organisation/moduleA/index.js', 'var @organisation/moduleA/index.js')) 57 | 58 | }); 59 | 60 | describe('should invoke an empty callback', function(){ 61 | it('when given a non-node module', assertResult('non-node-module', undefined)); 62 | it('when given a relative path', assertResult('./src/index.js', undefined)); 63 | }); 64 | 65 | after(function(){ 66 | restoreMock() 67 | }); 68 | }); 69 | 70 | // Test reading from file 71 | describe('reads from a file', function() { 72 | 73 | before(function(){ 74 | mockNodeModules(); 75 | context.instance = nodeExternals({modulesFromFile: true}); 76 | }); 77 | 78 | describe('should invoke a commonjs callback', function(){ 79 | it('when given an existing module in the file', assertResult('moduleE', 'commonjs moduleE')); 80 | it('when given an existing module for scoped package in the file', assertResult('@organisation/moduleE', 'commonjs @organisation/moduleE')); 81 | it('when given an existing file in a sub-module', assertResult('moduleG/another-sub/index.js', 'commonjs moduleG/another-sub/index.js')); 82 | it('when given an existing file in a scoped package', assertResult('@organisation/moduleG/index.js', 'commonjs @organisation/moduleG/index.js')) 83 | 84 | }); 85 | 86 | describe('should invoke an empty callback', function(){ 87 | it('when given a non-node module', assertResult('non-node-module', undefined)); 88 | it('when given a module in the folder but not in the file', assertResult('moduleA', undefined)); 89 | it('when given a module of scoped package in the folder but not in the file', assertResult('@organisation/moduleA', undefined)); 90 | it('when given a relative path', assertResult('./src/index.js', undefined)); 91 | }); 92 | 93 | after(function(){ 94 | restoreMock() 95 | }); 96 | }); 97 | 98 | // Test whitelist 99 | describe('respects a whitelist', function() { 100 | 101 | before(function(){ 102 | mockNodeModules(); 103 | context.instance = nodeExternals({ 104 | whitelist: ['moduleA/sub-module', 'moduleA/another-sub/index.js', 'moduleC', function (m) { 105 | return m == 'moduleF'; 106 | }, /^moduleD/] 107 | }); 108 | }); 109 | 110 | describe('should invoke a commonjs callback', function(){ 111 | it('when given an existing module', assertResult('moduleB', 'commonjs moduleB')); 112 | it('when given an existing sub-module', assertResult('moduleB/sub-module', 'commonjs moduleB/sub-module')); 113 | it('when given a module which is the parent on an ignored path', assertResult('moduleA', 'commonjs moduleA')); 114 | it('when given a sub-module of an ignored module', assertResult('moduleC/sub-module', 'commonjs moduleC/sub-module')); 115 | it('when given a sub-module of an module ignored by a function', assertResult('moduleF/sub-module', 'commonjs moduleF/sub-module')); 116 | }); 117 | 118 | describe('should invoke an empty callback', function(){ 119 | it('when given module path ignored by a function', assertResult('moduleC', undefined)); 120 | it('when given an ignored module path', assertResult('moduleF', undefined)); 121 | it('when given an ignored sub-module path', assertResult('moduleA/sub-module', undefined)); 122 | it('when given an ignored file path', assertResult('moduleA/another-sub/index.js', undefined)); 123 | it('when given an ignored regex path', assertResult('moduleD', undefined)); 124 | it('when given an ignored regex sub-module path', assertResult('moduleD/sub-module', undefined)); 125 | it('when given a non-node module', assertResult('non-node-module', undefined)); 126 | it('when given a relative path', assertResult('./src/index.js', undefined)); 127 | }); 128 | 129 | after(function(){ 130 | restoreMock() 131 | }); 132 | }); 133 | 134 | // Test absolute path support 135 | describe('invocation with an absolute path setting', function() { 136 | 137 | before(function(){ 138 | mockNodeModules(); 139 | context.instance = nodeExternals({ 140 | includeAbsolutePaths: true 141 | }); 142 | }); 143 | 144 | describe('should invoke a commonjs callback', function(){ 145 | it('when given an existing module', assertResult('moduleA', 'commonjs moduleA')); 146 | it('when given another existing module', assertResult('moduleB', 'commonjs moduleB')); 147 | it('when given another existing module for scoped package', assertResult('@organisation/moduleA', 'commonjs @organisation/moduleA')); 148 | it('when given an existing sub-module', assertResult('moduleA/sub-module', 'commonjs moduleA/sub-module')); 149 | it('when given an existing file in a sub-module', assertResult('moduleA/another-sub/index.js', 'commonjs moduleA/another-sub/index.js')); 150 | it('when given an existing file in a scoped package', assertResult('@organisation/moduleA/index.js', 'commonjs @organisation/moduleA/index.js')); 151 | it('when given an absolute path', assertResult('/test/node_modules/moduleA', 'commonjs /test/node_modules/moduleA')); 152 | it('when given another absolute path', assertResult('../../test/node_modules/moduleA', 'commonjs ../../test/node_modules/moduleA')); 153 | it('when given another absolute path for scoped package', assertResult('/test/node_modules/@organisation/moduleA', 'commonjs /test/node_modules/@organisation/moduleA')); 154 | it('when given an existing sub-module inside node_modules', assertResult('/moduleA/node_modules/moduleB', 'commonjs /moduleA/node_modules/moduleB')); 155 | }); 156 | 157 | describe('should invoke an empty callback', function(){ 158 | it('when given a non-node module', assertResult('non-node-module', undefined)); 159 | it('when given a module in the file but not in folder', assertResult('moduleE', undefined)); 160 | it('when given a relative path', assertResult('./src/index.js', undefined)); 161 | it('when given a different absolute path', assertResult('/test/node_modules/non-node-module', undefined)); 162 | 163 | it('when given a complex different absolute path', assertResult('/test/node_modules/non-node-module/node_modules/moduleA', undefined)); 164 | it('when given a complex different absolute path for scoped package', assertResult('/test/node_modules/non-node-module/node_modules/@organisation/moduleA', undefined)); 165 | 166 | it('when given another complex different absolute path', assertResult('../../node_modules/non-node-module/node_modules/moduleA', undefined)); 167 | it('when given another complex different absolute path for scoped package', assertResult('../../node_modules/non-node-module/node_modules/@organisation/moduleA', undefined)); 168 | 169 | }); 170 | 171 | after(function(){ 172 | restoreMock() 173 | }); 174 | }); --------------------------------------------------------------------------------