├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── __fixtures__ ├── builtins-6.0.0 │ ├── index.js │ └── package.json ├── builtins │ ├── index.js │ └── package.json ├── cherry-picked │ ├── index.js │ └── package.json ├── deps │ ├── index.js │ └── package.json ├── node_modules │ ├── @scope │ │ ├── bar │ │ │ ├── bar.js │ │ │ └── index.js │ │ ├── baz │ │ │ ├── baz.js │ │ │ └── index.js │ │ └── foo │ │ │ ├── foo.js │ │ │ └── index.js │ ├── bar │ │ ├── bar.js │ │ └── index.js │ ├── baz │ │ ├── baz.js │ │ └── index.js │ └── foo │ │ ├── foo.js │ │ └── index.js ├── package-path │ └── package.json ├── peer-deps │ ├── index.js │ └── package.json └── scoped │ ├── index.js │ └── package.json ├── __tests__ ├── __snapshots__ │ └── index.js.snap └── index.js ├── index.js ├── package-lock.json └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.{md,json,lock,*rc}] 13 | insert_final_newline = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | ._* 3 | node_modules 4 | npm-debug.log 5 | !__fixtures__/node_modules 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "8" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 stevenbenisek 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rollup-plugin-auto-external 2 | 3 | [![Build Status](https://travis-ci.org/stevenbenisek/rollup-plugin-auto-external.svg?branch=master)](https://travis-ci.org/stevenbenisek/rollup-plugin-auto-external) 4 | 5 | > [Rollup](https://rollupjs.org/) plugin to automatically exclude package.json dependencies and peerDependencies from your bundle. 6 | 7 | ## Install 8 | 9 | ```bash 10 | npm install --save-dev rollup-plugin-auto-external 11 | ``` 12 | 13 | ## Usage 14 | 15 | ##### Example `rollup.config.js` 16 | 17 | ```js 18 | import autoExternal from 'rollup-plugin-auto-external'; 19 | 20 | export default { 21 | input: 'index.js', 22 | plugins: [autoExternal()], 23 | }; 24 | ``` 25 | 26 | ##### Example `rollup.config.js` with options 27 | 28 | ```js 29 | import path from 'path'; 30 | import autoExternal from 'rollup-plugin-auto-external'; 31 | 32 | export default { 33 | input: 'index.js', 34 | plugins: [ 35 | autoExternal({ 36 | builtins: false, 37 | dependencies: true, 38 | packagePath: path.resolve('./packages/module/package.json'), 39 | peerDependencies: false, 40 | }), 41 | ], 42 | }; 43 | ``` 44 | 45 | ##### Example `rollup.config.js` with [external](https://github.com/rollup/rollup/wiki/JavaScript-API#external) 46 | 47 | `rollup-plugin-auto-external` does not overwrite the [external](https://github.com/rollup/rollup/wiki/JavaScript-API#external) option. The two can happily coexist. 48 | 49 | ```js 50 | import autoExternal from 'rollup-plugin-auto-external'; 51 | 52 | export default { 53 | input: 'index.js', 54 | external: id => id.includes('babel-runtime'), 55 | plugins: [autoExternal()], 56 | }; 57 | ``` 58 | 59 | ##### Example `rollup.config.js` with per format options 60 | 61 | ```js 62 | import autoExternal from 'rollup-plugin-auto-external'; 63 | 64 | export default ['es', 'umd'].map(format => ({ 65 | input: 'index.js', 66 | plugins: [ 67 | autoExternal({ 68 | dependencies: format === 'es', 69 | }), 70 | ], 71 | })); 72 | ``` 73 | 74 | ### Options 75 | 76 | #### `builtins` 77 | 78 | `boolean`|`string`: defaults to `true`. Add all Node.js builtin modules (in the running version) as externals. Specify a `string` value (e.g., `'6.0.0'`) to add all builtin modules for a _specific version_ of Node.js. 79 | 80 | Rollup will complain if `builtins` is present, and the build target is a browser. You may want [rollup-plugin-node-builtins](https://npm.im/package/rollup-plugin-node-builtins). 81 | 82 | #### `dependencies` 83 | 84 | `boolean`: defaults to `true`. 85 | 86 | #### `packagePath` 87 | 88 | `string`: defaults to `process.cwd()`. Path to a package.json file or its directory. 89 | 90 | #### `peerDependencies` 91 | 92 | `boolean`: defaults to `true`. 93 | -------------------------------------------------------------------------------- /__fixtures__/builtins-6.0.0/index.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | 3 | module.exports = os; 4 | -------------------------------------------------------------------------------- /__fixtures__/builtins-6.0.0/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /__fixtures__/builtins/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = path; 4 | -------------------------------------------------------------------------------- /__fixtures__/builtins/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /__fixtures__/cherry-picked/index.js: -------------------------------------------------------------------------------- 1 | import foo from 'foo/foo'; 2 | import bar from 'bar/bar'; 3 | import baz from 'baz/baz'; 4 | 5 | export default `${foo}${bar}${baz}`; 6 | -------------------------------------------------------------------------------- /__fixtures__/cherry-picked/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "foo": "^0.0.0", 4 | "bar": "^0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /__fixtures__/deps/index.js: -------------------------------------------------------------------------------- 1 | import foo from 'foo'; 2 | import bar from 'bar'; 3 | import baz from 'baz'; 4 | 5 | export default `${foo}${bar}${baz}`; 6 | -------------------------------------------------------------------------------- /__fixtures__/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "foo": "^0.0.0", 4 | "bar": "^0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/@scope/bar/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = '@scope/bar'; 2 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/@scope/bar/index.js: -------------------------------------------------------------------------------- 1 | const bar = require('./bar'); 2 | 3 | module.exports = bar; 4 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/@scope/baz/baz.js: -------------------------------------------------------------------------------- 1 | export default '@scope/baz'; 2 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/@scope/baz/index.js: -------------------------------------------------------------------------------- 1 | import baz from './baz'; 2 | 3 | export default baz; 4 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/@scope/foo/foo.js: -------------------------------------------------------------------------------- 1 | export default '@scope/foo'; 2 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/@scope/foo/index.js: -------------------------------------------------------------------------------- 1 | import foo from './foo'; 2 | 3 | export default foo; 4 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/bar/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = 'bar'; 2 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/bar/index.js: -------------------------------------------------------------------------------- 1 | const bar = require('./bar'); 2 | 3 | module.exports = bar; 4 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/baz/baz.js: -------------------------------------------------------------------------------- 1 | export default 'baz'; 2 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/baz/index.js: -------------------------------------------------------------------------------- 1 | import baz from './baz'; 2 | 3 | export default baz; 4 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/foo/foo.js: -------------------------------------------------------------------------------- 1 | export default 'foo'; 2 | -------------------------------------------------------------------------------- /__fixtures__/node_modules/foo/index.js: -------------------------------------------------------------------------------- 1 | import foo from './foo'; 2 | 3 | export default foo; 4 | -------------------------------------------------------------------------------- /__fixtures__/package-path/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "foo": "^0.0.0", 4 | "bar": "^0.0.0", 5 | "baz": "^0.0.0" 6 | } 7 | } -------------------------------------------------------------------------------- /__fixtures__/peer-deps/index.js: -------------------------------------------------------------------------------- 1 | import foo from 'foo'; 2 | import bar from 'bar'; 3 | import baz from 'baz'; 4 | 5 | export default `${foo}${bar}${baz}`; 6 | -------------------------------------------------------------------------------- /__fixtures__/peer-deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "peerDependencies": { 3 | "foo": "^0.0.0", 4 | "bar": "^0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /__fixtures__/scoped/index.js: -------------------------------------------------------------------------------- 1 | import foo from '@scope/foo'; 2 | import bar from '@scope/bar'; 3 | import baz from '@scope/baz'; 4 | 5 | export default `${foo}${bar}${baz}`; 6 | -------------------------------------------------------------------------------- /__fixtures__/scoped/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@scope/foo": "^0.0.0", 4 | "@scope/bar": "^0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/index.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`autoExternal(options) should add builtins by default 1`] = ` 4 | "import path from 'path'; 5 | 6 | var builtins = path; 7 | 8 | export default builtins; 9 | " 10 | `; 11 | 12 | exports[`autoExternal(options) should add dependencies by default 1`] = ` 13 | "import foo from 'foo'; 14 | import bar from 'bar'; 15 | 16 | var baz = 'baz'; 17 | 18 | var index = \`\${foo}\${bar}\${baz}\`; 19 | 20 | export default index; 21 | " 22 | `; 23 | 24 | exports[`autoExternal(options) should add peerDependencies by default 1`] = ` 25 | "import foo from 'foo'; 26 | import bar from 'bar'; 27 | 28 | var baz = 'baz'; 29 | 30 | var index = \`\${foo}\${bar}\${baz}\`; 31 | 32 | export default index; 33 | " 34 | `; 35 | 36 | exports[`autoExternal(options) should handle a custom package file path 1`] = ` 37 | "import foo from 'foo'; 38 | import bar from 'bar'; 39 | import baz from 'baz'; 40 | 41 | var index = \`\${foo}\${bar}\${baz}\`; 42 | 43 | export default index; 44 | " 45 | `; 46 | 47 | exports[`autoExternal(options) should handle a directory path as the packagePath 1`] = ` 48 | "import foo from 'foo'; 49 | import bar from 'bar'; 50 | import baz from 'baz'; 51 | 52 | var index = \`\${foo}\${bar}\${baz}\`; 53 | 54 | export default index; 55 | " 56 | `; 57 | 58 | exports[`autoExternal(options) should handle adding builtins for a specific Node.js version 1`] = ` 59 | "import os from 'os'; 60 | 61 | var builtins6_0_0 = os; 62 | 63 | export default builtins6_0_0; 64 | " 65 | `; 66 | 67 | exports[`autoExternal(options) should handle cherry picked modules 1`] = ` 68 | "import foo from 'foo/foo'; 69 | import bar from 'bar/bar'; 70 | 71 | var baz = 'baz'; 72 | 73 | var index = \`\${foo}\${bar}\${baz}\`; 74 | 75 | export default index; 76 | " 77 | `; 78 | 79 | exports[`autoExternal(options) should handle disabling builtins 1`] = ` 80 | "// Copyright Joyent, Inc. and other Node contributors. 81 | // 82 | // Permission is hereby granted, free of charge, to any person obtaining a 83 | // copy of this software and associated documentation files (the 84 | // \\"Software\\"), to deal in the Software without restriction, including 85 | // without limitation the rights to use, copy, modify, merge, publish, 86 | // distribute, sublicense, and/or sell copies of the Software, and to permit 87 | // persons to whom the Software is furnished to do so, subject to the 88 | // following conditions: 89 | // 90 | // The above copyright notice and this permission notice shall be included 91 | // in all copies or substantial portions of the Software. 92 | // 93 | // THE SOFTWARE IS PROVIDED \\"AS IS\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS 94 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 95 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 96 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 97 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 98 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 99 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 100 | 101 | // resolves . and .. elements in a path array with directory names there 102 | // must be no slashes, empty elements, or device names (c:\\\\) in the array 103 | // (so also no leading and trailing slashes - it does not distinguish 104 | // relative and absolute paths) 105 | function normalizeArray(parts, allowAboveRoot) { 106 | // if the path tries to go above the root, \`up\` ends up > 0 107 | var up = 0; 108 | for (var i = parts.length - 1; i >= 0; i--) { 109 | var last = parts[i]; 110 | if (last === '.') { 111 | parts.splice(i, 1); 112 | } else if (last === '..') { 113 | parts.splice(i, 1); 114 | up++; 115 | } else if (up) { 116 | parts.splice(i, 1); 117 | up--; 118 | } 119 | } 120 | 121 | // if the path is allowed to go above the root, restore leading ..s 122 | if (allowAboveRoot) { 123 | for (; up--; up) { 124 | parts.unshift('..'); 125 | } 126 | } 127 | 128 | return parts; 129 | } 130 | 131 | // Split a filename into [root, dir, basename, ext], unix version 132 | // 'root' is just a slash, or nothing. 133 | var splitPathRe = 134 | /^(\\\\/?|)([\\\\s\\\\S]*?)((?:\\\\.{1,2}|[^\\\\/]+?|)(\\\\.[^.\\\\/]*|))(?:[\\\\/]*)$/; 135 | var splitPath = function(filename) { 136 | return splitPathRe.exec(filename).slice(1); 137 | }; 138 | 139 | // path.resolve([from ...], to) 140 | // posix version 141 | function resolve() { 142 | var resolvedPath = '', 143 | resolvedAbsolute = false; 144 | 145 | for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { 146 | var path = (i >= 0) ? arguments[i] : '/'; 147 | 148 | // Skip empty and invalid entries 149 | if (typeof path !== 'string') { 150 | throw new TypeError('Arguments to path.resolve must be strings'); 151 | } else if (!path) { 152 | continue; 153 | } 154 | 155 | resolvedPath = path + '/' + resolvedPath; 156 | resolvedAbsolute = path.charAt(0) === '/'; 157 | } 158 | 159 | // At this point the path should be resolved to a full absolute path, but 160 | // handle relative paths to be safe (might happen when process.cwd() fails) 161 | 162 | // Normalize the path 163 | resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { 164 | return !!p; 165 | }), !resolvedAbsolute).join('/'); 166 | 167 | return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; 168 | } 169 | // path.normalize(path) 170 | // posix version 171 | function normalize(path) { 172 | var isPathAbsolute = isAbsolute(path), 173 | trailingSlash = substr(path, -1) === '/'; 174 | 175 | // Normalize the path 176 | path = normalizeArray(filter(path.split('/'), function(p) { 177 | return !!p; 178 | }), !isPathAbsolute).join('/'); 179 | 180 | if (!path && !isPathAbsolute) { 181 | path = '.'; 182 | } 183 | if (path && trailingSlash) { 184 | path += '/'; 185 | } 186 | 187 | return (isPathAbsolute ? '/' : '') + path; 188 | } 189 | // posix version 190 | function isAbsolute(path) { 191 | return path.charAt(0) === '/'; 192 | } 193 | 194 | // posix version 195 | function join() { 196 | var paths = Array.prototype.slice.call(arguments, 0); 197 | return normalize(filter(paths, function(p, index) { 198 | if (typeof p !== 'string') { 199 | throw new TypeError('Arguments to path.join must be strings'); 200 | } 201 | return p; 202 | }).join('/')); 203 | } 204 | 205 | 206 | // path.relative(from, to) 207 | // posix version 208 | function relative(from, to) { 209 | from = resolve(from).substr(1); 210 | to = resolve(to).substr(1); 211 | 212 | function trim(arr) { 213 | var start = 0; 214 | for (; start < arr.length; start++) { 215 | if (arr[start] !== '') break; 216 | } 217 | 218 | var end = arr.length - 1; 219 | for (; end >= 0; end--) { 220 | if (arr[end] !== '') break; 221 | } 222 | 223 | if (start > end) return []; 224 | return arr.slice(start, end - start + 1); 225 | } 226 | 227 | var fromParts = trim(from.split('/')); 228 | var toParts = trim(to.split('/')); 229 | 230 | var length = Math.min(fromParts.length, toParts.length); 231 | var samePartsLength = length; 232 | for (var i = 0; i < length; i++) { 233 | if (fromParts[i] !== toParts[i]) { 234 | samePartsLength = i; 235 | break; 236 | } 237 | } 238 | 239 | var outputParts = []; 240 | for (var i = samePartsLength; i < fromParts.length; i++) { 241 | outputParts.push('..'); 242 | } 243 | 244 | outputParts = outputParts.concat(toParts.slice(samePartsLength)); 245 | 246 | return outputParts.join('/'); 247 | } 248 | 249 | var sep = '/'; 250 | var delimiter = ':'; 251 | 252 | function dirname(path) { 253 | var result = splitPath(path), 254 | root = result[0], 255 | dir = result[1]; 256 | 257 | if (!root && !dir) { 258 | // No dirname whatsoever 259 | return '.'; 260 | } 261 | 262 | if (dir) { 263 | // It has a dirname, strip trailing slash 264 | dir = dir.substr(0, dir.length - 1); 265 | } 266 | 267 | return root + dir; 268 | } 269 | 270 | function basename(path, ext) { 271 | var f = splitPath(path)[2]; 272 | // TODO: make this comparison case-insensitive on windows? 273 | if (ext && f.substr(-1 * ext.length) === ext) { 274 | f = f.substr(0, f.length - ext.length); 275 | } 276 | return f; 277 | } 278 | 279 | 280 | function extname(path) { 281 | return splitPath(path)[3]; 282 | } 283 | var path = { 284 | extname: extname, 285 | basename: basename, 286 | dirname: dirname, 287 | sep: sep, 288 | delimiter: delimiter, 289 | relative: relative, 290 | join: join, 291 | isAbsolute: isAbsolute, 292 | normalize: normalize, 293 | resolve: resolve 294 | }; 295 | function filter (xs, f) { 296 | if (xs.filter) return xs.filter(f); 297 | var res = []; 298 | for (var i = 0; i < xs.length; i++) { 299 | if (f(xs[i], i, xs)) res.push(xs[i]); 300 | } 301 | return res; 302 | } 303 | 304 | // String.prototype.substr - negative index don't work in IE8 305 | var substr = 'ab'.substr(-1) === 'b' ? 306 | function (str, start, len) { return str.substr(start, len) } : 307 | function (str, start, len) { 308 | if (start < 0) start = str.length + start; 309 | return str.substr(start, len); 310 | } 311 | ; 312 | 313 | var builtins = path; 314 | 315 | export default builtins; 316 | " 317 | `; 318 | 319 | exports[`autoExternal(options) should handle disabling dependencies 1`] = ` 320 | "var foo = 'foo'; 321 | 322 | var bar = 'bar'; 323 | 324 | var bar_1 = bar; 325 | 326 | var baz = 'baz'; 327 | 328 | var index = \`\${foo}\${bar_1}\${baz}\`; 329 | 330 | export default index; 331 | " 332 | `; 333 | 334 | exports[`autoExternal(options) should handle disabling peerDependencies 1`] = ` 335 | "var foo = 'foo'; 336 | 337 | var bar = 'bar'; 338 | 339 | var bar_1 = bar; 340 | 341 | var baz = 'baz'; 342 | 343 | var index = \`\${foo}\${bar_1}\${baz}\`; 344 | 345 | export default index; 346 | " 347 | `; 348 | 349 | exports[`autoExternal(options) should handle extending external array 1`] = ` 350 | "import foo from 'foo'; 351 | import bar from 'bar'; 352 | import baz from 'baz'; 353 | 354 | var index = \`\${foo}\${bar}\${baz}\`; 355 | 356 | export default index; 357 | " 358 | `; 359 | 360 | exports[`autoExternal(options) should handle extending external function 1`] = ` 361 | "import foo from 'foo'; 362 | import bar from 'bar'; 363 | import baz from 'baz'; 364 | 365 | var index = \`\${foo}\${bar}\${baz}\`; 366 | 367 | export default index; 368 | " 369 | `; 370 | 371 | exports[`autoExternal(options) should handle scoped modules 1`] = ` 372 | "import foo from '@scope/foo'; 373 | import bar from '@scope/bar'; 374 | 375 | var baz = '@scope/baz'; 376 | 377 | var index = \`\${foo}\${bar}\${baz}\`; 378 | 379 | export default index; 380 | " 381 | `; 382 | -------------------------------------------------------------------------------- /__tests__/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const rollup = require('rollup'); 3 | const builtins = require('rollup-plugin-node-builtins'); 4 | const commonjs = require('rollup-plugin-commonjs'); 5 | const nodeResolve = require('rollup-plugin-node-resolve'); 6 | const autoExternal = require('../index'); 7 | 8 | const bundle = ({ input, external }, options) => { 9 | process.chdir(path.dirname(input)); 10 | 11 | return rollup 12 | .rollup({ 13 | external, 14 | input, 15 | plugins: [autoExternal(options), builtins(), nodeResolve(), commonjs()], 16 | }) 17 | .then(bundle => bundle.generate({ format: 'esm' })) 18 | .then(result => result.output[0].code) 19 | .then(code => expect(code).toMatchSnapshot()); 20 | }; 21 | 22 | let cwd; 23 | 24 | beforeAll(() => { 25 | cwd = process.cwd(); 26 | }); 27 | 28 | afterEach(() => { 29 | process.chdir(cwd); 30 | }); 31 | 32 | describe('autoExternal(options)', () => { 33 | it('should have a name', () => { 34 | expect(autoExternal().name).toEqual('auto-external'); 35 | }); 36 | 37 | it('should add dependencies by default', () => 38 | bundle({ 39 | input: path.resolve(__dirname, '../__fixtures__/deps/index.js'), 40 | })); 41 | 42 | it('should handle disabling dependencies', () => 43 | bundle( 44 | { input: path.resolve(__dirname, '../__fixtures__/deps/index.js') }, 45 | { dependencies: false } 46 | )); 47 | 48 | it('should add peerDependencies by default', () => 49 | bundle({ 50 | input: path.resolve(__dirname, '../__fixtures__/peer-deps/index.js'), 51 | })); 52 | 53 | it('should handle disabling peerDependencies', () => 54 | bundle( 55 | { input: path.resolve(__dirname, '../__fixtures__/peer-deps/index.js') }, 56 | { peerDependencies: false } 57 | )); 58 | 59 | it('should add builtins by default', () => 60 | bundle({ 61 | input: path.resolve(__dirname, '../__fixtures__/builtins/index.js'), 62 | })); 63 | 64 | it('should handle disabling builtins', () => 65 | bundle( 66 | { input: path.resolve(__dirname, '../__fixtures__/builtins/index.js') }, 67 | { builtins: false } 68 | )); 69 | 70 | it('should handle adding builtins for a specific Node.js version', () => 71 | bundle( 72 | { 73 | input: path.resolve( 74 | __dirname, 75 | '../__fixtures__/builtins-6.0.0/index.js' 76 | ), 77 | }, 78 | { builtins: '6.0.0' } 79 | )); 80 | 81 | it('should handle extending external array', () => 82 | bundle({ 83 | input: path.resolve(__dirname, '../__fixtures__/deps/index.js'), 84 | external: ['baz'], 85 | })); 86 | 87 | it('should handle extending external function', () => 88 | bundle({ 89 | input: path.resolve(__dirname, '../__fixtures__/deps/index.js'), 90 | external: id => id.includes('baz'), 91 | })); 92 | 93 | it('should handle a custom package file path', () => 94 | bundle( 95 | { input: path.resolve(__dirname, '../__fixtures__/deps/index.js') }, 96 | { 97 | packagePath: path.resolve( 98 | __dirname, 99 | '../__fixtures__/package-path/package.json' 100 | ), 101 | } 102 | )); 103 | 104 | it('should handle a directory path as the packagePath', () => 105 | bundle( 106 | { input: path.resolve(__dirname, '../__fixtures__/deps/index.js') }, 107 | { packagePath: path.resolve(__dirname, '../__fixtures__/package-path') } 108 | )); 109 | 110 | it('should handle cherry picked modules', () => 111 | bundle({ 112 | input: path.resolve(__dirname, '../__fixtures__/cherry-picked/index.js'), 113 | })); 114 | 115 | it('should handle scoped modules', () => 116 | bundle({ 117 | input: path.resolve(__dirname, '../__fixtures__/scoped/index.js'), 118 | })); 119 | }); 120 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const getBuiltins = require('builtins'); 2 | const path = require('path'); 3 | const readPkg = require('read-pkg'); 4 | const safeResolve = require('safe-resolve'); 5 | const semver = require('semver'); 6 | 7 | module.exports = ({ 8 | builtins = true, 9 | dependencies = true, 10 | packagePath, 11 | peerDependencies = true, 12 | } = {}) => ({ 13 | name: 'auto-external', 14 | options(opts) { 15 | const pkg = readPkg.sync(packagePath); 16 | let ids = []; 17 | 18 | if (dependencies && pkg.dependencies) { 19 | ids = ids.concat(Object.keys(pkg.dependencies)); 20 | } 21 | 22 | if (peerDependencies && pkg.peerDependencies) { 23 | ids = ids.concat(Object.keys(pkg.peerDependencies)); 24 | } 25 | 26 | if (builtins) { 27 | ids = ids.concat(getBuiltins(semver.valid(builtins))); 28 | } 29 | 30 | ids = ids.map(safeResolve).filter(Boolean); 31 | 32 | const external = id => { 33 | if (typeof opts.external === 'function' && opts.external(id)) { 34 | return true; 35 | } 36 | 37 | if (Array.isArray(opts.external) && opts.external.includes(id)) { 38 | return true; 39 | } 40 | 41 | /** 42 | * The `id` argument is a resolved path if `rollup-plugin-node-resolve` 43 | * and `rollup-plugin-commonjs` are included. 44 | */ 45 | const resolvedPath = safeResolve(id); 46 | 47 | if (resolvedPath === null) { 48 | return false; 49 | } 50 | 51 | const resolvedDirname = path.dirname(resolvedPath); 52 | 53 | return ids.some(idx => resolvedDirname.startsWith(path.dirname(idx))); 54 | }; 55 | 56 | return Object.assign({}, opts, { external }); 57 | }, 58 | }); 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugin-auto-external", 3 | "version": "3.0.0-alpha.0", 4 | "description": "Rollup plugin to automatically exclude package.json dependencies and peerDependencies from your bundle", 5 | "main": "index.js", 6 | "scripts": { 7 | "prepublishOnly": "npm test", 8 | "test": "$(npm bin)/jest --modulePaths=__fixtures__/node_modules" 9 | }, 10 | "keywords": [ 11 | "rollup", 12 | "plugin", 13 | "external", 14 | "auto", 15 | "dependencies", 16 | "peerDependencies" 17 | ], 18 | "author": "Steven Benisek ", 19 | "homepage": "https://github.com/stevenbenisek/rollup-plugin-auto-external", 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/stevenbenisek/rollup-plugin-auto-external.git" 23 | }, 24 | "license": "MIT", 25 | "engines": { 26 | "node": ">=6" 27 | }, 28 | "devDependencies": { 29 | "jest": "^24.1.0", 30 | "rollup": "^1.3.2", 31 | "rollup-plugin-node-resolve": "^4.0.1", 32 | "rollup-plugin-commonjs": "^9.2.1", 33 | "rollup-plugin-node-builtins": "^2.1.2" 34 | }, 35 | "peerDependencies": { 36 | "rollup": ">=0.45.2" 37 | }, 38 | "dependencies": { 39 | "builtins": "^2.0.0", 40 | "read-pkg": "^3.0.0", 41 | "safe-resolve": "^1.0.0", 42 | "semver": "^5.6.0" 43 | }, 44 | "files": [ 45 | "index.js" 46 | ] 47 | } 48 | --------------------------------------------------------------------------------