├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .jshintrc ├── .mailmap ├── AUTHORS ├── CHANGELOG ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE-MIT ├── README.md ├── docs ├── uglify-examples.md ├── uglify-options.md └── uglify-overview.md ├── package-lock.json ├── package.json ├── tasks ├── lib │ └── uglify.js └── uglify.js └── test ├── fixtures ├── expected │ ├── asciionly.js │ ├── beautify.js │ ├── comments.js │ ├── commentsWithImportant.js │ ├── compress.js │ ├── compress_explicit.js │ ├── compress_mangle.js │ ├── compress_mangle_banner.js │ ├── compress_mangle_beautify.js │ ├── compress_mangle_except.js │ ├── deep │ │ └── directory │ │ │ └── location │ │ │ └── source_map.js.map │ ├── expression.js │ ├── expression.json │ ├── mangle.js │ ├── mangleprops.js │ ├── mangleprops_withExcept.js │ ├── mangleprops_withExceptAndExceptionsFiles.js │ ├── mangleprops_withExceptionsFiles.js │ ├── mangleprops_withNameCacheFile1.js │ ├── mangleprops_withNameCacheFile2.js │ ├── mangleprops_withRegex.js │ ├── maxLineLen.js │ ├── multifile.js │ ├── quotes_double.js │ ├── quotes_original.js │ ├── quotes_single.js │ ├── screwIE8.js │ ├── source_map_custom_name │ ├── sourcemap_basic.js │ ├── sourcemap_basic.js.map │ ├── sourcemap_customDir.js │ ├── sourcemap_customName.js │ ├── sourcemap_customRoot.js │ ├── sourcemap_customRoot.js.map │ ├── sourcemap_customUrl.js │ ├── sourcemap_customUrl.js.map │ ├── sourcemap_functionName.js │ ├── sourcemap_functionName.js.fn.map │ ├── sourcemap_sources.js.map │ ├── sourcemapin.js │ ├── sourcemapin.js.map │ ├── sourcemapin_customUrl.js │ ├── sourcemapin_customUrl.js.map │ ├── sourcemapin_sources.js │ ├── sourcemapin_sources.js.map │ ├── sourcemaps_multiple1.js │ ├── sourcemaps_multiple1.js.map │ ├── sourcemaps_multiple1_fnName.js │ ├── sourcemaps_multiple1_fnName.js.fn.map │ ├── sourcemaps_multiple2.js │ ├── sourcemaps_multiple2.js.map │ ├── sourcemaps_multiple2_fnName.js │ ├── sourcemaps_multiple2_fnName.js.fn.map │ ├── uglify_name_cache.json │ └── wrap.js └── src │ ├── comments.js │ ├── exceptionsfile1.json │ ├── exceptionsfile2.json │ ├── expression.js │ ├── localization.js │ ├── mangleprops.js │ ├── mangleprops_withNameCache.js │ ├── mangleprops_withRegex.js │ ├── quotes.js │ ├── screwIE8.js │ ├── simple.js │ ├── simple.json │ ├── simple2.coffee │ ├── simple2.js │ └── simple2.map └── uglify_test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf 3 | *.js.map text eol=lf 4 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | FORCE_COLOR: 2 7 | 8 | jobs: 9 | run: 10 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | node: [12, 14, 16] 17 | os: [ubuntu-latest, windows-latest] 18 | 19 | steps: 20 | - name: Clone repository 21 | uses: actions/checkout@v2 22 | 23 | - name: Set up Node.js 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: ${{ matrix.node }} 27 | 28 | - name: Install npm dependencies 29 | run: npm ci 30 | 31 | - name: Run tests 32 | run: npm test 33 | 34 | # We test multiple Windows shells because of prior stdout buffering issues 35 | # filed against Grunt. https://github.com/joyent/node/issues/3584 36 | - name: Run PowerShell tests 37 | run: "npm test # PowerShell" # Pass comment to PS for easier debugging 38 | shell: powershell 39 | if: startsWith(matrix.os, 'windows') 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | tmp 4 | .idea 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "immed": true, 7 | "latedef": true, 8 | "newcap": true, 9 | "noarg": true, 10 | "node": true, 11 | "sub": true, 12 | "undef": true, 13 | "unused": true 14 | } 15 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Michał Gołębiowski-Owczarek 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | "Cowboy" Ben Alman (http://benalman.com) 2 | Tyler Kellen (http://goingslowly.com) 3 | Jarrod Overson (http://jarrodoverson.com) -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | v5.1.0: 2 | date: 2022-03-27 3 | changes: 4 | - Update dependencies. uglify-js ^3.15.2. 5 | - Requires node 12+. 6 | v5.0.0: 7 | date: 2020-07-16 8 | changes: 9 | - Requires node 10+. 10 | - Update dependencies. 11 | v4.0.1: 12 | date: 2019-03-21 13 | changes: 14 | - Update uglify-js to v3.5.0. 15 | - Update dependencies. 16 | v4.0.0: 17 | date: 2018-08-26 18 | changes: 19 | - Update dependencies. 20 | - Requires Node.js >= 6. 21 | v3.4.0: 22 | date: 2018-07-29 23 | changes: 24 | - Update uglify-js to v3.4.0. 25 | v3.3.0: 26 | date: 2017-12-24 27 | changes: 28 | - Update uglify-js to v3.3.0. 29 | v3.2.1: 30 | date: 2017-11-26 31 | changes: 32 | - Update uglify-js to v3.2.0. 33 | v3.1.0: 34 | date: 2017-09-11 35 | changes: 36 | - Update uglify-js to v3.1.0. 37 | v3.0.1: 38 | date: 2017-05-20 39 | changes: 40 | - Fix toplevel option. 41 | v3.0.0: 42 | date: 2017-05-12 43 | changes: 44 | - Update uglify-js to v3.0.4. 45 | v2.3.0: 46 | date: 2017-04-05 47 | changes: 48 | - Make CLI output less verbose. 49 | v2.2.1: 50 | date: 2017-03-31 51 | changes: 52 | - Fix banner option. 53 | v2.2.0: 54 | date: 2017-03-01 55 | changes: 56 | - Update uglify-js to v2.8.3. 57 | v2.1.0: 58 | date: 2017-02-08 59 | changes: 60 | - Show size changes in output. Switch to `object.assign`. 61 | v2.0.0: 62 | date: 2016-07-19 63 | changes: 64 | - Update uglify-js to v2.7.0. `screwIE8` is enabled by default. 65 | v1.0.2: 66 | date: 2016-07-19 67 | changes: 68 | - Update grunt to ^1.0.0. 69 | - Fix `beautify` when passed as an object. 70 | - Fix docs about `report` values. 71 | v1.0.1: 72 | date: 2016-03-16 73 | changes: 74 | - Downgrade maxmin for Node.js 0.10. 75 | v1.0.0: 76 | date: 2016-03-04 77 | changes: 78 | - Use uglify-js ~2.6.2 to fix sourcemap issue. 79 | - Improve docs for `global-defs` and `--define` options. 80 | - Add `sourceMapUrl` option. 81 | - Add `bare_returns` option. 82 | - Optionally set report verbosity level using report option. 83 | v0.11.1: 84 | date: 2016-01-29 85 | changes: 86 | - Update lodash to ^4.0.1. 87 | - Update grunt-contrib-clean to ^0.7.0. 88 | - Update grunt-contrib-jshint to ^0.12.0. 89 | v0.11.0: 90 | date: 2015-11-20 91 | changes: 92 | - Update uglify-js to ~2.6.0. 93 | v0.10.1: 94 | date: 2015-11-12 95 | changes: 96 | - Update uglify-js to ~2.5. 97 | v0.10.0: 98 | date: 2015-10-27 99 | changes: 100 | - Update uglify-js to ^2.5. 101 | v0.9.2: 102 | date: 2015-08-24 103 | changes: 104 | - Update uglify-js to ^2.4.24 105 | v0.9.1: 106 | date: 2015-04-07 107 | changes: 108 | - More fixes for `mangle` options. 109 | v0.9.0: 110 | date: 2015-04-07 111 | changes: 112 | - Add hook into uglify-js's mangling functionality. 113 | v0.8.1: 114 | date: 2015-03-30 115 | changes: 116 | - Lock uglify-js to 2.4.17 due to breaking changes. 117 | v0.8.0: 118 | date: 2015-02-19 119 | changes: 120 | - Add `screwIE8` option. 121 | - Fix issue with explicit `compress` in Node.js 0.12.0. 122 | v0.7.0: 123 | date: 2014-12-23 124 | changes: 125 | - Add `sourceMapRoot` options. 126 | - Update readme descriptions. 127 | - Remove reference to clean-css. 128 | v0.6.0: 129 | date: 2014-09-17 130 | changes: 131 | - Output fixes. 132 | - 'Add `ASCIIOnly` option.' 133 | - Other fixes. 134 | v0.5.1: 135 | date: 2014-07-25 136 | changes: 137 | - Update chalk to ^0.5.1. 138 | - Output updates. 139 | v0.4.0: 140 | date: 2014-03-01 141 | changes: 142 | - Remove grunt-lib-contrib dependency and add more colors. 143 | v0.3.3: 144 | date: 2014-02-27 145 | changes: 146 | - Remove unnecessary calls to `grunt.template.process`. 147 | v0.3.2: 148 | date: 2014-01-22 149 | changes: 150 | - Fix handling of `sourceMapIncludeSources` option. 151 | v0.3.1: 152 | date: 2014-01-20 153 | changes: 154 | - Fix relative path issue in sourcemaps. 155 | v0.3.0: 156 | date: 2014-01-16 157 | changes: 158 | - Refactor sourcemap support. 159 | v0.2.7: 160 | date: 2013-11-09 161 | changes: 162 | - 'Prepend banner if `sourceMap` option not set, addresses #109.' 163 | v0.2.6: 164 | date: 2013-11-08 165 | changes: 166 | - 'Merge #45, #53, #85 (#105 by way of duping #53).' 167 | - Add support for banners in uglified files with sourcemaps. 168 | - Update docs. 169 | v0.2.5: 170 | date: 2013-10-28 171 | changes: 172 | - Add warning for banners when using sourcemaps. 173 | v0.2.4: 174 | date: 2013-09-02 175 | changes: 176 | - 'Update sourcemap format via #83.' 177 | v0.2.3: 178 | date: 2013-06-10 179 | changes: 180 | - Add `footer` option. 181 | v0.2.2: 182 | date: 2013-05-31 183 | changes: 184 | - 'Revert #56 due to #58 until [chrome/239660](https://code.google.com/p/chromium/issues/detail?id=239660&q=sourcemappingurl&colspec=ID%20Pri%20M%20Iteration%20ReleaseBlock%20Cr%20Status%20Owner%20Summary%20OS%20Modified) [firefox/870361](https://bugzilla.mozilla.org/show_bug.cgi?id=870361) drop.' 185 | v0.2.1: 186 | date: 2013-05-22 187 | changes: 188 | - 'Update uglify-js to ~2.3.5 #55 #40.' 189 | - 'Change `sourcemappingUrl` syntax #56.' 190 | - 'Disable sorting of names for consistent mangling #44.' 191 | - 'Update docs for `sourceMapRoot` #47 #25.' 192 | v0.2.0: 193 | date: 2013-03-14 194 | changes: 195 | - No longer report gzip results by default. 196 | - Support `report` option. 197 | v0.1.2: 198 | date: 2013-01-30 199 | changes: 200 | - Add better error reporting. 201 | - Support for dynamic names of multiple sourcemaps. 202 | v0.1.1: 203 | date: 2013-02-15 204 | changes: 205 | - First official release for Grunt 0.4.0. 206 | v0.1.1rc6: 207 | date: 2013-01-18 208 | changes: 209 | - Update grunt/gruntplugin dependencies to rc6. 210 | - Change in-development grunt/gruntplugin dependency versions from tilde version ranges to specific versions. 211 | v0.1.1rc5: 212 | date: 2013-01-09 213 | changes: 214 | - Update to work with grunt v0.4.0rc5. 215 | - Switch back to `this.files` API. 216 | v0.1.0: 217 | date: 2012-11-28 218 | changes: 219 | - Work in progress, not officially released yet. 220 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Please see the [Contributing to grunt](https://gruntjs.com/contributing) guide for information on contributing to this project. 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-contrib-uglify 3 | * https://gruntjs.com/ 4 | * 5 | * Copyright (c) 2016 "Cowboy" Ben Alman, contributors 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | module.exports = function(grunt) { 12 | 13 | // Project configuration. 14 | grunt.initConfig({ 15 | jshint: { 16 | all: [ 17 | 'Gruntfile.js', 18 | 'tasks/**/*.js', 19 | '<%= nodeunit.tests %>' 20 | ], 21 | options: { 22 | jshintrc: '.jshintrc' 23 | } 24 | }, 25 | 26 | // Before generating any new files, remove any previously-created files. 27 | clean: { 28 | tests: ['tmp'] 29 | }, 30 | 31 | // Configuration to be run (and then tested). 32 | uglify: { 33 | compress: { 34 | files: { 35 | 'tmp/compress.js': ['test/fixtures/src/simple.js'] 36 | }, 37 | options: { 38 | mangle: false 39 | } 40 | }, 41 | compress_explicit: { 42 | files: { 43 | 'tmp/compress_explicit.js': ['test/fixtures/src/simple.js'] 44 | }, 45 | options: { 46 | compress: true 47 | } 48 | }, 49 | compress_mangle: { 50 | files: { 51 | 'tmp/compress_mangle.js': ['test/fixtures/src/simple.js'] 52 | } 53 | }, 54 | compress_mangle_banner: { 55 | files: { 56 | 'tmp/compress_mangle_banner.js': ['test/fixtures/src/simple.js'] 57 | }, 58 | options: { 59 | banner: '// banner without sourcemap\n' 60 | } 61 | }, 62 | no_src: { 63 | files: { 64 | 'tmp/compress_mangle.js': [] 65 | } 66 | }, 67 | compress_mangle_except: { 68 | files: { 69 | 'tmp/compress_mangle_except.js': ['test/fixtures/src/simple.js'] 70 | }, 71 | options: { 72 | mangle: { 73 | reserved: ['argumentC'] 74 | } 75 | } 76 | }, 77 | compress_mangle_beautify: { 78 | files: { 79 | 'tmp/compress_mangle_beautify.js': ['test/fixtures/src/simple.js'] 80 | }, 81 | options: { 82 | beautify: true, 83 | footer: '\n// This is a footer.' 84 | } 85 | }, 86 | multifile: { 87 | files: { 88 | 'tmp/multifile.js': ['test/fixtures/src/simple.js', 'test/fixtures/src/comments.js'] 89 | }, 90 | options: { 91 | mangle: false 92 | } 93 | }, 94 | comments: { 95 | src: 'test/fixtures/src/comments.js', 96 | dest: 'tmp/comments.js', 97 | options: { 98 | mangle: false, 99 | output: { 100 | comments: 'some' 101 | } 102 | } 103 | }, 104 | commentsWithImportant: { 105 | src: 'test/fixtures/src/comments.js', 106 | dest: 'tmp/commentsWithImportant.js', 107 | options: { 108 | mangle: false, 109 | output: { 110 | comments: /^!|@preserve|@license|@cc_on/i 111 | } 112 | } 113 | }, 114 | wrap: { 115 | src: 'test/fixtures/src/simple.js', 116 | dest: 'tmp/wrap.js', 117 | options: { 118 | compress: false, 119 | mangle: false, 120 | wrap: 'testExport' 121 | } 122 | }, 123 | maxLineLen: { 124 | src: 'test/fixtures/src/simple2.js', 125 | dest: 'tmp/maxLineLen.js', 126 | options: { 127 | mangle: false, 128 | output: { 129 | max_line_len: 100 130 | } 131 | } 132 | }, 133 | ASCIIOnly: { 134 | src: 'test/fixtures/src/localization.js', 135 | dest: 'tmp/asciionly.js', 136 | options: { 137 | mangle: false, 138 | output: { 139 | ascii_only: true 140 | } 141 | } 142 | }, 143 | screwIE8: { 144 | src: 'test/fixtures/src/screwIE8.js', 145 | dest: 'tmp/screwIE8.js', 146 | options: { 147 | ie8: true 148 | } 149 | }, 150 | sourcemap_basic: { 151 | src: 'test/fixtures/src/simple.js', 152 | dest: 'tmp/sourcemap_basic.js', 153 | options: { 154 | sourceMap: true 155 | } 156 | }, 157 | sourcemap_customName: { 158 | src: 'test/fixtures/src/simple.js', 159 | dest: 'tmp/sourcemap_customName.js', 160 | options: { 161 | sourceMap: true, 162 | sourceMapName: 'tmp/source_map_custom_name' 163 | } 164 | }, 165 | sourcemap_customDir: { 166 | src: 'test/fixtures/src/simple.js', 167 | dest: 'tmp/sourcemap_customDir.js', 168 | options: { 169 | sourceMap: true, 170 | sourceMapName: 'tmp/deep/directory/location/source_map.js.map' 171 | } 172 | }, 173 | sourcemap_customRoot: { 174 | src: 'test/fixtures/src/simple.js', 175 | dest: 'tmp/sourcemap_customRoot.js', 176 | options: { 177 | sourceMap: { 178 | root: 'https://github.com/RReverser/grunt-contrib-uglify/tree/master/tmp' 179 | } 180 | } 181 | }, 182 | sourcemap_customUrl: { 183 | src: 'test/fixtures/src/simple.js', 184 | dest: 'tmp/sourcemap_customUrl.js', 185 | options: { 186 | sourceMap: { 187 | url: 'https://www.test.com/test/sourcemap_customUrl.js.map' 188 | } 189 | } 190 | }, 191 | sourcemap_functionName: { 192 | src: 'test/fixtures/src/simple.js', 193 | dest: 'tmp/sourcemap_functionName.js', 194 | options: { 195 | sourceMap: true, 196 | sourceMapName: function(dest) { 197 | return dest + '.fn.map'; 198 | } 199 | } 200 | }, 201 | sourcemap_multiple: { 202 | files: { 203 | 'tmp/sourcemaps_multiple1.js': ['test/fixtures/src/simple.js'], 204 | 'tmp/sourcemaps_multiple2.js': ['test/fixtures/src/comments.js'] 205 | }, 206 | options: { 207 | sourceMap: true 208 | } 209 | }, 210 | sourcemap_multipleFunctionNames: { 211 | files: { 212 | 'tmp/sourcemaps_multiple1_fnName.js': ['test/fixtures/src/simple.js'], 213 | 'tmp/sourcemaps_multiple2_fnName.js': ['test/fixtures/src/comments.js'] 214 | }, 215 | options: { 216 | sourceMap: true, 217 | sourceMapName: function(dest) { 218 | return dest + '.fn.map'; 219 | } 220 | } 221 | }, 222 | sourcemapin: { 223 | files: { 224 | 'tmp/sourcemapin.js': ['test/fixtures/src/simple2.js'] 225 | }, 226 | options: { 227 | mangle: false, 228 | banner: '// Hello World\n', 229 | sourceMap: { 230 | includeSources: false 231 | }, 232 | sourceMapIn: function() { 233 | return 'test/fixtures/src/simple2.map'; 234 | } 235 | } 236 | }, 237 | sourcemap_sources: { 238 | files: { 239 | 'tmp/sourcemap_sources.js': ['test/fixtures/src/simple.js'] 240 | }, 241 | options: { 242 | sourceMap: { 243 | includeSources: true 244 | } 245 | } 246 | }, 247 | sourcemapin_sources: { 248 | files: { 249 | 'tmp/sourcemapin_sources.js': ['test/fixtures/src/simple2.js'] 250 | }, 251 | options: { 252 | sourceMap: { 253 | includeSources: true 254 | }, 255 | sourceMapIn: function() { 256 | return 'test/fixtures/src/simple2.map'; 257 | } 258 | } 259 | }, 260 | sourcemapin_customUrl: { 261 | files: { 262 | 'tmp/sourcemapin_customUrl.js': ['test/fixtures/src/simple2.js'] 263 | }, 264 | options: { 265 | sourceMap: { 266 | includeSources: true, 267 | url: 'sourcemapin_customUrl.js.map' 268 | }, 269 | sourceMapIn: function() { 270 | return 'test/fixtures/src/simple2.map'; 271 | } 272 | } 273 | }, 274 | expression_json: { 275 | files: { 276 | 'tmp/expression.json': ['test/fixtures/src/simple.json'] 277 | }, 278 | options: { 279 | parse: { 280 | expression: true 281 | }, 282 | mangle: false, 283 | compress: false 284 | } 285 | }, 286 | expression_js: { 287 | files: { 288 | 'tmp/expression.js': ['test/fixtures/src/expression.js'] 289 | }, 290 | options: { 291 | parse: { 292 | expression: true 293 | }, 294 | mangle: false, 295 | compress: false 296 | } 297 | }, 298 | mangleprops: { 299 | files: { 300 | 'tmp/mangleprops.js': ['test/fixtures/src/mangleprops.js'] 301 | }, 302 | options: { 303 | mangle: { 304 | properties: true 305 | } 306 | } 307 | }, 308 | mangleprops_withExcept: { 309 | files: { 310 | 'tmp/mangleprops_withExcept.js': ['test/fixtures/src/mangleprops.js'] 311 | }, 312 | options: { 313 | mangle: { 314 | reserved: ['dontMangleMeVariable'], 315 | properties: true 316 | } 317 | } 318 | }, 319 | mangleprops_withExceptionsFiles: { 320 | files: { 321 | 'tmp/mangleprops_withExceptionsFiles.js': ['test/fixtures/src/mangleprops.js'] 322 | }, 323 | options: { 324 | mangle: { 325 | toplevel: true, 326 | properties: true 327 | }, 328 | exceptionsFiles: ['test/fixtures/src/exceptionsfile1.json', 'test/fixtures/src/exceptionsfile2.json'] 329 | } 330 | }, 331 | mangleprops_withExceptAndExceptionsFiles: { 332 | files: { 333 | 'tmp/mangleprops_withExceptAndExceptionsFiles.js': ['test/fixtures/src/mangleprops.js'] 334 | }, 335 | options: { 336 | mangle: { 337 | toplevel: true, 338 | reserved: ['dontMangleMeVariable'], 339 | properties: true 340 | }, 341 | exceptionsFiles: ['test/fixtures/src/exceptionsfile1.json', 'test/fixtures/src/exceptionsfile2.json'] 342 | } 343 | }, 344 | mangleprops_withNameCacheFile: { 345 | files: { 346 | 'tmp/mangleprops_withNameCacheFile1.js': ['test/fixtures/src/mangleprops.js'], 347 | 'tmp/mangleprops_withNameCacheFile2.js': ['test/fixtures/src/mangleprops_withNameCache.js'] 348 | }, 349 | options: { 350 | mangle: { 351 | toplevel: true, 352 | properties: true 353 | }, 354 | nameCache: 'tmp/uglify_name_cache.json' 355 | } 356 | }, 357 | mangleprops_withRegex: { 358 | files: { 359 | 'tmp/mangleprops_withRegex.js': ['test/fixtures/src/mangleprops_withRegex.js'] 360 | }, 361 | options: { 362 | mangle: { 363 | properties: { 364 | regex: /^[^#].*/ 365 | } 366 | } 367 | } 368 | }, 369 | quotes_single: { 370 | files: { 371 | 'tmp/quotes_single.js': ['test/fixtures/src/quotes.js'] 372 | }, 373 | options: { 374 | output: { 375 | quote_style: 1 376 | } 377 | } 378 | }, 379 | quotes_double: { 380 | files: { 381 | 'tmp/quotes_double.js': ['test/fixtures/src/quotes.js'] 382 | }, 383 | options: { 384 | output: { 385 | quote_style: 2 386 | } 387 | } 388 | }, 389 | quotes_original: { 390 | files: { 391 | 'tmp/quotes_original.js': ['test/fixtures/src/quotes.js'] 392 | }, 393 | options: { 394 | output: { 395 | quote_style: 3 396 | } 397 | } 398 | }, 399 | mangle_isNotObject: { 400 | files: { 401 | 'tmp/mangle.js': ['test/fixtures/src/simple.js'] 402 | }, 403 | mangle: true 404 | }, 405 | beautify_Object: { 406 | files: { 407 | 'tmp/beautify.js': ['test/fixtures/src/simple.js'] 408 | }, 409 | options: { 410 | beautify: { 411 | ascii_only: true, 412 | indent_start: 2, 413 | max_line_len: 55 414 | } 415 | } 416 | } 417 | }, 418 | 419 | // Unit tests. 420 | nodeunit: { 421 | tests: ['test/*_test.js'] 422 | } 423 | }); 424 | 425 | // task that expects its argument (another task) to fail 426 | grunt.registerTask('expectFail', function() { 427 | var task = this.args.join(':'); 428 | 429 | var done = this.async(); 430 | 431 | function onComplete(error, result) { 432 | grunt.log.write('\n > ' + result.stdout.split('\n').join('\n > ') + '\n'); 433 | var rv = error ? true : new Error('Task ' + task + ' unexpectedly passed.'); 434 | done(rv); 435 | } 436 | 437 | grunt.util.spawn({ 438 | grunt: true, 439 | args: task 440 | }, onComplete); 441 | }); 442 | 443 | // Actually load this plugin's task(s). 444 | grunt.loadTasks('tasks'); 445 | 446 | // These plugins provide necessary tasks. 447 | grunt.loadNpmTasks('grunt-contrib-jshint'); 448 | grunt.loadNpmTasks('grunt-contrib-clean'); 449 | grunt.loadNpmTasks('grunt-contrib-nodeunit'); 450 | grunt.loadNpmTasks('grunt-contrib-internal'); 451 | 452 | // Whenever the "test" task is run, first clean the "tmp" dir, then run this 453 | // plugin's task(s), then test the result. 454 | grunt.registerTask('test', [ 455 | 'jshint', 456 | 'clean', 457 | 'uglify', 458 | 'nodeunit' 459 | ]); 460 | 461 | // By default, lint and run all tests. 462 | grunt.registerTask('default', ['test', 'build-contrib']); 463 | 464 | }; 465 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 "Cowboy" Ben Alman, contributors 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grunt-contrib-uglify v5.2.1 [![Build Status](https://github.com/gruntjs/grunt-contrib-uglify/workflows/Tests/badge.svg)](https://github.com/gruntjs/grunt-contrib-uglify/actions?workflow=Tests) 2 | 3 | > Minify JavaScript files with UglifyJS 4 | 5 | 6 | 7 | ## Getting Started 8 | 9 | If you haven't used [Grunt](https://gruntjs.com/) before, be sure to check out the [Getting Started](https://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](https://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: 10 | 11 | ```shell 12 | npm install grunt-contrib-uglify --save-dev 13 | ``` 14 | 15 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: 16 | 17 | ```js 18 | grunt.loadNpmTasks('grunt-contrib-uglify'); 19 | ``` 20 | 21 | 22 | 23 | 24 | ## Uglify task 25 | _Run this task with the `grunt uglify` command._ 26 | 27 | Task targets, files and options may be specified according to the grunt [Configuring tasks](https://gruntjs.com/configuring-tasks) guide. 28 | 29 | ### Options 30 | 31 | This task primarily delegates to [UglifyJS](https://github.com/mishoo/UglifyJS2), so please consider their documentation as required reading for advanced configuration. 32 | 33 | 34 | ###### Deprecated options from `2.x` 35 | 36 | Option | Replacement 37 | ----------------------- | ----------- 38 | ASCIIOnly | output.ascii_only 39 | enclose | — 40 | exportAll | — 41 | expression | parse.expression 42 | indentLevel | output.indent_level 43 | mangleProperties | mangle.properties 44 | maxLineLen | output.max\_line_len 45 | preserveComments | output.comments 46 | quoteStyle | output.quote_style 47 | screwIE8 | !ie8 48 | sourceMapIncludeSources | sourceMap.includeSources 49 | sourceMapRoot | sourceMap.root 50 | sourceMapUrl | sourceMap.url 51 | 52 | 53 | #### mangle 54 | Type: `Boolean` `Object` 55 | Default: `{}` 56 | 57 | Turn on or off mangling with default options. If an `Object` is specified, it is passed directly to `ast.mangle_names()` *and* `ast.compute_char_frequency()` (mimicking command line behavior). [View all options here](https://github.com/mishoo/UglifyJS2#mangle-options). 58 | 59 | #### compress 60 | Type: `Boolean` `Object` 61 | Default: `{}` 62 | 63 | Turn on or off source compression with default options. If an `Object` is specified, it is passed as options to `UglifyJS.Compressor()`. [View all options here](https://github.com/mishoo/UglifyJS2#compress-options). 64 | 65 | #### beautify 66 | Type: `Boolean` `Object` 67 | Default: `false` 68 | 69 | Turns on beautification of the generated source code. [View all options here](https://github.com/mishoo/UglifyJS2#output-options) 70 | 71 | ###### parse.expression 72 | Type: `Boolean` 73 | Default: `false` 74 | 75 | Parse a single expression, rather than a program (for parsing JSON) 76 | 77 | #### report 78 | Type: `string` 79 | Choices: `'min'`, `'gzip'` 80 | Default: `'min'` 81 | 82 | Report minification result or both minification and gzip results. 83 | This is useful to see exactly how well uglify-js is performing but using `'gzip'` will make the task take 5-10x longer to complete. [Example output](https://github.com/sindresorhus/maxmin#readme). 84 | 85 | #### sourceMap 86 | Type: `Boolean` 87 | Default: `false` 88 | 89 | If `true`, a source map file will be generated in the same directory as the `dest` file. By default it will have the same basename as the `dest` file, but with a `.map` extension. 90 | 91 | #### sourceMapName 92 | Type: `String` `Function` 93 | Default: `undefined` 94 | 95 | To customize the name or location of the generated source map, pass a string to indicate where to write the source map to. If a function is provided, the uglify destination is passed as the argument and the return value will be used as the file name. 96 | 97 | #### sourceMapIn 98 | Type: `String` `Function` 99 | Default: `undefined` 100 | 101 | The location of an input source map from an earlier compilation, e.g. from CoffeeScript. If a function is provided, the 102 | uglify source is passed as the argument and the return value will be used as the sourceMap name. This only makes sense 103 | when there's one source file. 104 | 105 | #### sourceMap.includeSources 106 | Type: `Boolean` 107 | Default: `false` 108 | 109 | Pass this flag if you want to include the content of source files in the source map as sourcesContent property. 110 | 111 | ###### sourceMap.root 112 | Type: `String` 113 | Default: `undefined` 114 | 115 | With this option you can customize root URL that browser will use when looking for sources. 116 | 117 | If the sources are not absolute URLs after prepending of the `sourceMap.root`, the sources are resolved relative to the source map. 118 | 119 | #### sourceMap.url 120 | Type: `String` 121 | Default: `undefined` 122 | 123 | Override the calculated value for `sourceMappingURL` in the source map. This is useful if the source map location is not relative to the base path of the minified file, i.e. when using a CDN 124 | 125 | #### wrap 126 | Type: `String` 127 | Default: `undefined` 128 | 129 | Wrap all of the code in a closure, an easy way to make sure nothing is leaking. 130 | For variables that need to be public `exports` and `global` variables are made available. 131 | The value of wrap is the global variable exports will be available as. 132 | 133 | #### output.ascii_only 134 | Type: `Boolean` 135 | Default: `false` 136 | 137 | Enables to encode non-ASCII characters as \uXXXX. 138 | 139 | #### output.comments 140 | Type: `Boolean` `String` `Function` 141 | Default: `undefined` 142 | Options: `false` `'all'` `'some'` 143 | 144 | Turn on preservation of comments. 145 | 146 | - `false` will strip all comments 147 | - `'all'` will preserve all comments in code blocks that have not been squashed or dropped 148 | - `'some'` will preserve all comments that include a closure compiler style directive (`@preserve` `@license` `@cc_on`) 149 | - `Function` specify your own comment preservation function. You will be passed the current node and the current comment and are expected to return either `true` or `false` 150 | - `RegExp` `'/[RegExp]/'` will preserve comments matching given RegExp or stringified RegExp 151 | 152 | #### banner 153 | Type: `String` 154 | Default: `''` 155 | 156 | This string will be prepended to the minified output. Template strings (e.g. `<%= config.value %>`) will be expanded automatically. 157 | 158 | #### footer 159 | Type: `String` 160 | Default: `''` 161 | 162 | This string will be appended to the minified output. Template strings (e.g. `<%= config.value %>`) will be expanded automatically. 163 | 164 | #### ie8 165 | Type: `Boolean` 166 | Default: `false` 167 | 168 | Set this to `true` if you still care about full compliance with Internet Explorer 6-8 quirks. 169 | 170 | #### mangle.properties 171 | Type: `Boolean` `Object` 172 | Default: `false` 173 | 174 | Turn on or off property mangling with default options. If an `Object` is specified, it is passed directly to `ast.mangle_properties()` (mimicking command line behavior). [View all options here](https://github.com/mishoo/UglifyJS2#mangle-options). 175 | 176 | #### reserveDOMProperties 177 | Type: `Boolean` 178 | Default: `false` 179 | 180 | Use this flag in conjunction with `mangle.properties` to prevent built-in browser object properties from being mangled. 181 | 182 | #### exceptionsFiles 183 | Type: `Array` 184 | Default: `[]` 185 | 186 | Use this with `mangle.properties` to pass one or more JSON files containing a list of variables and object properties 187 | that should not be mangled. See the [UglifyJS docs](https://www.npmjs.com/package/uglify-js) for more info on the file syntax. 188 | 189 | #### nameCache 190 | Type: `String` 191 | Default: `''` 192 | 193 | A string that is a path to a JSON cache file that uglify will create and use to coordinate symbol mangling between 194 | multiple runs of uglify. Note: this generated file uses the same JSON format as the `exceptionsFiles` files. 195 | 196 | #### output.quote_style 197 | Type: `Integer` 198 | Default: `0` 199 | 200 | Preserve or enforce quotation mark style. 201 | 202 | * `0` will use single or double quotes such as to minimize the number of bytes (prefers double quotes when both will do) 203 | * `1` will always use single quotes 204 | * `2` will always use double quotes 205 | * `3` will preserve original quotation marks 206 | 207 | ### Usage examples 208 | 209 | #### Basic compression 210 | 211 | This configuration will compress and mangle the input files using the default options. 212 | 213 | ```js 214 | // Project configuration. 215 | grunt.initConfig({ 216 | uglify: { 217 | my_target: { 218 | files: { 219 | 'dest/output.min.js': ['src/input1.js', 'src/input2.js'] 220 | } 221 | } 222 | } 223 | }); 224 | ``` 225 | 226 | #### No mangling 227 | 228 | Specify `mangle: false` to prevent changes to your variable and function names. 229 | 230 | ```js 231 | // Project configuration. 232 | grunt.initConfig({ 233 | uglify: { 234 | options: { 235 | mangle: false 236 | }, 237 | my_target: { 238 | files: { 239 | 'dest/output.min.js': ['src/input.js'] 240 | } 241 | } 242 | } 243 | }); 244 | ``` 245 | 246 | #### Reserved identifiers 247 | 248 | You can specify identifiers to leave untouched with an `reserved` array in the `mangle` options. 249 | 250 | ```js 251 | // Project configuration. 252 | grunt.initConfig({ 253 | uglify: { 254 | options: { 255 | mangle: { 256 | reserved: ['jQuery', 'Backbone'] 257 | } 258 | }, 259 | my_target: { 260 | files: { 261 | 'dest/output.min.js': ['src/input.js'] 262 | } 263 | } 264 | } 265 | }); 266 | ``` 267 | 268 | #### Source maps 269 | 270 | Generate a source map by setting the `sourceMap` option to `true`. The generated 271 | source map will be in the same directory as the destination file. Its name will be 272 | the basename of the destination file with a `.map` extension. Override these 273 | defaults with the `sourceMapName` attribute. 274 | 275 | ```js 276 | // Project configuration. 277 | grunt.initConfig({ 278 | uglify: { 279 | my_target: { 280 | options: { 281 | sourceMap: true, 282 | sourceMapName: 'path/to/sourcemap.map' 283 | }, 284 | files: { 285 | 'dest/output.min.js': ['src/input.js'] 286 | } 287 | } 288 | } 289 | }); 290 | ``` 291 | 292 | #### Advanced source maps 293 | 294 | Set the `sourceMap.includeSources` option to `true` to embed your sources directly into the map. To include 295 | a source map from a previous compilation pass it as the value of the `sourceMapIn` option. 296 | 297 | ```js 298 | // Project configuration. 299 | grunt.initConfig({ 300 | uglify: { 301 | my_target: { 302 | options: { 303 | sourceMap: { 304 | includeSources: true 305 | }, 306 | sourceMapIn: 'example/coffeescript-sourcemap.js', // input sourcemap from a previous compilation 307 | }, 308 | files: { 309 | 'dest/output.min.js': ['src/input.js'], 310 | }, 311 | }, 312 | }, 313 | }); 314 | ``` 315 | 316 | Refer to the [UglifyJS SourceMap Documentation](https://github.com/mishoo/UglifyJS2#source-map-options) for more information. 317 | 318 | #### Turn off console warnings 319 | 320 | Specify `drop_console: true` as part of the `compress` options to discard calls to `console.*` functions. 321 | This will suppress warning messages in the console. 322 | 323 | ```js 324 | // Project configuration. 325 | grunt.initConfig({ 326 | uglify: { 327 | options: { 328 | compress: { 329 | drop_console: true 330 | } 331 | }, 332 | my_target: { 333 | files: { 334 | 'dest/output.min.js': ['src/input.js'] 335 | } 336 | } 337 | } 338 | }); 339 | ``` 340 | 341 | #### Beautify 342 | 343 | Specify `beautify: true` to beautify your code for debugging/troubleshooting purposes. 344 | Pass an object to manually configure any other output options. 345 | 346 | See [UglifyJS documentation](https://github.com/mishoo/UglifyJS2#output-options) for more information. 347 | 348 | ```js 349 | // Project configuration. 350 | grunt.initConfig({ 351 | uglify: { 352 | my_target: { 353 | options: { 354 | beautify: true 355 | }, 356 | files: { 357 | 'dest/output.min.js': ['src/input.js'] 358 | } 359 | }, 360 | my_advanced_target: { 361 | options: { 362 | beautify: { 363 | width: 80 364 | } 365 | }, 366 | files: { 367 | 'dest/output.min.js': ['src/input.js'] 368 | } 369 | } 370 | } 371 | }); 372 | ``` 373 | 374 | #### Banner comments 375 | 376 | In this example, running `grunt uglify:my_target` will prepend a banner created by interpolating the `banner` template string with the config object. Here, those properties are the values imported from the `package.json` file (which are available via the `pkg` config property) plus today's date. 377 | 378 | _Note: you don't have to use an external JSON file. It's also valid to create the `pkg` object inline in the config. That being said, if you already have a JSON file, you might as well reference it._ 379 | 380 | ```js 381 | // Project configuration. 382 | grunt.initConfig({ 383 | pkg: grunt.file.readJSON('package.json'), 384 | uglify: { 385 | options: { 386 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + 387 | '<%= grunt.template.today("yyyy-mm-dd") %> */' 388 | }, 389 | my_target: { 390 | files: { 391 | 'dest/output.min.js': ['src/input.js'] 392 | } 393 | } 394 | } 395 | }); 396 | ``` 397 | 398 | #### Conditional compilation 399 | 400 | You can also enable UglifyJS conditional compilation. This is commonly used to remove debug code blocks for production builds. This is equivalent to the command line `--define` option. 401 | 402 | See [UglifyJS global definitions documentation](https://github.com/mishoo/UglifyJS2#conditional-compilation) for more information. 403 | 404 | ```js 405 | // Project configuration. 406 | grunt.initConfig({ 407 | uglify: { 408 | options: { 409 | compress: { 410 | global_defs: { 411 | 'DEBUG': false 412 | }, 413 | dead_code: true 414 | } 415 | }, 416 | my_target: { 417 | files: { 418 | 'dest/output.min.js': ['src/input.js'] 419 | } 420 | } 421 | } 422 | }); 423 | ``` 424 | 425 | #### Compiling all files in a folder dynamically 426 | 427 | This configuration will compress and mangle the files dynamically. 428 | 429 | ```js 430 | // Project configuration. 431 | grunt.initConfig({ 432 | uglify: { 433 | my_target: { 434 | files: [{ 435 | expand: true, 436 | cwd: 'src/js', 437 | src: '**/*.js', 438 | dest: 'dest/js' 439 | }] 440 | } 441 | } 442 | }); 443 | ``` 444 | 445 | #### Compiling all files separately in the each their path 446 | 447 | This configuration will compress and mangle all js files separately in each folder. 448 | 449 | Also exclude jQuery for mangling and ignore all `*.min.js` files. 450 | 451 | ```js 452 | // Project configuration. 453 | uglify: { 454 | dev: { 455 | options: { 456 | mangle: { 457 | reserved: ['jQuery'] 458 | } 459 | }, 460 | files: [{ 461 | expand: true, 462 | src: ['dist/assets/js/*.js', '!dist/assets/js/*.min.js'], 463 | dest: 'dist/assets', 464 | cwd: '.', 465 | rename: function (dst, src) { 466 | // To keep the source js files and make new files as `*.min.js`: 467 | // return dst + '/' + src.replace('.js', '.min.js'); 468 | // Or to override to src: 469 | return src; 470 | } 471 | }] 472 | } 473 | }, 474 | ``` 475 | 476 | #### Turn on object property name mangling 477 | 478 | This configuration will turn on object property name mangling, but not mangle built-in browser object properties. 479 | Additionally, variables and object properties listed in the `myExceptionsFile.json` will be mangled. For more info, 480 | on the format of the exception file format please see the [UglifyJS docs](https://www.npmjs.com/package/uglify-js). 481 | 482 | ```js 483 | // Project configuration. 484 | grunt.initConfig({ 485 | uglify: { 486 | options: { 487 | mangle: { 488 | properties: true 489 | }, 490 | reserveDOMProperties: true, 491 | exceptionsFiles: [ 'myExceptionsFile.json' ] 492 | }, 493 | my_target: { 494 | files: { 495 | 'dest/output.min.js': ['src/input.js'] 496 | } 497 | } 498 | } 499 | }); 500 | ``` 501 | 502 | #### Turn on use of name mangling cache 503 | 504 | Turn on use of name mangling cache to coordinate mangled symbols between outputted uglify files. uglify will the 505 | generate a JSON cache file with the name provided in the options. Note: this generated file uses the same JSON format 506 | as the `exceptionsFiles` files. 507 | 508 | ```js 509 | // Project configuration. 510 | grunt.initConfig({ 511 | uglify: { 512 | options: { 513 | nameCache: '.tmp/grunt-uglify-cache.json', 514 | }, 515 | my_target: { 516 | files: { 517 | 'dest/output1.min.js': ['src/input1.js'], 518 | 'dest/output2.min.js': ['src/input2.js'] 519 | } 520 | } 521 | } 522 | }); 523 | ``` 524 | 525 | 526 | ## Release History 527 | 528 | * 2022-03-27   v5.1.0   Update dependencies. uglify-js ^3.15.2. Requires node 12+. 529 | * 2020-07-16   v5.0.0   Requires node 10+. Update dependencies. 530 | * 2019-03-21   v4.0.1   Update uglify-js to v3.5.0. Update dependencies. 531 | * 2018-08-26   v4.0.0   Update dependencies. Requires Node.js >= 6. 532 | * 2018-07-29   v3.4.0   Update uglify-js to v3.4.0. 533 | * 2017-12-24   v3.3.0   Update uglify-js to v3.3.0. 534 | * 2017-11-26   v3.2.1   Update uglify-js to v3.2.0. 535 | * 2017-09-11   v3.1.0   Update uglify-js to v3.1.0. 536 | * 2017-05-20   v3.0.1   Fix toplevel option. 537 | * 2017-05-12   v3.0.0   Update uglify-js to v3.0.4. 538 | * 2017-04-05   v2.3.0   Make CLI output less verbose. 539 | * 2017-03-31   v2.2.1   Fix banner option. 540 | * 2017-03-01   v2.2.0   Update uglify-js to v2.8.3. 541 | * 2017-02-08   v2.1.0   Show size changes in output. Switch to `object.assign`. 542 | * 2016-07-19   v2.0.0   Update uglify-js to v2.7.0. `screwIE8` is enabled by default. 543 | * 2016-07-19   v1.0.2   Update grunt to ^1.0.0. Fix `beautify` when passed as an object. Fix docs about `report` values. 544 | * 2016-03-16   v1.0.1   Downgrade maxmin for Node.js 0.10. 545 | * 2016-03-04   v1.0.0   Use uglify-js ~2.6.2 to fix sourcemap issue. Improve docs for `global-defs` and `--define` options. Add `sourceMapUrl` option. Add `bare_returns` option. Optionally set report verbosity level using report option. 546 | * 2016-01-29   v0.11.1   Update lodash to ^4.0.1. Update grunt-contrib-clean to ^0.7.0. Update grunt-contrib-jshint to ^0.12.0. 547 | * 2015-11-20   v0.11.0   Update uglify-js to ~2.6.0. 548 | * 2015-11-12   v0.10.1   Update uglify-js to ~2.5. 549 | * 2015-10-27   v0.10.0   Update uglify-js to ^2.5. 550 | * 2015-08-24   v0.9.2   Update uglify-js to ^2.4.24 551 | * 2015-04-07   v0.9.1   More fixes for `mangle` options. 552 | * 2015-04-07   v0.9.0   Add hook into uglify-js's mangling functionality. 553 | * 2015-03-30   v0.8.1   Lock uglify-js to 2.4.17 due to breaking changes. 554 | * 2015-02-19   v0.8.0   Add `screwIE8` option. Fix issue with explicit `compress` in Node.js 0.12.0. 555 | * 2014-12-23   v0.7.0   Add `sourceMapRoot` options. Update readme descriptions. Remove reference to clean-css. 556 | * 2014-09-17   v0.6.0   Output fixes. Add `ASCIIOnly` option. Other fixes. 557 | * 2014-07-25   v0.5.1   Update chalk to ^0.5.1. Output updates. 558 | * 2014-03-01   v0.4.0   Remove grunt-lib-contrib dependency and add more colors. 559 | * 2014-02-27   v0.3.3   Remove unnecessary calls to `grunt.template.process`. 560 | * 2014-01-22   v0.3.2   Fix handling of `sourceMapIncludeSources` option. 561 | * 2014-01-20   v0.3.1   Fix relative path issue in sourcemaps. 562 | * 2014-01-16   v0.3.0   Refactor sourcemap support. 563 | * 2013-11-09   v0.2.7   Prepend banner if `sourceMap` option not set, addresses #109. 564 | * 2013-11-08   v0.2.6   Merge #45, #53, #85 (#105 by way of duping #53). Add support for banners in uglified files with sourcemaps. Update docs. 565 | * 2013-10-28   v0.2.5   Add warning for banners when using sourcemaps. 566 | * 2013-09-02   v0.2.4   Update sourcemap format via #83. 567 | * 2013-06-10   v0.2.3   Add `footer` option. 568 | * 2013-05-31   v0.2.2   Revert #56 due to #58 until [chrome/239660](https://code.google.com/p/chromium/issues/detail?id=239660&q=sourcemappingurl&colspec=ID%20Pri%20M%20Iteration%20ReleaseBlock%20Cr%20Status%20Owner%20Summary%20OS%20Modified) [firefox/870361](https://bugzilla.mozilla.org/show_bug.cgi?id=870361) drop. 569 | * 2013-05-22   v0.2.1   Update uglify-js to ~2.3.5 #55 #40. Change `sourcemappingUrl` syntax #56. Disable sorting of names for consistent mangling #44. Update docs for `sourceMapRoot` #47 #25. 570 | * 2013-03-14   v0.2.0   No longer report gzip results by default. Support `report` option. 571 | * 2013-01-30   v0.1.2   Add better error reporting. Support for dynamic names of multiple sourcemaps. 572 | * 2013-02-15   v0.1.1   First official release for Grunt 0.4.0. 573 | * 2013-01-18   v0.1.1rc6   Update grunt/gruntplugin dependencies to rc6. Change in-development grunt/gruntplugin dependency versions from tilde version ranges to specific versions. 574 | * 2013-01-09   v0.1.1rc5   Update to work with grunt v0.4.0rc5. Switch back to `this.files` API. 575 | * 2012-11-28   v0.1.0   Work in progress, not officially released yet. 576 | 577 | --- 578 | 579 | Task submitted by ["Cowboy" Ben Alman](http://benalman.com) 580 | 581 | *This file was generated on Fri Apr 15 2022 21:00:08.* 582 | -------------------------------------------------------------------------------- /docs/uglify-examples.md: -------------------------------------------------------------------------------- 1 | # Usage examples 2 | 3 | ## Basic compression 4 | 5 | This configuration will compress and mangle the input files using the default options. 6 | 7 | ```js 8 | // Project configuration. 9 | grunt.initConfig({ 10 | uglify: { 11 | my_target: { 12 | files: { 13 | 'dest/output.min.js': ['src/input1.js', 'src/input2.js'] 14 | } 15 | } 16 | } 17 | }); 18 | ``` 19 | 20 | ## No mangling 21 | 22 | Specify `mangle: false` to prevent changes to your variable and function names. 23 | 24 | ```js 25 | // Project configuration. 26 | grunt.initConfig({ 27 | uglify: { 28 | options: { 29 | mangle: false 30 | }, 31 | my_target: { 32 | files: { 33 | 'dest/output.min.js': ['src/input.js'] 34 | } 35 | } 36 | } 37 | }); 38 | ``` 39 | 40 | ## Reserved identifiers 41 | 42 | You can specify identifiers to leave untouched with an `reserved` array in the `mangle` options. 43 | 44 | ```js 45 | // Project configuration. 46 | grunt.initConfig({ 47 | uglify: { 48 | options: { 49 | mangle: { 50 | reserved: ['jQuery', 'Backbone'] 51 | } 52 | }, 53 | my_target: { 54 | files: { 55 | 'dest/output.min.js': ['src/input.js'] 56 | } 57 | } 58 | } 59 | }); 60 | ``` 61 | 62 | ## Source maps 63 | 64 | Generate a source map by setting the `sourceMap` option to `true`. The generated 65 | source map will be in the same directory as the destination file. Its name will be 66 | the basename of the destination file with a `.map` extension. Override these 67 | defaults with the `sourceMapName` attribute. 68 | 69 | ```js 70 | // Project configuration. 71 | grunt.initConfig({ 72 | uglify: { 73 | my_target: { 74 | options: { 75 | sourceMap: true, 76 | sourceMapName: 'path/to/sourcemap.map' 77 | }, 78 | files: { 79 | 'dest/output.min.js': ['src/input.js'] 80 | } 81 | } 82 | } 83 | }); 84 | ``` 85 | 86 | ## Advanced source maps 87 | 88 | Set the `sourceMap.includeSources` option to `true` to embed your sources directly into the map. To include 89 | a source map from a previous compilation pass it as the value of the `sourceMapIn` option. 90 | 91 | ```js 92 | // Project configuration. 93 | grunt.initConfig({ 94 | uglify: { 95 | my_target: { 96 | options: { 97 | sourceMap: { 98 | includeSources: true 99 | }, 100 | sourceMapIn: 'example/coffeescript-sourcemap.js', // input sourcemap from a previous compilation 101 | }, 102 | files: { 103 | 'dest/output.min.js': ['src/input.js'], 104 | }, 105 | }, 106 | }, 107 | }); 108 | ``` 109 | 110 | Refer to the [UglifyJS SourceMap Documentation](https://github.com/mishoo/UglifyJS2#source-map-options) for more information. 111 | 112 | ## Turn off console warnings 113 | 114 | Specify `drop_console: true` as part of the `compress` options to discard calls to `console.*` functions. 115 | This will suppress warning messages in the console. 116 | 117 | ```js 118 | // Project configuration. 119 | grunt.initConfig({ 120 | uglify: { 121 | options: { 122 | compress: { 123 | drop_console: true 124 | } 125 | }, 126 | my_target: { 127 | files: { 128 | 'dest/output.min.js': ['src/input.js'] 129 | } 130 | } 131 | } 132 | }); 133 | ``` 134 | 135 | ## Beautify 136 | 137 | Specify `beautify: true` to beautify your code for debugging/troubleshooting purposes. 138 | Pass an object to manually configure any other output options. 139 | 140 | See [UglifyJS documentation](https://github.com/mishoo/UglifyJS2#output-options) for more information. 141 | 142 | ```js 143 | // Project configuration. 144 | grunt.initConfig({ 145 | uglify: { 146 | my_target: { 147 | options: { 148 | beautify: true 149 | }, 150 | files: { 151 | 'dest/output.min.js': ['src/input.js'] 152 | } 153 | }, 154 | my_advanced_target: { 155 | options: { 156 | beautify: { 157 | width: 80 158 | } 159 | }, 160 | files: { 161 | 'dest/output.min.js': ['src/input.js'] 162 | } 163 | } 164 | } 165 | }); 166 | ``` 167 | 168 | ## Banner comments 169 | 170 | In this example, running `grunt uglify:my_target` will prepend a banner created by interpolating the `banner` template string with the config object. Here, those properties are the values imported from the `package.json` file (which are available via the `pkg` config property) plus today's date. 171 | 172 | _Note: you don't have to use an external JSON file. It's also valid to create the `pkg` object inline in the config. That being said, if you already have a JSON file, you might as well reference it._ 173 | 174 | ```js 175 | // Project configuration. 176 | grunt.initConfig({ 177 | pkg: grunt.file.readJSON('package.json'), 178 | uglify: { 179 | options: { 180 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + 181 | '<%= grunt.template.today("yyyy-mm-dd") %> */' 182 | }, 183 | my_target: { 184 | files: { 185 | 'dest/output.min.js': ['src/input.js'] 186 | } 187 | } 188 | } 189 | }); 190 | ``` 191 | 192 | ## Conditional compilation 193 | 194 | You can also enable UglifyJS conditional compilation. This is commonly used to remove debug code blocks for production builds. This is equivalent to the command line `--define` option. 195 | 196 | See [UglifyJS global definitions documentation](https://github.com/mishoo/UglifyJS2#conditional-compilation) for more information. 197 | 198 | ```js 199 | // Project configuration. 200 | grunt.initConfig({ 201 | uglify: { 202 | options: { 203 | compress: { 204 | global_defs: { 205 | 'DEBUG': false 206 | }, 207 | dead_code: true 208 | } 209 | }, 210 | my_target: { 211 | files: { 212 | 'dest/output.min.js': ['src/input.js'] 213 | } 214 | } 215 | } 216 | }); 217 | ``` 218 | 219 | ## Compiling all files in a folder dynamically 220 | 221 | This configuration will compress and mangle the files dynamically. 222 | 223 | ```js 224 | // Project configuration. 225 | grunt.initConfig({ 226 | uglify: { 227 | my_target: { 228 | files: [{ 229 | expand: true, 230 | cwd: 'src/js', 231 | src: '**/*.js', 232 | dest: 'dest/js' 233 | }] 234 | } 235 | } 236 | }); 237 | ``` 238 | 239 | ## Compiling all files separately in the each their path 240 | 241 | This configuration will compress and mangle all js files separately in each folder. 242 | 243 | Also exclude jQuery for mangling and ignore all `*.min.js` files. 244 | 245 | ```js 246 | // Project configuration. 247 | uglify: { 248 | dev: { 249 | options: { 250 | mangle: { 251 | reserved: ['jQuery'] 252 | } 253 | }, 254 | files: [{ 255 | expand: true, 256 | src: ['dist/assets/js/*.js', '!dist/assets/js/*.min.js'], 257 | dest: 'dist/assets', 258 | cwd: '.', 259 | rename: function (dst, src) { 260 | // To keep the source js files and make new files as `*.min.js`: 261 | // return dst + '/' + src.replace('.js', '.min.js'); 262 | // Or to override to src: 263 | return src; 264 | } 265 | }] 266 | } 267 | }, 268 | ``` 269 | 270 | ## Turn on object property name mangling 271 | 272 | This configuration will turn on object property name mangling, but not mangle built-in browser object properties. 273 | Additionally, variables and object properties listed in the `myExceptionsFile.json` will be mangled. For more info, 274 | on the format of the exception file format please see the [UglifyJS docs](https://www.npmjs.com/package/uglify-js). 275 | 276 | ```js 277 | // Project configuration. 278 | grunt.initConfig({ 279 | uglify: { 280 | options: { 281 | mangle: { 282 | properties: true 283 | }, 284 | reserveDOMProperties: true, 285 | exceptionsFiles: [ 'myExceptionsFile.json' ] 286 | }, 287 | my_target: { 288 | files: { 289 | 'dest/output.min.js': ['src/input.js'] 290 | } 291 | } 292 | } 293 | }); 294 | ``` 295 | 296 | ## Turn on use of name mangling cache 297 | 298 | Turn on use of name mangling cache to coordinate mangled symbols between outputted uglify files. uglify will the 299 | generate a JSON cache file with the name provided in the options. Note: this generated file uses the same JSON format 300 | as the `exceptionsFiles` files. 301 | 302 | ```js 303 | // Project configuration. 304 | grunt.initConfig({ 305 | uglify: { 306 | options: { 307 | nameCache: '.tmp/grunt-uglify-cache.json', 308 | }, 309 | my_target: { 310 | files: { 311 | 'dest/output1.min.js': ['src/input1.js'], 312 | 'dest/output2.min.js': ['src/input2.js'] 313 | } 314 | } 315 | } 316 | }); 317 | ``` 318 | -------------------------------------------------------------------------------- /docs/uglify-options.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | This task primarily delegates to [UglifyJS](https://github.com/mishoo/UglifyJS2), so please consider their documentation as required reading for advanced configuration. 4 | 5 | 6 | #### Deprecated options from `2.x` 7 | 8 | Option | Replacement 9 | ----------------------- | ----------- 10 | ASCIIOnly | output.ascii_only 11 | enclose | — 12 | exportAll | — 13 | expression | parse.expression 14 | indentLevel | output.indent_level 15 | mangleProperties | mangle.properties 16 | maxLineLen | output.max\_line_len 17 | preserveComments | output.comments 18 | quoteStyle | output.quote_style 19 | screwIE8 | !ie8 20 | sourceMapIncludeSources | sourceMap.includeSources 21 | sourceMapRoot | sourceMap.root 22 | sourceMapUrl | sourceMap.url 23 | 24 | 25 | ## mangle 26 | Type: `Boolean` `Object` 27 | Default: `{}` 28 | 29 | Turn on or off mangling with default options. If an `Object` is specified, it is passed directly to `ast.mangle_names()` *and* `ast.compute_char_frequency()` (mimicking command line behavior). [View all options here](https://github.com/mishoo/UglifyJS2#mangle-options). 30 | 31 | ## compress 32 | Type: `Boolean` `Object` 33 | Default: `{}` 34 | 35 | Turn on or off source compression with default options. If an `Object` is specified, it is passed as options to `UglifyJS.Compressor()`. [View all options here](https://github.com/mishoo/UglifyJS2#compress-options). 36 | 37 | ## beautify 38 | Type: `Boolean` `Object` 39 | Default: `false` 40 | 41 | Turns on beautification of the generated source code. [View all options here](https://github.com/mishoo/UglifyJS2#output-options) 42 | 43 | #### parse.expression 44 | Type: `Boolean` 45 | Default: `false` 46 | 47 | Parse a single expression, rather than a program (for parsing JSON) 48 | 49 | ## report 50 | Type: `string` 51 | Choices: `'min'`, `'gzip'` 52 | Default: `'min'` 53 | 54 | Report minification result or both minification and gzip results. 55 | This is useful to see exactly how well uglify-js is performing but using `'gzip'` will make the task take 5-10x longer to complete. [Example output](https://github.com/sindresorhus/maxmin#readme). 56 | 57 | ## sourceMap 58 | Type: `Boolean` 59 | Default: `false` 60 | 61 | If `true`, a source map file will be generated in the same directory as the `dest` file. By default it will have the same basename as the `dest` file, but with a `.map` extension. 62 | 63 | ## sourceMapName 64 | Type: `String` `Function` 65 | Default: `undefined` 66 | 67 | To customize the name or location of the generated source map, pass a string to indicate where to write the source map to. If a function is provided, the uglify destination is passed as the argument and the return value will be used as the file name. 68 | 69 | ## sourceMapIn 70 | Type: `String` `Function` 71 | Default: `undefined` 72 | 73 | The location of an input source map from an earlier compilation, e.g. from CoffeeScript. If a function is provided, the 74 | uglify source is passed as the argument and the return value will be used as the sourceMap name. This only makes sense 75 | when there's one source file. 76 | 77 | ## sourceMap.includeSources 78 | Type: `Boolean` 79 | Default: `false` 80 | 81 | Pass this flag if you want to include the content of source files in the source map as sourcesContent property. 82 | 83 | #### sourceMap.root 84 | Type: `String` 85 | Default: `undefined` 86 | 87 | With this option you can customize root URL that browser will use when looking for sources. 88 | 89 | If the sources are not absolute URLs after prepending of the `sourceMap.root`, the sources are resolved relative to the source map. 90 | 91 | ## sourceMap.url 92 | Type: `String` 93 | Default: `undefined` 94 | 95 | Override the calculated value for `sourceMappingURL` in the source map. This is useful if the source map location is not relative to the base path of the minified file, i.e. when using a CDN 96 | 97 | ## wrap 98 | Type: `String` 99 | Default: `undefined` 100 | 101 | Wrap all of the code in a closure, an easy way to make sure nothing is leaking. 102 | For variables that need to be public `exports` and `global` variables are made available. 103 | The value of wrap is the global variable exports will be available as. 104 | 105 | ## output.ascii_only 106 | Type: `Boolean` 107 | Default: `false` 108 | 109 | Enables to encode non-ASCII characters as \uXXXX. 110 | 111 | ## output.comments 112 | Type: `Boolean` `String` `Function` 113 | Default: `undefined` 114 | Options: `false` `'all'` `'some'` 115 | 116 | Turn on preservation of comments. 117 | 118 | - `false` will strip all comments 119 | - `'all'` will preserve all comments in code blocks that have not been squashed or dropped 120 | - `'some'` will preserve all comments that include a closure compiler style directive (`@preserve` `@license` `@cc_on`) 121 | - `Function` specify your own comment preservation function. You will be passed the current node and the current comment and are expected to return either `true` or `false` 122 | - `RegExp` `'/[RegExp]/'` will preserve comments matching given RegExp or stringified RegExp 123 | 124 | ## banner 125 | Type: `String` 126 | Default: `''` 127 | 128 | This string will be prepended to the minified output. Template strings (e.g. `<%= config.value %>`) will be expanded automatically. 129 | 130 | ## footer 131 | Type: `String` 132 | Default: `''` 133 | 134 | This string will be appended to the minified output. Template strings (e.g. `<%= config.value %>`) will be expanded automatically. 135 | 136 | ## ie8 137 | Type: `Boolean` 138 | Default: `false` 139 | 140 | Set this to `true` if you still care about full compliance with Internet Explorer 6-8 quirks. 141 | 142 | ## mangle.properties 143 | Type: `Boolean` `Object` 144 | Default: `false` 145 | 146 | Turn on or off property mangling with default options. If an `Object` is specified, it is passed directly to `ast.mangle_properties()` (mimicking command line behavior). [View all options here](https://github.com/mishoo/UglifyJS2#mangle-options). 147 | 148 | ## reserveDOMProperties 149 | Type: `Boolean` 150 | Default: `false` 151 | 152 | Use this flag in conjunction with `mangle.properties` to prevent built-in browser object properties from being mangled. 153 | 154 | ## exceptionsFiles 155 | Type: `Array` 156 | Default: `[]` 157 | 158 | Use this with `mangle.properties` to pass one or more JSON files containing a list of variables and object properties 159 | that should not be mangled. See the [UglifyJS docs](https://www.npmjs.com/package/uglify-js) for more info on the file syntax. 160 | 161 | ## nameCache 162 | Type: `String` 163 | Default: `''` 164 | 165 | A string that is a path to a JSON cache file that uglify will create and use to coordinate symbol mangling between 166 | multiple runs of uglify. Note: this generated file uses the same JSON format as the `exceptionsFiles` files. 167 | 168 | ## output.quote_style 169 | Type: `Integer` 170 | Default: `0` 171 | 172 | Preserve or enforce quotation mark style. 173 | 174 | * `0` will use single or double quotes such as to minimize the number of bytes (prefers double quotes when both will do) 175 | * `1` will always use single quotes 176 | * `2` will always use double quotes 177 | * `3` will preserve original quotation marks 178 | -------------------------------------------------------------------------------- /docs/uglify-overview.md: -------------------------------------------------------------------------------- 1 | Task targets, files and options may be specified according to the grunt [Configuring tasks](https://gruntjs.com/configuring-tasks) guide. 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-contrib-uglify", 3 | "description": "Minify JavaScript files with UglifyJS", 4 | "version": "5.2.2", 5 | "author": { 6 | "name": "Grunt Team", 7 | "url": "https://gruntjs.com/" 8 | }, 9 | "repository": "gruntjs/grunt-contrib-uglify", 10 | "license": "MIT", 11 | "engines": { 12 | "node": ">=12" 13 | }, 14 | "main": "tasks/uglify.js", 15 | "scripts": { 16 | "test": "grunt test" 17 | }, 18 | "dependencies": { 19 | "chalk": "^4.1.2", 20 | "maxmin": "^3.0.0", 21 | "uglify-js": "^3.16.1", 22 | "uri-path": "^1.0.0" 23 | }, 24 | "devDependencies": { 25 | "grunt": "^1.5.2", 26 | "grunt-contrib-clean": "^2.0.0", 27 | "grunt-contrib-internal": "^7.0.0", 28 | "grunt-contrib-jshint": "^3.2.0", 29 | "grunt-contrib-nodeunit": "^4.0.0" 30 | }, 31 | "keywords": [ 32 | "gruntplugin" 33 | ], 34 | "files": [ 35 | "tasks" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /tasks/lib/uglify.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-contrib-uglify 3 | * https://gruntjs.com/ 4 | * 5 | * Copyright (c) 2017 "Cowboy" Ben Alman, contributors 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | // External libs. 12 | var path = require('path'); 13 | var UglifyJS = require('uglify-js'); 14 | var uriPath = require('uri-path'); 15 | var domprops = require('uglify-js/tools/domprops'); 16 | 17 | // Converts \r\n to \n 18 | function normalizeLf(string) { 19 | return string.replace(/\r\n/g, '\n'); 20 | } 21 | 22 | function toCache(cache, key) { 23 | if (cache[key]) { 24 | cache[key].props = UglifyJS.Dictionary.fromObject(cache[key].props); 25 | } else { 26 | cache[key] = { 27 | cname: -1, 28 | props: new UglifyJS.Dictionary() 29 | }; 30 | } 31 | return cache[key]; 32 | } 33 | 34 | exports.init = function(grunt) { 35 | var exports = {}; 36 | 37 | // Minify with UglifyJS. 38 | // From https://github.com/mishoo/UglifyJS2 39 | exports.minify = function(files, dest, options) { 40 | options = options || {}; 41 | 42 | grunt.verbose.write('Minifying with UglifyJS...'); 43 | 44 | var totalCode = ''; 45 | var minifyOptions = { 46 | compress: options.compress, 47 | ie8: options.ie8, 48 | keep_fnames: options.keep_fnames, 49 | mangle: options.mangle, 50 | output: options.output || {}, 51 | parse: options.parse || {}, 52 | sourceMap: options.sourceMap, 53 | toplevel: options.toplevel, 54 | wrap: options.wrap, 55 | webkit: options.webkit 56 | }; 57 | 58 | if (options.banner) { 59 | minifyOptions.output.preamble = normalizeLf(options.banner); 60 | } 61 | 62 | if (options.beautify) { 63 | minifyOptions.output.beautify = true; 64 | for (var key in options.beautify) { 65 | minifyOptions.output[key] = options.beautify[key]; 66 | } 67 | } 68 | 69 | var cache; 70 | if (options.nameCache) { 71 | try { 72 | cache = JSON.parse(grunt.file.read(options.nameCache)); 73 | } catch (ex) { 74 | cache = {}; 75 | } 76 | } 77 | 78 | if (minifyOptions.mangle) { 79 | if (typeof minifyOptions.mangle !== 'object') { 80 | minifyOptions.mangle = {}; 81 | } 82 | if (cache) { 83 | minifyOptions.mangle.cache = toCache(cache, 'vars'); 84 | } 85 | if (!Array.isArray(minifyOptions.mangle.reserved)) { 86 | minifyOptions.mangle.reserved = []; 87 | } 88 | if (minifyOptions.mangle.properties) { 89 | if (typeof minifyOptions.mangle.properties !== 'object') { 90 | minifyOptions.mangle.properties = {}; 91 | } 92 | if (cache) { 93 | minifyOptions.mangle.properties.cache = toCache(cache, 'props'); 94 | } 95 | if (!Array.isArray(minifyOptions.mangle.properties.reserved)) { 96 | minifyOptions.mangle.properties.reserved = []; 97 | } 98 | if (options.reserveDOMProperties) { 99 | domprops.forEach(function(name) { 100 | UglifyJS.push_uniq(minifyOptions.mangle.properties.reserved, name); 101 | }); 102 | } 103 | } 104 | if (options.exceptionsFiles) { 105 | options.exceptionsFiles.forEach(function(file) { 106 | try { 107 | var obj = JSON.parse(grunt.file.read(file)); 108 | if (minifyOptions.mangle && obj.vars) { 109 | obj.vars.forEach(function(name) { 110 | UglifyJS.push_uniq(minifyOptions.mangle.reserved, name); 111 | }); 112 | } 113 | if (minifyOptions.mangle.properties && obj.props) { 114 | obj.props.forEach(function(name) { 115 | UglifyJS.push_uniq(minifyOptions.mangle.properties.reserved, name); 116 | }); 117 | } 118 | } catch (ex) { 119 | grunt.warn(ex); 120 | } 121 | }); 122 | } 123 | } 124 | 125 | var result = UglifyJS.minify(files.reduce(function(o, file) { 126 | var code = grunt.file.read(file); 127 | totalCode += code; 128 | 129 | // The src file name must be relative to the source map for things to work 130 | var basename = path.basename(file); 131 | var fileDir = path.dirname(file); 132 | var sourceMapDir = path.dirname(options.generatedSourceMapName); 133 | var relativePath = path.relative(sourceMapDir, fileDir); 134 | var pathPrefix = relativePath ? relativePath + path.sep : ''; 135 | 136 | // Convert paths to use forward slashes for sourcemap use in the browser 137 | o[uriPath(pathPrefix + basename)] = code; 138 | return o; 139 | }, {}), minifyOptions); 140 | if (result.error) { 141 | throw result.error; 142 | } 143 | 144 | if (options.nameCache) { 145 | grunt.file.write(options.nameCache, JSON.stringify(cache, function(key, value) { 146 | return value instanceof UglifyJS.Dictionary ? value.toObject() : value; 147 | })); 148 | } 149 | 150 | grunt.verbose.ok(); 151 | 152 | return { 153 | max: totalCode, 154 | min: result.code, 155 | sourceMap: result.map 156 | }; 157 | }; 158 | 159 | return exports; 160 | }; 161 | -------------------------------------------------------------------------------- /tasks/uglify.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-contrib-uglify 3 | * https://gruntjs.com/ 4 | * 5 | * Copyright (c) 2016 "Cowboy" Ben Alman, contributors 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var path = require('path'); 12 | var chalk = require('chalk'); 13 | var maxmin = require('maxmin'); 14 | var uriPath = require('uri-path'); 15 | var err; 16 | 17 | // Return the relative path from file1 => file2 18 | function relativePath(file1, file2) { 19 | var file1Dirname = path.dirname(file1); 20 | var file2Dirname = path.dirname(file2); 21 | 22 | if (file1Dirname !== file2Dirname) { 23 | return path.relative(file1Dirname, file2Dirname); 24 | } 25 | return ''; 26 | } 27 | 28 | // Converts \r\n to \n 29 | function normalizeLf(string) { 30 | return string.replace(/\r\n/g, '\n'); 31 | } 32 | 33 | module.exports = function(grunt) { 34 | // Internal lib. 35 | var uglify = require('./lib/uglify').init(grunt); 36 | 37 | var getAvailableFiles = function (filesArray) { 38 | return filesArray.filter(function (filepath) { 39 | if (!grunt.file.exists(filepath)) { 40 | grunt.log.warn('Source file ' + chalk.cyan(filepath) + ' not found'); 41 | return false; 42 | } 43 | return true; 44 | }); 45 | }; 46 | 47 | grunt.registerMultiTask('uglify', 'Minify files with UglifyJS.', function() { 48 | // Merge task-specific and/or target-specific options with these defaults. 49 | var options = this.options({ 50 | banner: '', 51 | footer: '', 52 | compress: {}, 53 | mangle: {}, 54 | beautify: false, 55 | report: 'min', 56 | ie8: false 57 | }); 58 | 59 | var footer = normalizeLf(options.footer); 60 | var mapNameGenerator, mapInNameGenerator; 61 | var created = { 62 | maps: 0, 63 | files: 0 64 | }; 65 | var size = { 66 | before: 0, 67 | after: 0 68 | }; 69 | var generateSourceMapURL = options.sourceMap && !options.sourceMap.url; 70 | var generateSourceMapFilename = options.sourceMap && !options.sourceMap.filename; 71 | 72 | // function to get the name of the sourceMap 73 | if (typeof options.sourceMapName === 'function') { 74 | mapNameGenerator = options.sourceMapName; 75 | } 76 | 77 | // Iterate over all src-dest file pairs. 78 | this.files.forEach(function (f) { 79 | var availableFiles = getAvailableFiles(f.src); 80 | 81 | if (availableFiles.length === 0) { 82 | grunt.log.warn('Destination ' + chalk.cyan(f.dest) + ' not written because src files were empty.'); 83 | return; 84 | } 85 | 86 | // function to get the name of the sourceMapIn file 87 | if (typeof options.sourceMapIn === 'function') { 88 | if (availableFiles.length !== 1) { 89 | grunt.fail.warn('Cannot generate `sourceMapIn` for multiple source files.'); 90 | } 91 | mapInNameGenerator = options.sourceMapIn; 92 | } 93 | 94 | // dynamically create destination sourcemap name 95 | if (mapNameGenerator) { 96 | try { 97 | options.generatedSourceMapName = mapNameGenerator(f.dest); 98 | } catch (e) { 99 | err = new Error('SourceMap failed.'); 100 | err.origError = e; 101 | grunt.fail.warn(err); 102 | } 103 | // If no name is passed append .map to the filename 104 | } else if (!options.sourceMapName) { 105 | options.generatedSourceMapName = f.dest + '.map'; 106 | } else { 107 | options.generatedSourceMapName = options.sourceMapName; 108 | } 109 | 110 | // Dynamically create incoming sourcemap names 111 | if (mapInNameGenerator) { 112 | try { 113 | options.sourceMapIn = mapInNameGenerator(availableFiles[0]); 114 | } catch (e) { 115 | err = new Error('SourceMapInName failed.'); 116 | err.origError = e; 117 | grunt.fail.warn(err); 118 | } 119 | } 120 | 121 | if (options.sourceMap) { 122 | if (typeof options.sourceMap !== 'object') { 123 | options.sourceMap = {}; 124 | } 125 | if (options.sourceMapIn) { 126 | options.sourceMap.content = grunt.file.read(options.sourceMapIn); 127 | } 128 | // Calculate the path from the dest file to the sourcemap for sourceMap.url 129 | if (generateSourceMapURL) { 130 | if (generateSourceMapFilename) { 131 | options.sourceMap.filename = path.basename(f.dest); 132 | } 133 | var destToSourceMapPath = relativePath(f.dest, options.generatedSourceMapName); 134 | var sourceMapBasename = path.basename(options.generatedSourceMapName); 135 | options.sourceMap.url = uriPath(path.join(destToSourceMapPath, sourceMapBasename)); 136 | } 137 | } 138 | 139 | // Minify files, warn and fail on error. 140 | var result; 141 | try { 142 | result = uglify.minify(availableFiles, f.dest, options); 143 | } catch (e) { 144 | console.log(e); 145 | err = new Error('Uglification failed.'); 146 | if (e.message) { 147 | err.message += '\n' + e.message + '. \n'; 148 | if (e.line) { 149 | err.message += 'Line ' + e.line + ' in ' + availableFiles + '\n'; 150 | } 151 | } 152 | err.origError = e; 153 | grunt.log.warn('Uglifying source ' + chalk.cyan(availableFiles) + ' failed.'); 154 | grunt.fail.warn(err); 155 | } 156 | 157 | // Concat minified source + footer 158 | var output = result.min + footer; 159 | 160 | var unCompiledJSString = availableFiles.map(function (file) { 161 | return grunt.file.read(file); 162 | }).join(''); 163 | 164 | // Write the destination file. 165 | grunt.file.write(f.dest, output); 166 | 167 | size.before += unCompiledJSString.length; 168 | 169 | // Write source map 170 | if (options.sourceMap) { 171 | grunt.file.write(options.generatedSourceMapName, result.sourceMap); 172 | grunt.verbose.writeln('File ' + chalk.cyan(options.generatedSourceMapName) + ' created (source map).'); 173 | created.maps++; 174 | } 175 | 176 | var outputSize = maxmin(result.max, output, options.report === 'gzip'); 177 | grunt.verbose.writeln('File ' + chalk.cyan(f.dest) + ' created: ' + chalk.dim(outputSize)); 178 | 179 | created.files++; 180 | size.after += output.length; 181 | }); 182 | 183 | if (created.maps > 0) { 184 | grunt.log.ok(created.maps + ' source' + grunt.util.pluralize(created.maps, 'map/maps') + ' created.'); 185 | } 186 | 187 | if (created.files > 0) { 188 | grunt.log.ok(created.files + ' ' + grunt.util.pluralize(this.files.length, 'file/files') + ' created ' + chalk.dim(maxmin(size.before, size.after))); 189 | } else { 190 | grunt.log.warn('No files created.'); 191 | } 192 | }); 193 | }; 194 | -------------------------------------------------------------------------------- /test/fixtures/expected/asciionly.js: -------------------------------------------------------------------------------- 1 | var set=["This is a random set of ch\u03b1racters and strings.","\u8fd9\u662f\u4e00\u7ec4\u968f\u673a\u5b57\u7b26\u548c\u5b57\u7b26\u4e32\u3002","\u042d\u0442\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0438 \u0441\u0442\u0440\u043e\u043a","\u0426\xe9 \u0432\u0438\u043f\u0430\u0434\u043a\u043e\u0432\u0438\u0439 \u043d\u0430\u0431\u0456\u0440 \u0441\u0438\u043c\u0432\u043e\u043b\u0456\u0432 \u0442\u0430 \u0440\u044f\u0434\u043a\u0456\u0432"],answer=set[Math.floor(Math.random()*set.length)]; -------------------------------------------------------------------------------- /test/fixtures/expected/beautify.js: -------------------------------------------------------------------------------- 1 | var longNameA = 1, longNameB = 2; 2 | 3 | function longFunctionC(n, o) { 4 | return longNameA + longNameB + n + o; 5 | } 6 | 7 | var result = longFunctionC(3, 4); -------------------------------------------------------------------------------- /test/fixtures/expected/comments.js: -------------------------------------------------------------------------------- 1 | function foo(){return 42}function bar(){return 2*foo()} 2 | /* @preserve 3 | * multiline preserve 4 | */ 5 | /* @license 6 | * multiline license 7 | */function baz(){return bar()*bar()} -------------------------------------------------------------------------------- /test/fixtures/expected/commentsWithImportant.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * I am a comment 3 | */ 4 | function foo(){return 42} 5 | // @preserve preserve 6 | // @license license 7 | function bar(){return 2*foo()} 8 | /* @preserve 9 | * multiline preserve 10 | */ 11 | /* @license 12 | * multiline license 13 | */function baz(){return bar()*bar()} -------------------------------------------------------------------------------- /test/fixtures/expected/compress.js: -------------------------------------------------------------------------------- 1 | var longNameA=1,longNameB=2;function longFunctionC(argumentC,argumentD){return longNameA+longNameB+argumentC+argumentD}var result=longFunctionC(3,4); -------------------------------------------------------------------------------- /test/fixtures/expected/compress_explicit.js: -------------------------------------------------------------------------------- 1 | var longNameA=1,longNameB=2;function longFunctionC(n,o){return longNameA+longNameB+n+o}var result=longFunctionC(3,4); -------------------------------------------------------------------------------- /test/fixtures/expected/compress_mangle.js: -------------------------------------------------------------------------------- 1 | var longNameA=1,longNameB=2;function longFunctionC(n,o){return longNameA+longNameB+n+o}var result=longFunctionC(3,4); -------------------------------------------------------------------------------- /test/fixtures/expected/compress_mangle_banner.js: -------------------------------------------------------------------------------- 1 | // banner without sourcemap 2 | var longNameA=1,longNameB=2;function longFunctionC(n,o){return longNameA+longNameB+n+o}var result=longFunctionC(3,4); -------------------------------------------------------------------------------- /test/fixtures/expected/compress_mangle_beautify.js: -------------------------------------------------------------------------------- 1 | var longNameA = 1, longNameB = 2; 2 | 3 | function longFunctionC(n, o) { 4 | return longNameA + longNameB + n + o; 5 | } 6 | 7 | var result = longFunctionC(3, 4); 8 | // This is a footer. -------------------------------------------------------------------------------- /test/fixtures/expected/compress_mangle_except.js: -------------------------------------------------------------------------------- 1 | var longNameA=1,longNameB=2;function longFunctionC(argumentC,n){return longNameA+longNameB+argumentC+n}var result=longFunctionC(3,4); -------------------------------------------------------------------------------- /test/fixtures/expected/deep/directory/location/source_map.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sourcemap_customDir.js","sources":["../../../../test/fixtures/src/simple.js"],"names":["longNameA","longNameB","longFunctionC","argumentC","argumentD","result"],"mappings":"AAGA,IAAIA,UAAY,EAEZC,UAAY,EAEhB,SAASC,cAAcC,EAAUC,GAC/B,OAAOJ,UAAYC,UAAYE,EAAYC,EAG7C,IAAIC,OAASH,cAAc,EAAE"} -------------------------------------------------------------------------------- /test/fixtures/expected/expression.js: -------------------------------------------------------------------------------- 1 | function(doc){emit(doc._id,doc)} -------------------------------------------------------------------------------- /test/fixtures/expected/expression.json: -------------------------------------------------------------------------------- 1 | {employees:[{firstName:"John",lastName:"Doe"}]} -------------------------------------------------------------------------------- /test/fixtures/expected/mangle.js: -------------------------------------------------------------------------------- 1 | function longFunctionC(n,o){return longNameA+longNameB+n+o}var longNameA=1,longNameB=2,result=longFunctionC(3,4); -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops.js: -------------------------------------------------------------------------------- 1 | var myObj={n:function(n){0},e:function(){},o:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){}; -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops_withExcept.js: -------------------------------------------------------------------------------- 1 | var myObj={n:function(dontMangleMeVariable){0},e:function(){},o:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){}; -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops_withExceptAndExceptionsFiles.js: -------------------------------------------------------------------------------- 1 | var n={n:function(dontMangleMeVariable){0},dontMangleMeProperty:function(){},o:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){}; -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops_withExceptionsFiles.js: -------------------------------------------------------------------------------- 1 | var n={n:function(n){0},dontMangleMeProperty:function(){},o:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){}; -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops_withNameCacheFile1.js: -------------------------------------------------------------------------------- 1 | var n={n:function(n){0},o:function(){},t:function(){}},o=function(){},t=function(){}; -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops_withNameCacheFile2.js: -------------------------------------------------------------------------------- 1 | var a=10;n.n(a); -------------------------------------------------------------------------------- /test/fixtures/expected/mangleprops_withRegex.js: -------------------------------------------------------------------------------- 1 | var anObject={a:"val","#key2":"val2"}; -------------------------------------------------------------------------------- /test/fixtures/expected/maxLineLen.js: -------------------------------------------------------------------------------- 1 | !function(){var square=function(x){return x*x},list=[1,2,3,4,5],math={root:Math.sqrt,square:square, 2 | cube:function(x){return x*square(x)}};"undefined"!=typeof elvis&&null!=elvis&&alert("I knew it!"), 3 | function(accum$){for(var i$=0,length$=list.length;i$ x * x\n\n# Arrays:\nlist = [1, 2, 3, 4, 5]\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n\n# Existence:\nalert \"I knew it!\" if elvis?\n\n# Array comprehensions:\ncubes = (math.cube num for num in list)"],"names":["square","x","list","math","root","Math","sqrt","cube","elvis","alert","accum$","i$","length$","length"],"mappings":"gBAQCA,EAAS,SAAAC,G,OAAOA,EAAIA,GAGpBC,EAAO,CAAC,EAAG,EAAG,EAAG,EAAG,GAGpBC,EACG,CAAAC,KAAQC,KAAIC,KACbN,OAAQA,EACRO,KAAQ,SAAAN,G,OAAOA,EAAID,EAAOC,KAO1B,oBAAsBO,OAAA,MAAAA,OAAtBC,MAAM,cAGR,SAAAC,GAAS,I,IAAAC,EAAA,EAAAC,EAAyBV,EAAAW,OAAzBF,EAAAC,IAAAD,E,OAAAR,EAAII,KAAqBL,EAAAS"} -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemapin_sources.js: -------------------------------------------------------------------------------- 1 | !function(){var t=function(n){return n*n},r=[1,2,3,4,5],u={root:Math.sqrt,square:t,cube:function(n){return n*t(n)}};"undefined"!=typeof elvis&&null!=elvis&&alert("I knew it!"),function(n){for(var t=0,e=r.length;t x * x\n\n# Arrays:\nlist = [1, 2, 3, 4, 5]\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n\n# Existence:\nalert \"I knew it!\" if elvis?\n\n# Array comprehensions:\ncubes = (math.cube num for num in list)"],"names":["square","x","list","math","root","Math","sqrt","cube","elvis","alert","accum$","i$","length$","length"],"mappings":"gBAQCA,EAAS,SAAAC,G,OAAOA,EAAIA,GAGpBC,EAAO,CAAC,EAAG,EAAG,EAAG,EAAG,GAGpBC,EACG,CAAAC,KAAQC,KAAIC,KACbN,OAAQA,EACRO,KAAQ,SAAAN,G,OAAOA,EAAID,EAAOC,KAO1B,oBAAsBO,OAAA,MAAAA,OAAtBC,MAAM,cAGR,SAAAC,GAAS,I,IAAAC,EAAA,EAAAC,EAAyBV,EAAAW,OAAzBF,EAAAC,IAAAD,E,OAAAR,EAAII,KAAqBL,EAAAS"} -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple1.js: -------------------------------------------------------------------------------- 1 | var longNameA=1,longNameB=2;function longFunctionC(n,o){return longNameA+longNameB+n+o}var result=longFunctionC(3,4); 2 | //# sourceMappingURL=sourcemaps_multiple1.js.map -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple1.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sourcemaps_multiple1.js","sources":["../test/fixtures/src/simple.js"],"names":["longNameA","longNameB","longFunctionC","argumentC","argumentD","result"],"mappings":"AAGA,IAAIA,UAAY,EAEZC,UAAY,EAEhB,SAASC,cAAcC,EAAUC,GAC/B,OAAOJ,UAAYC,UAAYE,EAAYC,EAG7C,IAAIC,OAASH,cAAc,EAAE"} -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple1_fnName.js: -------------------------------------------------------------------------------- 1 | var longNameA=1,longNameB=2;function longFunctionC(n,o){return longNameA+longNameB+n+o}var result=longFunctionC(3,4); 2 | //# sourceMappingURL=sourcemaps_multiple1_fnName.js.fn.map -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple1_fnName.js.fn.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sourcemaps_multiple1_fnName.js","sources":["../test/fixtures/src/simple.js"],"names":["longNameA","longNameB","longFunctionC","argumentC","argumentD","result"],"mappings":"AAGA,IAAIA,UAAY,EAEZC,UAAY,EAEhB,SAASC,cAAcC,EAAUC,GAC/B,OAAOJ,UAAYC,UAAYE,EAAYC,EAG7C,IAAIC,OAASH,cAAc,EAAE"} -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple2.js: -------------------------------------------------------------------------------- 1 | function foo(){return 42}function bar(){return 2*foo()}function baz(){return bar()*bar()} 2 | //# sourceMappingURL=sourcemaps_multiple2.js.map -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple2.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sourcemaps_multiple2.js","sources":["../test/fixtures/src/comments.js"],"names":["foo","bar","baz"],"mappings":"AAGA,SAASA,MACP,OAAO,GAIT,SAASC,MACP,OAAa,EAAND,MAQT,SAASE,MACP,OAAOD,MAAMA"} -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple2_fnName.js: -------------------------------------------------------------------------------- 1 | function foo(){return 42}function bar(){return 2*foo()}function baz(){return bar()*bar()} 2 | //# sourceMappingURL=sourcemaps_multiple2_fnName.js.fn.map -------------------------------------------------------------------------------- /test/fixtures/expected/sourcemaps_multiple2_fnName.js.fn.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sourcemaps_multiple2_fnName.js","sources":["../test/fixtures/src/comments.js"],"names":["foo","bar","baz"],"mappings":"AAGA,SAASA,MACP,OAAO,GAIT,SAASC,MACP,OAAa,EAAND,MAQT,SAASE,MACP,OAAOD,MAAMA"} -------------------------------------------------------------------------------- /test/fixtures/expected/uglify_name_cache.json: -------------------------------------------------------------------------------- 1 | {"vars":{"cname":-1,"props":{"$myObj":"n","$dontMangleMeVariable2":"o","$dontMangleMeVariable3":"t","$myNumber":"a"}},"props":{"cname":-1,"props":{"$myFunction":"n","$dontMangleMeProperty":"o","$dontMangleMeProperty2":"t"}}} -------------------------------------------------------------------------------- /test/fixtures/expected/wrap.js: -------------------------------------------------------------------------------- 1 | (function(exports){var longNameA=1;var longNameB=2;function longFunctionC(argumentC,argumentD){return longNameA+longNameB+argumentC+argumentD}var result=longFunctionC(3,4)})(typeof testExport=="undefined"?testExport={}:testExport); -------------------------------------------------------------------------------- /test/fixtures/src/comments.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * I am a comment 3 | */ 4 | function foo() { 5 | return 42; 6 | } 7 | // @preserve preserve 8 | // @license license 9 | function bar() { 10 | return foo()*2; 11 | } 12 | /* @preserve 13 | * multiline preserve 14 | */ 15 | /* @license 16 | * multiline license 17 | */ 18 | function baz() { 19 | return bar()*bar(); 20 | } 21 | // end - not preserved -------------------------------------------------------------------------------- /test/fixtures/src/exceptionsfile1.json: -------------------------------------------------------------------------------- 1 | { 2 | "vars": ["dontMangleMeVariable2"], 3 | "props": ["dontMangleMeProperty"] 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/src/exceptionsfile2.json: -------------------------------------------------------------------------------- 1 | { 2 | "vars": ["dontMangleMeVariable3"], 3 | "props": [] 4 | } 5 | 6 | -------------------------------------------------------------------------------- /test/fixtures/src/expression.js: -------------------------------------------------------------------------------- 1 | function(doc) { 2 | emit(doc._id,doc); 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/src/localization.js: -------------------------------------------------------------------------------- 1 | var set = [ 2 | "This is a random set of chαracters and strings.", 3 | "这是一组随机字符和字符串。", 4 | "Это случайный набор символов и строк", 5 | "Цé випадковий набір символів та рядків" 6 | ], answer = set[Math.floor(Math.random()*set.length)]; -------------------------------------------------------------------------------- /test/fixtures/src/mangleprops.js: -------------------------------------------------------------------------------- 1 | var myObj = { 2 | myFunction: function(dontMangleMeVariable) { dontMangleMeVariable++; }, 3 | dontMangleMeProperty: function() {}, 4 | dontMangleMeProperty2: function() {} 5 | }; 6 | 7 | var dontMangleMeVariable2 = function() {}; 8 | var dontMangleMeVariable3 = function() {}; 9 | -------------------------------------------------------------------------------- /test/fixtures/src/mangleprops_withNameCache.js: -------------------------------------------------------------------------------- 1 | var myNumber = 10; 2 | myObj.myFunction(myNumber); 3 | -------------------------------------------------------------------------------- /test/fixtures/src/mangleprops_withRegex.js: -------------------------------------------------------------------------------- 1 | var anObject = { 2 | key1: 'val', 3 | '#key2': 'val2' 4 | }; 5 | -------------------------------------------------------------------------------- /test/fixtures/src/quotes.js: -------------------------------------------------------------------------------- 1 | function llama() { 2 | var a = 'This is a single quote string'; 3 | var b = "This is a double quote string"; 4 | var c = { 5 | "this": "is part of an Object", 6 | 'and': 'so is this', 7 | 'but': 'this one has "mixed" quotes: \'' 8 | }; 9 | 10 | return [a, b, c]; 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/src/screwIE8.js: -------------------------------------------------------------------------------- 1 | 2 | // screw-ie8 false will not remove quotes 3 | var reserved_words = { 4 | 'class': true 5 | }; 6 | -------------------------------------------------------------------------------- /test/fixtures/src/simple.js: -------------------------------------------------------------------------------- 1 | 2 | // Hello world, I'm a comment! 3 | 4 | var longNameA = 1; 5 | 6 | var longNameB = 2; 7 | 8 | function longFunctionC(argumentC,argumentD) { 9 | return longNameA + longNameB + argumentC + argumentD; 10 | } 11 | 12 | var result = longFunctionC(3,4); 13 | 14 | /*! I might be preserved, yay! */ 15 | 16 | -------------------------------------------------------------------------------- /test/fixtures/src/simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "employees": [ 3 | { 4 | "firstName": "John", 5 | "lastName": "Doe" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/src/simple2.coffee: -------------------------------------------------------------------------------- 1 | # Assignment: 2 | number = 42 3 | opposite = true 4 | 5 | # Conditions: 6 | number = -42 if opposite 7 | 8 | # Functions: 9 | square = (x) -> x * x 10 | 11 | # Arrays: 12 | list = [1, 2, 3, 4, 5] 13 | 14 | # Objects: 15 | math = 16 | root: Math.sqrt 17 | square: square 18 | cube: (x) -> x * square x 19 | 20 | # Splats: 21 | race = (winner, runners...) -> 22 | print winner, runners 23 | 24 | # Existence: 25 | alert "I knew it!" if elvis? 26 | 27 | # Array comprehensions: 28 | cubes = (math.cube num for num in list) -------------------------------------------------------------------------------- /test/fixtures/src/simple2.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 2.0.0-dev 2 | void function () { 3 | var cubes, list, math, number, opposite, race, square; 4 | number = 42; 5 | opposite = true; 6 | if (opposite) 7 | number = -42; 8 | square = function (x) { 9 | return x * x; 10 | }; 11 | list = [ 12 | 1, 13 | 2, 14 | 3, 15 | 4, 16 | 5 17 | ]; 18 | math = { 19 | root: Math.sqrt, 20 | square: square, 21 | cube: function (x) { 22 | return x * square(x); 23 | } 24 | }; 25 | race = function (winner, runners) { 26 | runners = 2 <= arguments.length ? [].slice.call(arguments, 1) : []; 27 | return print(winner, runners); 28 | }; 29 | if ('undefined' !== typeof elvis && null != elvis) 30 | alert('I knew it!'); 31 | cubes = function (accum$) { 32 | var num; 33 | for (var i$ = 0, length$ = list.length; i$ < length$; ++i$) { 34 | num = list[i$]; 35 | accum$.push(math.cube(num)); 36 | } 37 | return accum$; 38 | }.call(this, []); 39 | }.call(this); 40 | -------------------------------------------------------------------------------- /test/fixtures/src/simple2.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"test/fixtures/src/simple2.coffee","sources":["../test/fixtures/src/simple2.coffee"],"names":[],"mappings":"AAAC;;;EACA,MAAA,GAAW;EACX,QAAA,GAAW;EAGX,IAAgB,QAAhB,CAAA;AAAA,IAAA,MAAA,GAAS,CAAC;EAGV,MAAA,GAAS,SAAA,CAAA,CAAA,CAAA;WAAO,CAAA,CAAA,CAAA,CAAI;;EAGpB,IAAA,GAAO,CAAA;AAAA,IAAC,CAAD;AAAA,IAAI,CAAJ;AAAA,IAAO,CAAP;AAAA,IAAU,CAAV;AAAA,IAAa,CAAb;AAAA,EAAA;EAGP,IAAA,GACG,CAAA;AAAA,IAAA,IAAA,EAAQ,IAAI,KAAZ;AAAA,IACD,MAAA,EAAQ,MADP;AAAA,IAED,IAAA,EAAQ,SAAA,CAAA,CAAA,CAAA;aAAO,CAAA,CAAA,CAAA,CAAI,MAAA,CAAO,CAAP;KAFlB;AAAA,EAAA;EAKD,IAAA,GAAO,SAAA,CAAA,MAAA,EAAA,OAAA,CAAA;IAAS;WACf,KAAA,CAAM,MAAN,EAAc,OAAd;;EAGD,2BAAsB,KAAA,CAAA,EAAA,SAAA,KAAtB,CAAA;AAAA,IAAA,KAAA,CAAM,YAAN;EAGF,KAAA;;IAAS,2BAAyB,YAAzB,aAAA,CAAA,KAAA,CAAA;MAAkB,MAAO;kBAAzB,IAAI,KAAJ,CAAU,GAAV","sourcesContent":["# Assignment:\nnumber = 42\nopposite = true\n\n# Conditions:\nnumber = -42 if opposite\n\n# Functions:\nsquare = (x) -> x * x\n\n# Arrays:\nlist = [1, 2, 3, 4, 5]\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n\n# Existence:\nalert \"I knew it!\" if elvis?\n\n# Array comprehensions:\ncubes = (math.cube num for num in list)"]} -------------------------------------------------------------------------------- /test/uglify_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var grunt = require('grunt'); 4 | var path = require('path'); 5 | 6 | var read = function() { 7 | var filepath = path.join.apply(this, Array.prototype.slice.call(arguments)); 8 | return grunt.util.normalizelf(grunt.file.read(filepath)); 9 | }; 10 | 11 | exports.contrib_uglify = { 12 | preuglified_files: function(test) { 13 | 14 | var files = [ 15 | 'beautify.js', 16 | 'comments.js', 17 | 'commentsWithImportant.js', 18 | 'compress.js', 19 | 'compress_explicit.js', 20 | 'compress_mangle.js', 21 | 'compress_mangle_banner.js', 22 | 'compress_mangle_beautify.js', 23 | 'compress_mangle_except.js', 24 | 'multifile.js', 25 | 'wrap.js', 26 | 'maxLineLen.js', 27 | 'asciionly.js', 28 | 'screwIE8.js', 29 | 'sourcemap_basic.js', 30 | 'sourcemap_basic.js.map', 31 | 'sourcemap_customDir.js', 32 | 'sourcemap_customName.js', 33 | 'source_map_custom_name', 34 | 'sourcemap_customRoot.js', 35 | 'sourcemap_customRoot.js.map', 36 | 'sourcemap_customUrl.js', 37 | 'sourcemap_customUrl.js.map', 38 | 'sourcemap_functionName.js', 39 | 'sourcemap_functionName.js.fn.map', 40 | path.join('deep', 'directory', 'location', 'source_map.js.map'), 41 | 'sourcemapin.js', 42 | 'sourcemapin.js.map', 43 | 'sourcemap_sources.js.map', 44 | 'sourcemapin_customUrl.js', 45 | 'sourcemapin_customUrl.js.map', 46 | 'sourcemapin_sources.js', 47 | 'sourcemapin_sources.js.map', 48 | 'sourcemaps_multiple1.js', 49 | 'sourcemaps_multiple1.js.map', 50 | 'sourcemaps_multiple2.js', 51 | 'sourcemaps_multiple2.js.map', 52 | 'sourcemaps_multiple1_fnName.js', 53 | 'sourcemaps_multiple1_fnName.js.fn.map', 54 | 'sourcemaps_multiple2_fnName.js', 55 | 'sourcemaps_multiple2_fnName.js.fn.map', 56 | 'expression.json', 57 | 'expression.js', 58 | 'mangleprops.js', 59 | 'mangleprops_withExcept.js', 60 | 'mangleprops_withExceptionsFiles.js', 61 | 'mangleprops_withExceptAndExceptionsFiles.js', 62 | 'mangleprops_withNameCacheFile1.js', 63 | 'mangleprops_withNameCacheFile2.js', 64 | 'mangleprops_withRegex.js', 65 | 'uglify_name_cache.json', 66 | 'quotes_single.js', 67 | 'quotes_double.js', 68 | 'quotes_original.js' 69 | ]; 70 | 71 | test.expect(files.length); 72 | 73 | files.forEach(function(file) { 74 | var actual = read('tmp', file); 75 | var expected = read('test', 'fixtures', 'expected', file); 76 | test.equal(actual, expected, 'task output should equal ' + file); 77 | }); 78 | 79 | test.done(); 80 | } 81 | }; 82 | --------------------------------------------------------------------------------