├── .editorconfig ├── .eslintrc.yml ├── .gitattributes ├── .github └── workflows │ └── CI-CD.yaml ├── .gitignore ├── .mocharc.yml ├── .nycrc.yml ├── .vscode ├── launch.json └── tasks.json ├── 404.md ├── CHANGELOG.md ├── LICENSE ├── README.md ├── _config.yml ├── bin └── simplifyify.js ├── dist ├── index.js ├── package.json └── simplifyify.js ├── lib ├── expand-globs.js ├── file-set.js ├── fs-cache.js ├── index.js ├── transforms │ ├── banner.js │ ├── index.js │ ├── istanbul.js │ ├── tsify.js │ └── uglifyify.js ├── util.js └── write-bundles.js ├── package-lock.json ├── package.json └── test ├── fixtures ├── assert.js ├── cli.js └── mocha.js ├── specs ├── bundle.spec.js ├── cli.spec.js ├── debug.spec.js ├── exclude.spec.js ├── minify.spec.js ├── outfile.spec.js ├── standalone.spec.js ├── test.spec.js ├── transform.spec.js ├── typescript.spec.js └── watch.spec.js └── test-apps ├── error └── error.js ├── es5 ├── hello-world.js ├── index.js ├── lib │ ├── hello-world.js │ ├── index.js │ └── say │ │ └── index.js ├── package.json └── say │ └── index.js ├── es6-with-options ├── hello-world.js ├── index.js ├── package.json ├── say │ └── index.js └── src │ ├── hello-world.js │ ├── index.js │ └── say │ └── index.js ├── es6 ├── .babelrc ├── hello-world.js ├── index.js ├── package.json ├── say │ └── index.js └── src │ ├── hello-world.js │ ├── index.js │ └── say │ └── index.js ├── hello ├── banner.txt ├── hello-world.js ├── index.js ├── package.json └── say │ └── index.js ├── transform-options ├── hello-world.js ├── index.js ├── package.json ├── say │ └── index.js └── src │ ├── hello-world.js │ ├── index.js │ └── say │ └── index.js ├── typescript-error ├── error.ts └── tsconfig.json ├── typescript-options ├── hello-world.tsx ├── index.ts ├── package.json ├── say │ └── index.ts └── src │ ├── hello-world.tsx │ ├── index.js │ ├── index.ts │ └── say │ └── index.ts ├── typescript-tsconfig ├── hello-world.tsx ├── index.ts ├── say │ └── index.ts ├── src │ ├── hello-world.tsx │ ├── index.js │ ├── index.ts │ └── say │ │ └── index.ts └── tsconfig.json ├── typescript ├── hello-world.tsx ├── index.ts ├── say │ └── index.ts └── src │ ├── hello-world.tsx │ ├── index.js │ ├── index.ts │ └── say │ └── index.ts └── universal-lib ├── banner.txt ├── bower.json ├── lib ├── browser.js ├── node.js └── resolve.js └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor config 2 | # http://EditorConfig.org 3 | 4 | # This EditorConfig overrides any parent EditorConfigs 5 | root = true 6 | 7 | # Default rules applied to all file types 8 | [*] 9 | 10 | # No trailing spaces, newline at EOF 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | end_of_line = lf 15 | 16 | # 2 space indentation 17 | indent_style = space 18 | indent_size = 2 19 | 20 | # JavaScript-specific settings 21 | [*.{js,ts}] 22 | quote_type = double 23 | continuation_indent_size = 2 24 | curly_bracket_next_line = false 25 | indent_brace_style = BSD 26 | spaces_around_operators = true 27 | spaces_around_brackets = none 28 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | # ESLint config 2 | # http://eslint.org/docs/user-guide/configuring 3 | # https://jstools.dev/eslint-config/ 4 | 5 | root: true 6 | extends: "@jsdevtools" 7 | env: 8 | node: true 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Git attributes 2 | # https://git-scm.com/docs/gitattributes 3 | # https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes 4 | 5 | # Normalize line endings for all files that git determines to be text. 6 | # https://git-scm.com/docs/gitattributes#gitattributes-Settostringvalueauto 7 | * text=auto 8 | 9 | # Normalize line endings to LF on checkin, and do NOT convert to CRLF when checking-out on Windows. 10 | # https://git-scm.com/docs/gitattributes#gitattributes-Settostringvaluelf 11 | *.txt text eol=lf 12 | *.html text eol=lf 13 | *.md text eol=lf 14 | *.css text eol=lf 15 | *.scss text eol=lf 16 | *.map text eol=lf 17 | *.js text eol=lf 18 | *.jsx text eol=lf 19 | *.ts text eol=lf 20 | *.tsx text eol=lf 21 | *.json text eol=lf 22 | *.yml text eol=lf 23 | *.yaml text eol=lf 24 | *.xml text eol=lf 25 | *.svg text eol=lf 26 | -------------------------------------------------------------------------------- /.github/workflows/CI-CD.yaml: -------------------------------------------------------------------------------- 1 | # GitHub Actions workflow 2 | # https://help.github.com/en/actions/automating-your-workflow-with-github-actions 3 | # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions 4 | # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions 5 | 6 | name: CI-CD 7 | 8 | on: 9 | push: 10 | branches: 11 | - "*" 12 | tags-ignore: 13 | - "*" 14 | 15 | schedule: 16 | - cron: "0 0 1 * *" 17 | 18 | jobs: 19 | test: 20 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 21 | runs-on: ${{ matrix.os }} 22 | timeout-minutes: 10 23 | strategy: 24 | fail-fast: true 25 | matrix: 26 | os: 27 | - ubuntu-latest 28 | - macos-latest 29 | - windows-latest 30 | node: 31 | - 10 32 | - 12 33 | - 14 34 | 35 | steps: 36 | - name: Checkout source 37 | uses: actions/checkout@v2 38 | 39 | - name: Install Node ${{ matrix.node }} 40 | uses: actions/setup-node@v1 41 | with: 42 | node-version: ${{ matrix.node }} 43 | 44 | - name: Install dependencies 45 | run: npm ci 46 | 47 | - name: Run linters 48 | run: npm run lint 49 | 50 | - name: Run tests 51 | run: npm run coverage 52 | 53 | - name: Send code coverage results to Coveralls 54 | uses: coverallsapp/github-action@v1.1.0 55 | with: 56 | github-token: ${{ secrets.GITHUB_TOKEN }} 57 | parallel: true 58 | 59 | coverage: 60 | name: Code Coverage 61 | runs-on: ubuntu-latest 62 | timeout-minutes: 10 63 | needs: test 64 | steps: 65 | - name: Let Coveralls know that all tests have finished 66 | uses: coverallsapp/github-action@v1.1.0 67 | with: 68 | github-token: ${{ secrets.GITHUB_TOKEN }} 69 | parallel-finished: true 70 | 71 | deploy: 72 | name: Publish to NPM 73 | if: github.ref == 'refs/heads/master' 74 | runs-on: ubuntu-latest 75 | timeout-minutes: 10 76 | needs: test 77 | 78 | steps: 79 | - name: Checkout source 80 | uses: actions/checkout@v2 81 | 82 | - name: Install Node 83 | uses: actions/setup-node@v1 84 | 85 | - name: Install dependencies 86 | run: npm ci 87 | 88 | - name: Publish to NPM 89 | uses: JS-DevTools/npm-publish@v1 90 | with: 91 | token: ${{ secrets.NPM_TOKEN }} 92 | 93 | - name: Prepare the non-scoped packaged 94 | run: | 95 | cp LICENSE *.md dist 96 | VERSION=$(node -e "console.log(require('./package.json').version)") 97 | sed -i "s/X.X.X/${VERSION}/g" dist/package.json 98 | 99 | - name: Publish the non-scoped package to NPM 100 | uses: JS-DevTools/npm-publish@v1 101 | with: 102 | token: ${{ secrets.NPM_TOKEN }} 103 | package: dist/package.json 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Git ignore 2 | # https://git-scm.com/docs/gitignore 3 | 4 | # Miscellaneous 5 | *~ 6 | *# 7 | .DS_STORE 8 | Thumbs.db 9 | .netbeans 10 | nbproject 11 | .node_history 12 | 13 | # IDEs & Text Editors 14 | .idea 15 | .sublime-* 16 | .vscode/settings.json 17 | .netbeans 18 | nbproject 19 | 20 | # Temporary files 21 | .tmp 22 | .temp 23 | .grunt 24 | .lock-wscript 25 | 26 | # Logs 27 | /logs 28 | *.log 29 | 30 | # Runtime data 31 | pids 32 | *.pid 33 | *.seed 34 | 35 | # Dependencies 36 | node_modules 37 | 38 | # Test output 39 | lib-cov 40 | .nyc_output 41 | /coverage 42 | /test/test-apps/*/dist 43 | /test/test-apps/*/*.bundle.js 44 | -------------------------------------------------------------------------------- /.mocharc.yml: -------------------------------------------------------------------------------- 1 | # Mocha options 2 | # https://mochajs.org/#configuring-mocha-nodejs 3 | # https://github.com/mochajs/mocha/blob/master/example/config/.mocharc.yml 4 | 5 | 6 | # Test files 7 | spec: 8 | - test/fixtures/**/*.js 9 | - test/specs/**/*.spec.js 10 | 11 | # Abort after first test failure 12 | bail: true 13 | retries: 2 14 | recursive: true 15 | timeout: 10000 16 | -------------------------------------------------------------------------------- /.nycrc.yml: -------------------------------------------------------------------------------- 1 | # NYC config 2 | # https://github.com/istanbuljs/nyc#configuration-files 3 | 4 | extension: 5 | - .js 6 | - .ts 7 | 8 | reporter: 9 | - text 10 | - lcov 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Run Simlifyify", 6 | "type": "node", 7 | "request": "launch", 8 | "program": "${workspaceRoot}/bin/simplifyify.js", 9 | "stopOnEntry": false, 10 | "args": [ 11 | "error/error.js", 12 | "--watch", 13 | "--outfile", 14 | "error/dist/error.js", 15 | ], 16 | "cwd": "${workspaceRoot}/test/test-apps", 17 | "preLaunchTask": null, 18 | "runtimeExecutable": null, 19 | "runtimeArgs": [ 20 | "--nolazy" 21 | ], 22 | "env": { 23 | "NODE_ENV": "development", 24 | "DEBUG": "true" 25 | }, 26 | "console": "internalConsole", 27 | "sourceMaps": false 28 | }, 29 | { 30 | "name": "Run tests", 31 | "type": "node", 32 | "request": "launch", 33 | "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", 34 | "stopOnEntry": false, 35 | "args": [ 36 | "--timeout=600000", 37 | "--retries=0" 38 | ], 39 | "cwd": "${workspaceRoot}", 40 | "preLaunchTask": null, 41 | "runtimeExecutable": null, 42 | "runtimeArgs": [ 43 | "--nolazy" 44 | ], 45 | "env": { 46 | "NODE_ENV": "development" 47 | }, 48 | "console": "internalConsole", 49 | "sourceMaps": false 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | { 10 | "version": "0.1.0", 11 | "command": "npm", 12 | "isShellCommand": true, 13 | "suppressTaskName": true, 14 | "tasks": [ 15 | { 16 | "taskName": "lint", 17 | "args": ["run", "lint"], 18 | "showOutput": "always", 19 | "problemMatcher": "$eslint-stylish", 20 | "isBuildCommand": true 21 | }, 22 | { 23 | "taskName": "test", 24 | "args": ["run", "test"], 25 | "showOutput": "always", 26 | "isTestCommand": true 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /404.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: 404 3 | --- 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ==================================================================================================== 3 | All notable changes will be documented in this file. 4 | Simplifyify adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | 7 | 8 | [v8.0.0](https://github.com/JS-DevTools/simplifyify/tree/v8.0.0) (2020-02-18) 9 | ---------------------------------------------------------------------------------------------------- 10 | 11 | - Moved Simplifyify to the [@JSDevTools scope](https://www.npmjs.com/org/jsdevtools) on NPM 12 | 13 | - The "simplifyify" NPM package is now just a wrapper around the scoped "@jsdevtools/simplifyify" package 14 | 15 | 16 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v7.0.7...v8.0.0) 17 | 18 | 19 | 20 | [v7.0.0](https://github.com/JS-DevTools/simplifyify/tree/v7.0.0) (2018-10-18) 21 | ---------------------------------------------------------------------------------------------------- 22 | 23 | #### Breaking Change 24 | - Simplifyify is no longer tested on Node 6 and Node 8. It's now only tested on the latest LTS version of Node (which is currently Node 10). It **currently** still works fine in older versions, but they are no longer officially supported. 25 | 26 | #### Other Changes 27 | - Improved performance by making many operations async and parallelizing them 28 | 29 | - Fixed a bug that caused Simplifyify to crash in watch mode when files contained syntax errors 30 | 31 | 32 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v6.0.0...v7.0.0) 33 | 34 | 35 | 36 | [v6.0.0](https://github.com/JS-DevTools/simplifyify/tree/v6.0.0) (2018-09-29) 37 | ---------------------------------------------------------------------------------------------------- 38 | 39 | #### Breaking Changes 40 | - The shorthand argument for the `--exclude` option is now `-x` instead of `-u` 41 | 42 | - The `--test` argument has been replaced with `--coverage` for clarity. The corresponding shorthand argument is `-c`. 43 | 44 | - The `--coverage` argument produces a `.coverage.js` file instead of a `.test.js` file 45 | 46 | 47 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v5.0.0...v6.0.0) 48 | 49 | 50 | 51 | [v5.0.0](https://github.com/JS-DevTools/simplifyify/tree/v5.0.0) (2018-09-17) 52 | ---------------------------------------------------------------------------------------------------- 53 | 54 | #### TypeScript Support 55 | - Simplifyify now has built-in support for TypeScript! If your entry file has a `.ts` or `.tsx` extension, then Simplifyify will automatically use [TSify](https://github.com/TypeStrong/tsify/) to transpile your code. You can configure TSify via the `browserify.plugins` field in your package.json, or via a tsconfig.json file. If both exist, then the `browserify.plugins` field overrides any values in tsconfig.json. 56 | 57 | #### Breaking Changes 58 | - Dropped support for Node v4.0 and older (see https://github.com/nodejs/Release) 59 | 60 | - Previously, [browserify-banner](https://github.com/JS-DevTools/browserify-banner) could be configured using the `browserify.transform` field in package.json. But browserify-banner is a Browserify plugin, not a transform. This caused it to be loaded twice - once as a plugin and once as a transform. You should now use the `browserify.plugins` field instead. 61 | 62 | - The `browserify.transform` field in package.json can be used to configure Browserify transforms. Previously, Simplifyify allowed you to _also_ use it to configure Browserify plugins, but that caused plugins to be loaded twice - once as a plugin and once as a transform. This can cause undefined behavior with some plugins. To fix that, Simplifyify now expects you to to configure Browserify plugins using the `browserify.plugins` field instead. 63 | 64 | 65 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v4.0.3...v5.0.0) 66 | 67 | 68 | 69 | [v4.0.0](https://github.com/JS-DevTools/simplifyify/tree/v4.0.0) (2018-01-17) 70 | ---------------------------------------------------------------------------------------------------- 71 | 72 | - Updated all dependencies, including major version updates of `browserify`, `babelify`, `browserify-istanbul`, and `exorcist` 73 | 74 | - Switched from UglifyJS to [Uglify-ES](https://www.npmjs.com/package/uglify-es), which supports ES2015+ syntax. This _shouldn't_ break anything, but I'm bumping the major version number just to be safe 75 | 76 | 77 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v3.3.0...v4.0.0) 78 | 79 | 80 | 81 | [v3.3.0](https://github.com/JS-DevTools/simplifyify/tree/v3.3.0) (2018-01-10) 82 | ---------------------------------------------------------------------------------------------------- 83 | 84 | - Refactored to use ES6 syntax (Node 4.x compatible) 85 | 86 | - The `--standalone` option now supports a wildcard (e.g. "MyLib.*"). Thanks to [@taye](https://github.com/taye) for [the PR](https://github.com/JS-DevTools/simplifyify/pull/24) 87 | 88 | 89 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v3.2.0...v3.3.0) 90 | 91 | 92 | 93 | [v3.2.0](https://github.com/JS-DevTools/simplifyify/tree/v3.2.0) (2016-11-11) 94 | ---------------------------------------------------------------------------------------------------- 95 | 96 | - Fixed several subtle bugs that were introduced in 3.1.0 97 | 98 | 99 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v3.1.0...v3.2.0) 100 | 101 | 102 | 103 | [v3.1.0](https://github.com/JS-DevTools/simplifyify/tree/v3.1.0) (2016-11-06) 104 | ---------------------------------------------------------------------------------------------------- 105 | 106 | #### New Feature: [bannerify](https://www.npmjs.com/package/bannerify) support 107 | Just add a `banner.txt` file to your project, and it'll automatically be added to your output bundle(s). The `banner.txt` file can contain [Lodash templates](https://lodash.com/docs/4.16.6#template), which have access to the full [lodash](https://lodash.com/docs/4.16.6) library as well as [moment-js](http://momentjs.com/) for date/time formatting. See [this example](https://github.com/JS-DevTools/simplifyify/blob/master/test/test-apps/hello/banner.txt). 108 | 109 | #### Better performance 110 | File i/o operations have been optimized in this release. Files that are likely to be needed by multiple entry files are cached so they only need to be read once. Other file i/o operations that were previously synchronous are now asynchronous. 111 | 112 | 113 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v3.0.0...v3.1.0) 114 | 115 | 116 | 117 | [v3.0.0](https://github.com/JS-DevTools/simplifyify/tree/v3.0.0) (2016-11-02) 118 | ---------------------------------------------------------------------------------------------------- 119 | 120 | #### Major changes in this release: 121 | 122 | ##### 1) Dropped support for Node 0.x 123 | Simplifyify now requires Node 4.0 or greater, which is in-line with the [Node.js LTS schedule](https://github.com/nodejs/LTS). Many other dev tools, including some that `simplifyify` depends on, have also started dropping support for Node 0.x. Time to upgrade, folks. 124 | 125 | ##### 2) Better minification 126 | Simplifyify has always used [uglifyify](https://www.npmjs.com/package/uglifyify) under the hood to minify each module individually, but now it _also_ uses [UglifyJS](https://github.com/mishoo/UglifyJS2#uglifyjs-2) to minify the entire bundle file. This [2-phase process](https://github.com/JS-DevTools/simplifyify/blob/5ab81a30242b585bee21915fe899714404a4e81a/lib/add-transforms.js#L91-L159) produces the [smallest output possible](https://github.com/hughsk/uglifyify#motivationusage). 127 | 128 | ##### 3) Configure Uglifyify and Istanbul options 129 | You can now specify custom options for the built-in Uglifyify and Istanbul transforms via the [`browserify.transform`](https://github.com/substack/node-browserify#browserifytransform) in your `package.json`. See [this example](https://github.com/JS-DevTools/simplifyify#browserify-transforms) in the ReadMe. 130 | 131 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v2.0.4...v3.0.0) 132 | 133 | 134 | 135 | [v2.0.0](https://github.com/JS-DevTools/simplifyify/tree/v2.0.0) (2015-12-28) 136 | ---------------------------------------------------------------------------------------------------- 137 | 138 | #### Major changes in this release: 139 | 140 | ##### 1) Support for Browserify transforms 141 | Simplifyify will now check your `package.json` file to see if you have a [browserify.transform](https://github.com/substack/node-browserify#browserifytransform) field. If so, then it will automatically add those transforms. No need to specify them on the command line. See [the readme](https://github.com/JS-DevTools/simplifyify#browserify-transforms) for more details. 142 | 143 | ##### 2) You choose whether the "default" bundle gets created 144 | In previous versions, Simplifyify _always_ created an unminified bundle. This makes sense if you don't specify _any_ output options. But if you _do_ specify output options (such as `--coverage` or `--minify`), then you may not have expected it to _also_ create an unminified bundle. So, in this version, there is now a `--bundle` option that you must use to explicitly specify that you want an unminified bundle. Otherwise, only the bundle(s) that you explicitly specify will be created. 145 | 146 | [Full Changelog](https://github.com/JS-DevTools/simplifyify/compare/v1.6.0...v2.0.0) 147 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 James Messinger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simplifyify 2 | ============================ 3 | #### A simplified Browserify and Watchify CLI 4 | 5 | [![Cross-Platform Compatibility](https://jstools.dev/img/badges/os-badges.svg)](https://github.com/JS-DevTools/simplifyify/actions) 6 | [![Build Status](https://github.com/JS-DevTools/simplifyify/workflows/CI-CD/badge.svg)](https://github.com/JS-DevTools/simplifyify/actions) 7 | 8 | [![Coverage Status](https://coveralls.io/repos/github/JS-DevTools/simplifyify/badge.svg?branch=master)](https://coveralls.io/github/JS-DevTools/simplifyify?branch=master) 9 | [![Dependencies](https://david-dm.org/JS-DevTools/simplifyify.svg)](https://david-dm.org/JS-DevTools/simplifyify) 10 | 11 | [![npm](https://img.shields.io/npm/v/@jsdevtools/simplifyify.svg)](https://www.npmjs.com/package/@jsdevtools/simplifyify) 12 | [![License](https://img.shields.io/npm/l/@jsdevtools/simplifyify.svg)](LICENSE) 13 | [![Buy us a tree](https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-lightgreen)](https://plant.treeware.earth/JS-DevTools/simplifyify) 14 | 15 | I constantly find myself using the same Browserify plug-ins and transforms on every project, and I always end up writing pretty much the same Gulp script over and over again. Simplifyify is the solution to that problem. 16 | 17 | 18 | 19 | Features 20 | -------------------------- 21 | - Supports [globs](https://github.com/isaacs/node-glob#glob-primer), even on Windows 22 | - Supports Browserify [transforms](#browserify-transforms) and [plugins](#browserify-plugins), such as Babel, CoffeeScript, TypeScript, etc. 23 | - Built-in support for TypeScript. Enabled automatically if the entry file has a `.ts` or `.tsx` extension 24 | - Has a programmatic [API](#api), for use with build tools like Grunt, Gulp, Broccoli, etc. 25 | - Bundle everything into one big file, or create different bundles for each part of your app (see [examples below](#examples)) 26 | - Add a banner with version, date, license, etc. via [browserify-banner](https://www.npmjs.com/package/browserify-banner) 27 | - One command creates all the files you need: 28 | - `--bundle` bundles your code and nothing else. Useful during development 29 | - `--debug` creates _external_ source-maps (`.map`) using [exorcist](https://www.npmjs.com/package/exorcist) 30 | - `--minify` shrinks your code using [uglifyify](https://www.npmjs.com/package/uglifyify) _and_ [Uglify-ES](https://github.com/mishoo/UglifyJS2/tree/harmony) 31 | - `--coverage` adds code-coverage instrumentation using [istanbul](https://istanbul.js.org/) 32 | - `--watch` uses [watchify](https://www.npmjs.com/package/watchify) for _fast_ differential re-builds as files change 33 | 34 | 35 | Related Projects 36 | -------------------------- 37 | - [globify](https://jstools.dev/globify)
38 | Run browserify and watchify with globs - even on Windows 39 | 40 | - [sourcemapify](https://jstools.dev/sourcemapify)
41 | Sourcemap plugin for Browserify 42 | 43 | - [browserify-banner](https://jstools.dev/browserify-banner)
44 | Add a comment (and/or code) to the top of your Browserify bundle 45 | 46 | 47 | 48 | Installation 49 | -------------------------- 50 | Install using [npm](https://docs.npmjs.com/about-npm/): 51 | 52 | ```bash 53 | npm install @jsdevtools/simplifyify 54 | ``` 55 | 56 | 57 | Usage 58 | -------------------------- 59 | ``` 60 | Usage: simplifyify [options] 61 | 62 | Options: 63 | 64 | -b, --bundle Create a non-minified bundle (*.js) for each source file. 65 | This is the default if no other output option is set. 66 | 67 | -m, --minify Create a minified bundle (*.min.js) for each source file. 68 | 69 | -c, --coverage Create a bundle with code-coverage instrumentation 70 | (*.coverage.js) for each source file. 71 | 72 | -d, --debug Create a source map (*.js.map) for each bundle 73 | 74 | -w, --watch Watch source file(s) and rebuild the bundle(s) automatically 75 | 76 | -o, --outfile The output file or directory. 77 | May include a filename pattern (e.g. "*.bundle.js") 78 | 79 | -x, --exclude File path or glob pattern to exclude. 80 | Don't forget to put quotes around glob patterns 81 | 82 | -s, --standalone Export as a named UMD bundle (e.g. "my.cool.module") 83 | May include a wildcard (e.g. "MyLib.*") 84 | 85 | Arguments: 86 | 87 | One or more file paths and/or glob patterns. 88 | Don't forget to put quotes around glob patterns. 89 | A separate Browserify bundle will be created 90 | for each source file. 91 | ``` 92 | 93 | 94 | Examples 95 | -------------------------- 96 | #### One entry file --> one output file 97 | In the simplest usage, you can use Simplifyify to bundle all of your code into a single file: 98 | 99 | ```bash 100 | simplifyify src/index.js 101 | 102 | src/index.js --> src/index.bundle.js # <-- unminified code 103 | ``` 104 | 105 | By default, the output file is at the same path as the entry file, but with a `.bundle.js` extension. You can customize this using the `--outfile` argument: 106 | 107 | ```bash 108 | simplifyify src/index.js --outfile dist/my-package.js 109 | 110 | src/index.js --> dist/my-package.js # <-- unminified code 111 | ``` 112 | 113 | If you want the bundled code to be minified, then add the `--minify` flag: 114 | 115 | ```bash 116 | simplifyify src/index.js --outfile dist/my-package.js --minify 117 | 118 | src/index.js --> dist/my-package.js # <-- minified code 119 | ``` 120 | 121 | What if you also want a source map (`.map`) file? Just add the `--debug` flag. 122 | 123 | ```bash 124 | simplifyify src/index.js --outfile dist/my-package.js --minify --debug 125 | 126 | src/index.js --> dist/my-package.js # <-- minified code 127 | src/index.js --> dist/my-package.js.map # <-- source map 128 | ``` 129 | 130 | 131 | 132 | #### One entry file --> multiple output files 133 | Simplifyify can output multiple bundles of your code in a single command. Let's say you want to create an unminified bundle for development (with a source map), a minified bundle for production (with a source map), and a test bundle (with code-coverage instrumentation) for testing: 134 | 135 | ```bash 136 | simplifyify src/index.js --outfile dist/my-package.js --bundle --debug --minify --coverage 137 | 138 | src/index.js --> dist/my-package.js # <-- unminified code 139 | src/index.js --> dist/my-package.js.map # <-- source map 140 | src/index.js --> dist/my-package.min.js # <-- minified code 141 | src/index.js --> dist/my-package.min.js.map # <-- source map 142 | src/index.js --> dist/my-package.coverage.js # <-- code-coverage 143 | ``` 144 | 145 | 146 | 147 | #### Multiple entry files --> multiple output files _for each_ 148 | In many applications, it doesn't make sense for _all_ of your code to be bundled into one huge file. Maybe you want to create separate bundles for each folder, or for each component or section of your app. Simplifyify makes this easy. It will create separate bundles for each entry file that you specify. For example: 149 | 150 | ```bash 151 | simplifyify src/store.js src/cart.js src/checkout.js --outfile dist --bundle --minify --debug 152 | 153 | src/store.js --> dist/store.js # <-- unminified code 154 | src/store.js --> dist/store.js.map # <-- source map 155 | src/store.js --> dist/store.min.js # <-- minified code 156 | src/store.js --> dist/store.min.js.map # <-- source map 157 | src/cart.js --> dist/cart.js # <-- unminified code 158 | src/cart.js --> dist/cart.js.map # <-- source map 159 | src/cart.js --> dist/cart.min.js # <-- minified code 160 | src/cart.js --> dist/cart.min.js.map # <-- source map 161 | src/checkout.js --> dist/checkout.js # <-- unminified code 162 | src/checkout.js --> dist/checkout.js.map # <-- source map 163 | src/checkout.js --> dist/checkout.min.js # <-- minified code 164 | src/checkout.js --> dist/checkout.min.js.map # <-- source map 165 | ``` 166 | 167 | Specifying each entry file can quickly become cumbersome though. That's where [globs](https://github.com/isaacs/node-glob#glob-primer) come in. You can specify one or more globs, and Simplifyify will create a separate bundle for each file that matches the glob pattern. For example: 168 | 169 | ```bash 170 | simplifyify "src/*/index.js" --outfile "dist/*.bundle.js" --bundle --minify --debug 171 | 172 | src/store/index.js --> dist/store/index.bundle.js # <-- unminified code 173 | src/store/index.js --> dist/store/index.bundle.js.map # <-- source map 174 | src/store/index.js --> dist/store/index.bundle.min.js # <-- minified code 175 | src/store/index.js --> dist/store/index.bundle.min.js.map # <-- source map 176 | src/cart/index.js --> dist/cart/index.bundle.js # <-- unminified code 177 | src/cart/index.js --> dist/cart/index.bundle.js.map # <-- source map 178 | src/cart/index.js --> dist/cart/index.bundle.min.js # <-- minified code 179 | src/cart/index.js --> dist/cart/index.bundle.min.js.map # <-- source map 180 | src/checkout/index.js --> dist/checkout/index.bundle.js # <-- unminified code 181 | src/checkout/index.js --> dist/checkout/index.bundle.js.map # <-- source map 182 | src/checkout/index.js --> dist/checkout/index.bundle.min.js # <-- minified code 183 | src/checkout/index.js --> dist/checkout/index.bundle.min.js.map # <-- source map 184 | ``` 185 | 186 | > **TIP:** Don't forget to put quotes around your glob patterns! Otherwise, some shells (e.g. Bash) will try to expand them themselves, which may or may not work 187 | 188 | 189 | 190 | Browserify Transforms 191 | -------------------------- 192 | Simplifyify honors the [`browserify.transform`](https://github.com/substack/node-browserify#browserifytransform) field in your `package.json` file. For example, the following configuration uses [Babelify](https://github.com/babel/babelify) to transform your ES6 code to ES5: 193 | 194 | ```json 195 | { 196 | "name": "my-package", 197 | "version": "1.2.3", 198 | "browserify": { 199 | "transform": ["babelify"] 200 | }, 201 | "devDependencies": { 202 | "babelify": "^10.0.0" 203 | } 204 | } 205 | ``` 206 | 207 | You can also specify options for your transforms. The exact options depend on the transform you're using. Here's an example that configures [Babelify](https://github.com/babel/babelify) and also modifies Simplifyify's default config for [uglifyify](https://www.npmjs.com/package/uglifyify): 208 | 209 | ```json 210 | { 211 | "name": "my-package", 212 | "version": "1.2.3", 213 | "browserify": { 214 | "transform": [ 215 | ["babelify", { 216 | "presets": ["@babel/preset-env"] 217 | }], 218 | ["uglifyify", { 219 | "mangle": true, 220 | "compress": { 221 | "sequences": true, 222 | "dead_code": true, 223 | "booleans": true, 224 | "conditionals": true, 225 | "if_return": false, 226 | "drop_console": false, 227 | "keep_fnames": true 228 | }, 229 | "output": { 230 | "comments": false 231 | } 232 | }] 233 | ] 234 | }, 235 | "devDependencies": { 236 | "@babel/preset-env": "^7.0.0", 237 | "babelify": "^10.0.0" 238 | } 239 | } 240 | ``` 241 | 242 | 243 | 244 | Browserify Plugins 245 | -------------------------- 246 | The same technique described above for Browserify transforms also works for Browserify plugins. Just add a `browserify.plugins` field to your `package.json` file. For example, the following configuration configures [TSify](https://github.com/TypeStrong/tsify/) to transpile your TypeScript code, and [browserify-banner](https://github.com/JS-DevTools/browserify-banner) to add a banner comment to the top of your output file(s). 247 | 248 | ```json 249 | { 250 | "name": "my-package", 251 | "version": "1.2.3", 252 | "browserify": { 253 | "plugins": [ 254 | ["browserify-banner", { 255 | "template": "<%= pkg.name %> v<%= pkg.version %>" 256 | }], 257 | ["tsify", { 258 | "target": "esnext", 259 | "module": "commonjs", 260 | "moduleResolution": "node", 261 | "jsx": "react" 262 | }] 263 | ] 264 | }, 265 | "devDependencies": { 266 | "typescript": "^3.0.3" 267 | } 268 | } 269 | ``` 270 | 271 | 272 | 273 | API 274 | -------------------------- 275 | Simplifyify also has a programmatic API, so you can use it directly in your build scripts (Gulp, Grunt, Broccoli, etc.) 276 | 277 | [Here's the API definition](https://github.com/JS-DevTools/simplifyify/blob/6709bb5bbf59b327b4ced3e833078de8db006b5a/lib/index.js#L9-L28), and [here's a full example](https://github.com/JS-DevTools/simplifyify/blob/6709bb5bbf59b327b4ced3e833078de8db006b5a/bin/simplifyify.js#L71-L102). Just pass an array of strings (file paths and/or glob patterns) and an options param. You get back an [`EventEmitter`](https://nodejs.org/api/events.html#events_class_events_eventemitter), which fires all the Browserify & Watchify events. 278 | 279 | ```javascript 280 | var simplifyify = require("@jsdevtools/simplifyify"); 281 | 282 | gulp.task("browserify", function(done) { 283 | simplifyify("lib/*.module.js", 284 | { 285 | outfile: "dist/*.bundle.js", 286 | debug: true, 287 | minify: true 288 | }) 289 | .on("end", function() { 290 | // Finished successfully! 291 | done(); 292 | }) 293 | .on("error", function(err) { 294 | // Something went wrong 295 | done(err); 296 | }); 297 | }); 298 | ``` 299 | 300 | 301 | 302 | Contributing 303 | -------------------------- 304 | Contributions, enhancements, and bug-fixes are welcome! [Open an issue](https://github.com/JS-DevTools/simplifyify/issues) on GitHub and [submit a pull request](https://github.com/JS-DevTools/simplifyify/pulls). 305 | 306 | #### Building 307 | To build the project locally on your computer: 308 | 309 | 1. __Clone this repo__
310 | `git clone https://github.com/JS-DevTools/simplifyify.git` 311 | 312 | 2. __Install dependencies__
313 | `npm install` 314 | 315 | 3. __Run the tests__
316 | `npm test` 317 | 318 | 319 | 320 | License 321 | -------------------------- 322 | Simplifyify is 100% free and open-source, under the [MIT license](LICENSE). Use it however you want. 323 | 324 | This package is [Treeware](http://treeware.earth). If you use it in production, then we ask that you [**buy the world a tree**](https://plant.treeware.earth/JS-DevTools/simplifyify) to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats. 325 | 326 | 327 | 328 | Big Thanks To 329 | -------------------------- 330 | Thanks to these awesome companies for their support of Open Source developers ❤ 331 | 332 | [![GitHub](https://jstools.dev/img/badges/github.svg)](https://github.com/open-source) 333 | [![NPM](https://jstools.dev/img/badges/npm.svg)](https://www.npmjs.com/) 334 | [![Coveralls](https://jstools.dev/img/badges/coveralls.svg)](https://coveralls.io) 335 | [![Travis CI](https://jstools.dev/img/badges/travis-ci.svg)](https://travis-ci.com) 336 | [![SauceLabs](https://jstools.dev/img/badges/sauce-labs.svg)](https://saucelabs.com) 337 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: JS-DevTools/gh-pages-theme 2 | 3 | title: Simplifyify 4 | logo: https://jstools.dev/img/logos/logo.png 5 | 6 | author: 7 | twitter: JSDevTools 8 | 9 | google_analytics: UA-68102273-3 10 | 11 | twitter: 12 | username: JSDevTools 13 | card: summary 14 | 15 | defaults: 16 | - scope: 17 | path: "" 18 | values: 19 | image: https://jstools.dev/img/logos/card.png 20 | - scope: 21 | path: "test/**/*" 22 | values: 23 | sitemap: false 24 | 25 | plugins: 26 | - jekyll-sitemap 27 | -------------------------------------------------------------------------------- /bin/simplifyify.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | let program = require("commander"); 5 | let path = require("path"); 6 | let manifest = require("../package"); 7 | let simplifyify = require("../"); 8 | 9 | /** 10 | * Parse command-line arguments 11 | */ 12 | function parseArguments () { 13 | program 14 | .version(manifest.version) 15 | .description(manifest.description) 16 | .arguments("") 17 | .option("-b, --bundle", "Create a non-minified bundle (*.js) for each source file") 18 | .option("-m, --minify", "Create a minified bundle (*.min.js) for each source file") 19 | .option("-c, --coverage", "Create a bundle with code-coverage instrumentation (*.coverage.js)") 20 | .option("-d, --debug", "Create a source map (*.js.map) for each bundle") 21 | .option("-w, --watch", "Watch source file(s) and rebuild the bundle(s) automatically") 22 | .option("-o, --outfile ", 'The output file or directory. May include a filename pattern (e.g. "*.bundle.js")') 23 | .option("-x, --exclude ", "File path or glob pattern to exclude") 24 | .option("-s, --standalone ", 'Export as a named UMD bundle (e.g. "my.cool.bundle"). May include a wildcard (e.g. "MyLib.*")') 25 | .on("--help", () => { 26 | console.log( 27 | " Arguments:\n" + 28 | "\n" + 29 | " One or more file paths and/or glob patterns.\n" + 30 | " Don't forget to put quotes around glob patterns.\n" + 31 | " A separate Browserify bundle will be created\n" + 32 | " for each source file.\n" + 33 | "\n" + 34 | " Examples:\n" + 35 | "\n" + 36 | " simplifyify src/index.js --outfile dist/bundle.js --bundle --debug --minify --coverage\n" + 37 | "\n" + 38 | " Output Files: \n" + 39 | " dist/bundle.js\n" + 40 | " dist/bundle.js.map\n" + 41 | " dist/bundle.min.js\n" + 42 | " dist/bundle.min.js.map\n" + 43 | " dist/bundle.coverage.js\n" + 44 | "\n" + 45 | "\n" + 46 | ' simplifyify "src/module-*.js" --outfile "dist/*.bundle.js" --bundle --minify\n' + 47 | "\n" + 48 | " Output Files: \n" + 49 | " dist/module-one.bundle.js\n" + 50 | " dist/module-one.bundle.min.js\n" + 51 | " dist/module-two.bundle.js\n" + 52 | " dist/module-two.bundle.min.js\n" 53 | ); 54 | }) 55 | .parse(process.argv); 56 | 57 | // Show help if no options were given 58 | if (program.args.length === 0) { 59 | program.outputHelp(); 60 | process.exit(1); 61 | } 62 | } 63 | 64 | /** 65 | * Program entry point 66 | */ 67 | function main () { 68 | parseArguments(); 69 | 70 | simplifyify(program.args, program) 71 | .on("update", (file) => { 72 | // Log that a file change has been detected 73 | let relativePath = path.relative(process.cwd(), file); 74 | console.log(`${relativePath} has changed`); 75 | }) 76 | .on("log", (msg) => { 77 | // Log # of bytes written & time taken 78 | console.log(msg); 79 | }) 80 | .on("end", (fileSet) => { 81 | // Log the output files that were written 82 | console.log(`${fileSet.entryFile} --> ${fileSet.outputFile}`); 83 | if (fileSet.mapFile) { 84 | console.log(`${fileSet.entryFile} --> ${fileSet.mapFile}`); 85 | } 86 | }) 87 | .on("error", (err, fileSet) => { 88 | // Log an error 89 | if (fileSet && fileSet.entryFile) { 90 | console.error(`Error bundling ${fileSet.entryFile}`); 91 | } 92 | 93 | if (process.env.DEBUG) { 94 | if (err.annotated) { 95 | // Show the annotated source code where the error occurred 96 | console.error(err.annotated); 97 | 98 | // Also show the stack trace, if there is one 99 | err.stack && console.error(err.stack); 100 | } 101 | else { 102 | // Show the stack trace, or fallback to the error message 103 | console.error(err.stack || err.message); 104 | } 105 | } 106 | else { 107 | console.error(err.message); 108 | } 109 | 110 | // Exit the app with an error code, 111 | // unless we're in "Watchify" mode, in which case, we just keep watching 112 | if (!program.watch) { 113 | process.exit(2); 114 | } 115 | }); 116 | } 117 | 118 | main(); 119 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = require("@jsdevtools/simplifyify"); 3 | -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplifyify", 3 | "version": "X.X.X", 4 | "description": "A simplified Browserify and Watchify CLI", 5 | "keywords": [ 6 | "browserify", 7 | "browserify-plugin", 8 | "watchify", 9 | "cli", 10 | "minify", 11 | "uglify", 12 | "uglifyify", 13 | "sourcemap", 14 | "source-map", 15 | "source map", 16 | "exorcist", 17 | "istanbul" 18 | ], 19 | "author": { 20 | "name": "James Messinger", 21 | "url": "https://jamesmessinger.com" 22 | }, 23 | "homepage": "https://jstools.dev/simplifyify", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/JS-DevTools/simplifyify.git" 27 | }, 28 | "license": "MIT", 29 | "main": "index.js", 30 | "bin": { 31 | "simplifyify": "simplifyify.js" 32 | }, 33 | "files": [ 34 | "simplifyify.js", 35 | "index.js" 36 | ], 37 | "engines": { 38 | "node": ">=10" 39 | }, 40 | "dependencies": { 41 | "@jsdevtools/simplifyify": "X.X.X" 42 | }, 43 | "peerDependencies": { 44 | "typescript": "*" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dist/simplifyify.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | require("@jsdevtools/simplifyify/bin/simplifyify.js"); 4 | -------------------------------------------------------------------------------- /lib/expand-globs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const globby = require("globby"); 4 | const path = require("path"); 5 | const FileSet = require("./file-set"); 6 | const util = require("./util"); 7 | 8 | module.exports = expandGlobs; 9 | 10 | /** 11 | * Expands the given list of file paths and/or globs, and returns an array of {@link FileSet} objects 12 | * that map input files to their corresponding output files. 13 | * 14 | * @param {string[]} globs - Entry file paths and/or glob patterns 15 | * @param {Options} options - Simplifyify CLI options 16 | * @returns {Promise} 17 | */ 18 | function expandGlobs (globs, options) { 19 | let outfileIsADirectory = isDirectory(options.outfile); 20 | 21 | return Promise.all( 22 | globs.map((pattern) => { 23 | return expandGlob(pattern, options, outfileIsADirectory); 24 | })) 25 | .then((arraysOfFileSets) => { 26 | // Flatten the array of FileSets 27 | return Array.prototype.concat.apply([], arraysOfFileSets); 28 | }); 29 | } 30 | 31 | /** 32 | * Expands the given glob pattern, and returns an array of {@link FileSet} objects that map 33 | * input files to their corresponding output files. 34 | * 35 | * @param {string} pattern - Entry file paths and/or glob pattern 36 | * @param {Options} options - Simplifyify CLI options 37 | * @param {boolean} outfileIsADirectory - Indicates whether the output location is a directory or a file 38 | * @returns {Promise} 39 | */ 40 | function expandGlob (pattern, options, outfileIsADirectory) { 41 | let baseDir; 42 | 43 | return Promise.resolve() 44 | .then(() => { 45 | // Determine the common parent directory of all the glob patterns 46 | baseDir = getBaseDir(pattern); 47 | 48 | // Find all files that match this glob pattern 49 | return globby(pattern, { 50 | unique: true, // only return unique matches 51 | onlyFiles: true, // only match files, not directories 52 | ignore: options.exclude ? [options.exclude] : [] 53 | }); 54 | }) 55 | .then(entryFiles => { 56 | let fileSets = []; 57 | 58 | // Create a FileSet for each entry file that was found 59 | for (let entryFile of entryFiles) { 60 | let fileSet = new FileSet(); 61 | fileSet.entryFile = entryFile; 62 | 63 | if (outfileIsADirectory) { 64 | fileSet.outputFile = rename(entryFile, baseDir, options.outfile); 65 | } 66 | else if (options.outfile) { 67 | fileSet.outputFile = options.outfile; 68 | } 69 | else { 70 | fileSet.outputFile = util.appendToFileName(entryFile, ".bundle"); 71 | } 72 | 73 | if (options.debug) { 74 | fileSet.mapFile = fileSet.outputFile + ".map"; 75 | } 76 | 77 | if (options.standalone) { 78 | fileSet.standalone = getStandalone(entryFile, baseDir, options.standalone); 79 | } 80 | 81 | fileSets.push(fileSet); 82 | } 83 | 84 | return fileSets; 85 | }); 86 | } 87 | 88 | /** 89 | * Determines the base directory of the given glob pattern. 90 | * This is used to determine the relative paths of matched files. 91 | * 92 | * @param {string} pattern - A glob pattern, such as "dir/subdir/*.js" 93 | * @returns {string} 94 | */ 95 | function getBaseDir (pattern) { 96 | // Some examples: 97 | // - *.js => . 98 | // - dir/**/*.js => dir 99 | // - dir/subdir/main-*.js => dir/subdir 100 | // - dir/subdir/index.js => dir/subdir 101 | // - dir/subdir/index.(js|coffee) => dir/subdir 102 | 103 | let wildcard = pattern.indexOf("*"); 104 | if (wildcard >= 0) { 105 | pattern = pattern.substr(0, wildcard + 1); 106 | } 107 | return path.dirname(pattern); 108 | } 109 | 110 | /** 111 | * Determines whether the given output filename is a directory. 112 | * 113 | * @param {string} pattern - A file path, a directory path, or a pattern, such as "dist/*.bundle.js" 114 | * @returns {boolean} 115 | */ 116 | function isDirectory (pattern) { 117 | if (pattern) { 118 | let basename = path.basename(pattern); 119 | if (basename.includes("*")) { 120 | // The pattern includes a filename pattern (e.g. "dist/*.bundle.js"), 121 | // which counts as a directory path 122 | return true; 123 | } 124 | else if (!basename.includes(".")) { 125 | // The pattern has no file extension, so assume it's a directory 126 | return true; 127 | } 128 | } 129 | 130 | return false; 131 | } 132 | 133 | /** 134 | * Returns the output file name, based on the the entry file name, the base directory, 135 | * and the output path/pattern. 136 | * 137 | * @param {string} file - The source file path and name (e.g. "lib/dir/subdir/my-file.js") 138 | * @param {string} baseDir - The directory to calculate the relative path from (e.g. "lib") 139 | * @param {string} namePattern - The output file path and pattern (e.g. "dest/*.bundle.js") 140 | * @returns {string} - The main output file path and name (e.g. "dest/dir/subdir/my-file.bundle.js") 141 | */ 142 | function rename (file, baseDir, namePattern) { 143 | let fileExtName = path.extname(file); // .js 144 | let fileBaseName = path.basename(file, fileExtName); // my-file 145 | let relativeDir = path.dirname(path.relative(baseDir, file)); // dir/subdir 146 | 147 | let patternFileName = path.basename(namePattern); // *.bundle.js 148 | let patternDir; 149 | if (!patternFileName.includes("*")) { 150 | patternDir = namePattern; // dest 151 | 152 | // TypeScript files transpile to JavaScript files 153 | if (util.isTypeScript(file)) { 154 | fileExtName = ".js"; 155 | } 156 | } 157 | else { 158 | patternDir = getBaseDir(namePattern); // dest 159 | fileExtName = patternFileName.substr(patternFileName.indexOf("*") + 1); // .bundle.js 160 | } 161 | 162 | let outputDir = path.join(patternDir, relativeDir); // dest/dir/subdir 163 | return path.join(outputDir, fileBaseName + fileExtName); // dest/dir/subdir/my-file.bundle.js 164 | } 165 | 166 | /** 167 | * Returns the output file name, based on the the entry file name, the base directory, 168 | * and the output path/pattern. 169 | * 170 | * @param {string} file - The source file path and name (e.g. "lib/dir/subdir/my-file.js") 171 | * @param {string} baseDir - The directory to calculate the relative path from (e.g. "lib") 172 | * @param {string} standalonePattern - The standalone option pattern (e.g. "MyLib.*") 173 | * @returns {string} - The UMD standalone module name (e.g. "MyLib.dir.subdir.my-file") 174 | */ 175 | function getStandalone (file, baseDir, standalonePattern) { 176 | let patternWildcardIndex = standalonePattern.indexOf("*"); 177 | 178 | if (patternWildcardIndex === -1) { 179 | // The same standalone name will be used for all bundles 180 | return standalonePattern; 181 | } 182 | 183 | let fileExtName = path.extname(file); // .js 184 | let fileBaseName = path.basename(file, fileExtName); // my-file 185 | let relativeDir = path.dirname(path.relative(baseDir, file)); // dir/subdir 186 | 187 | let standaloneName; 188 | if (relativeDir === ".") { 189 | standaloneName = fileBaseName; // my-file 190 | } 191 | else { 192 | let standaloneNamespace = relativeDir.replace(/[/\\]/g, "."); // dir.subdir 193 | standaloneName = standaloneNamespace + "." + fileBaseName; // dir.subdir.my-file 194 | } 195 | 196 | let standalone = standalonePattern.replace("*", standaloneName); // MyLib.dir.subdir.my-file 197 | return standalone; 198 | } 199 | -------------------------------------------------------------------------------- /lib/file-set.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * The input & output files for a Browserify bundle 5 | */ 6 | class FileSet { 7 | constructor () { 8 | /** 9 | * The entry file for a CommonJS module 10 | * @type {string} 11 | */ 12 | this.entryFile = ""; 13 | 14 | /** 15 | * The output file for a Browserify bundle 16 | * @type {string} 17 | */ 18 | this.outputFile = ""; 19 | 20 | /** 21 | * The source map file for a Browserify bundle 22 | * @type {string} 23 | */ 24 | this.mapFile = ""; 25 | 26 | /** 27 | * The UMD standalone module name for a Browserify bundle 28 | * @type {string} 29 | */ 30 | this.standalone = ""; 31 | } 32 | } 33 | 34 | module.exports = FileSet; 35 | -------------------------------------------------------------------------------- /lib/fs-cache.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | 6 | const cache = {/* 7 | filePath: { 8 | exists: true|false, 9 | contents: string|object, 10 | } 11 | */}; 12 | 13 | /** 14 | * Caches file contents so we don't have to find and read the same files 15 | * for every entry file. 16 | */ 17 | module.exports = { 18 | findFile, 19 | readTextFile, 20 | readJsonFile, 21 | }; 22 | 23 | /** 24 | * Searches for the given file name, starting in the given directory 25 | * and crawling up from there. 26 | * 27 | * @param {string} startingPath - The file path to start at 28 | * @returns {string|undefined} 29 | */ 30 | function findFile (startingPath) { 31 | let cached = cacheFile(startingPath); 32 | 33 | if (cached.exists) { 34 | return startingPath; 35 | } 36 | 37 | let fileName = path.basename(startingPath); 38 | let startingDir = path.dirname(startingPath); 39 | let parentDir = path.dirname(startingDir); 40 | if (parentDir !== startingDir) { 41 | return findFile(path.join(parentDir, fileName)); 42 | } 43 | } 44 | 45 | /** 46 | * Returns the contents of the specified file as a string. 47 | * 48 | * @param {string} filePath 49 | * @returns {string} 50 | */ 51 | function readTextFile (filePath) { 52 | let cached = cacheFile(filePath); 53 | return cached.contents; 54 | } 55 | 56 | /** 57 | * Returns the contents of the specified file as a JSON object. 58 | * 59 | * @param {string} filePath 60 | * @returns {object} 61 | */ 62 | function readJsonFile (filePath) { 63 | let cached = cacheFile(filePath); 64 | if (!cached.contents) { 65 | cached.contents = {}; 66 | } 67 | else if (typeof cached.contents === "string") { 68 | cached.contents = JSON.parse(cached.contents); 69 | } 70 | return cached.contents; 71 | } 72 | 73 | /** 74 | * Caches the given file, and returns the cached file. 75 | * 76 | * @param {string} filePath 77 | * @returns {object} 78 | */ 79 | function cacheFile (filePath) { 80 | let cached = cache[filePath]; 81 | 82 | if (cached) { 83 | return cached; 84 | } 85 | 86 | cached = {}; 87 | try { 88 | cached.contents = fs.readFileSync(filePath, "utf8"); 89 | cached.exists = true; 90 | } 91 | catch (e) { 92 | cached.exists = false; 93 | cached.contents = undefined; 94 | } 95 | 96 | return cache[filePath] = cached; 97 | } 98 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const expandGlobs = require("./expand-globs"); 4 | const writeBundles = require("./write-bundles"); 5 | const EventEmitter = require("events").EventEmitter; 6 | 7 | module.exports = simplifyify; 8 | 9 | /** 10 | * @typedef {{ 11 | * outfile: string, 12 | * exclude: string, 13 | * standalone: string, 14 | * bundle: boolean, 15 | * debug: boolean, 16 | * minify: boolean, 17 | * coverage: boolean, 18 | * watch: boolean 19 | * }} Options 20 | */ 21 | 22 | /** 23 | * The Simplifyify API 24 | * 25 | * @param {string|string[]} globs - One or more file paths and/or glob patterns 26 | * @param {Options} [options] - Simplifyify CLI options 27 | * @returns {EventEmitter} 28 | */ 29 | function simplifyify (globs, options) { 30 | options = options || {}; 31 | 32 | let events = new EventEmitter(); 33 | simplifyifyAsync(globs, options, events); 34 | return events; 35 | } 36 | 37 | /** 38 | * Do everything asynchronously, even parameter validation. 39 | * 40 | * @param {string|string[]} globs - One or more file paths and/or glob patterns 41 | * @param {Options} options - Simplifyify CLI options 42 | * @param {EventEmitter} events - Emits Browserify events 43 | */ 44 | function simplifyifyAsync (globs, options, events) { 45 | Promise.resolve() 46 | .then(() => { 47 | // Validate the entry files 48 | if (!globs || globs.length === 0) { 49 | events.emit("error", new Error("No entry files were specified")); 50 | return; 51 | } 52 | 53 | if (!Array.isArray(globs)) { 54 | globs = [globs]; 55 | } 56 | 57 | // Expand the glob(s) into a list of entry files and output files 58 | return expandGlobs(globs, options); 59 | }) 60 | .then((fileSets) => { 61 | if (fileSets.length === 0) { 62 | events.emit("error", new Error("No matching entry files were found")); 63 | return; 64 | } 65 | 66 | for (let fileSet of fileSets) { 67 | // Do this synchronously, so that files like package.json, bundle.txt, etc. 68 | // are only read once, and cached versions are used for subsequent bundles 69 | writeBundles(fileSet, events, options); 70 | } 71 | }) 72 | .catch((error) => { 73 | events.emit("error", error); 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /lib/transforms/banner.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const path = require("path"); 4 | const cache = require("../fs-cache"); 5 | const banner = require("@jsdevtools/browserify-banner"); 6 | 7 | module.exports = applyBanner; 8 | 9 | /** 10 | * Adds the Banner transform to the given Browserify or Watchify instance. 11 | * 12 | * @param {Browserify} browserify - The Browserify or Watchify instance 13 | * @param {object} manifest - The project manifest (package.json file) 14 | * @param {object} [options] - The Banner options, if any 15 | */ 16 | function applyBanner (browserify, manifest, options) { 17 | options = options || {}; 18 | 19 | if (!options.pkg) { 20 | // Default to the project manifest 21 | options.pkg = manifest; 22 | } 23 | 24 | if (!options.file) { 25 | // If there's a "banner.txt" file, then use it as the banner template 26 | let bannerPath = path.join(path.dirname(browserify.files.entryFile), "banner.txt"); 27 | bannerPath = cache.findFile(bannerPath); 28 | if (bannerPath) { 29 | options.template = cache.readTextFile(bannerPath); 30 | } 31 | } 32 | 33 | if (options.file || options.template || options.banner) { 34 | browserify.plugin(banner, options); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/transforms/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const ono = require("@jsdevtools/ono"); 4 | const util = require("../util"); 5 | const cache = require("../fs-cache"); 6 | const applyTSify = require("./tsify"); 7 | const applyIstanbul = require("./istanbul"); 8 | const applyUglifyify = require("./uglifyify"); 9 | const applyBanner = require("./banner"); 10 | 11 | /** 12 | * Provides easy access to the Browserify transforms from the project manifest. 13 | */ 14 | class Transforms { 15 | /** 16 | * @param {string} startingDir - The directory to start searching for the manifest file 17 | */ 18 | constructor (startingDir) { 19 | /** 20 | * The entire project manifest 21 | * @type {object} 22 | */ 23 | this.manifest = readProjectManifest(startingDir); 24 | 25 | /** 26 | * The TSify (TypeScript) transform options 27 | * @type {object} 28 | */ 29 | this.tsify = getBrowserifyOptions(this.manifest, "plugins", "tsify"); 30 | 31 | /** 32 | * The Uglifyify transform options 33 | * @type {object} 34 | */ 35 | this.uglifyify = getBrowserifyOptions(this.manifest, "transform", "uglifyify"); 36 | 37 | /** 38 | * The Istanbul transform options 39 | * @type {object} 40 | */ 41 | this.istanbul = getBrowserifyOptions(this.manifest, "transform", "browserify-istanbul"); 42 | 43 | /** 44 | * The Banner transform options 45 | * @type {object} 46 | */ 47 | this.banner = getBrowserifyOptions(this.manifest, "plugins", "browserify-banner"); 48 | 49 | /** 50 | * All other Browserify transforms from the project manifest 51 | * @type {array} 52 | */ 53 | this.otherTransforms = omitBrowserifyOptions(this.manifest, "transform", [ 54 | "uglifyify", "browserify-istanbul"]); 55 | 56 | /** 57 | * All other Browserify plugins from the project manifest 58 | * @type {array} 59 | */ 60 | this.otherPlugins = omitBrowserifyOptions(this.manifest, "plugins", [ 61 | "tsify", "browserify-banner"]); 62 | } 63 | 64 | /** 65 | * Configures the given Browserify or Watchify instance to use these transforms. 66 | * 67 | * @param {Browserify} browserify - The Browserify or Watchify instance 68 | * @param {object} [options] 69 | * @param {boolean} [options.minify] - Whether to include the uglifyify transform 70 | * @param {boolean} [options.coverage] - Whether to include the istanbul transform 71 | */ 72 | apply (browserify, options) { 73 | try { 74 | options = options || {}; 75 | 76 | // Add any user-defined transforms first 77 | for (let [name, config] of this.otherTransforms) { 78 | browserify.transform(require(name), config); 79 | } 80 | 81 | // Then any user-defined plugins 82 | for (let [name, config] of this.otherPlugins) { 83 | browserify.transform(require(name), config); 84 | } 85 | 86 | // Transpile TypeScript 87 | if (options.typescript) { 88 | applyTSify(browserify, this.tsify); 89 | } 90 | 91 | // Then minify 92 | if (options.minify) { 93 | applyUglifyify(browserify, this.uglifyify); 94 | } 95 | 96 | // Add code-coverage AFTER uglifyify, so it doesn't get mangled 97 | if (options.coverage) { 98 | applyIstanbul(browserify, this.istanbul); 99 | } 100 | 101 | // Add the banner last 102 | applyBanner(browserify, this.manifest, this.banner); 103 | } 104 | catch (e) { 105 | throw ono(e, "Error adding Browserify transforms"); 106 | } 107 | } 108 | } 109 | 110 | /** 111 | * Reads the project manifest (package.json file) and returns 112 | * it as a normalized object. 113 | * 114 | * @param {string} manifestPath - The path of the manifest file 115 | */ 116 | function readProjectManifest (manifestPath) { 117 | // Find the manifest file by crawling up the directory tree 118 | manifestPath = cache.findFile(manifestPath); 119 | 120 | // Parse the manifest 121 | let manifest = {}; 122 | if (manifestPath) { 123 | manifest = cache.readJsonFile(manifestPath); 124 | } 125 | 126 | // Normalize the manifest 127 | manifest.browserify = manifest.browserify || {}; 128 | manifest.browserify.transform = manifest.browserify.transform || []; 129 | manifest.browserify.plugins = manifest.browserify.plugins || []; 130 | 131 | return manifest; 132 | } 133 | 134 | /** 135 | * Returns the specified transform's or plugin's options from the project manifest (package.json). 136 | * If no options are set, then undefined is returned. 137 | * 138 | * @param {object} manifest - The project manifest (package.json file) 139 | * @param {string} type - "transform" or "plugins" 140 | * @param {string} name - The name of the transform/plugin whose options are returned 141 | * @returns {object|undefined} 142 | */ 143 | function getBrowserifyOptions (manifest, type, name) { 144 | for (let tuple of manifest.browserify[type]) { 145 | if (Array.isArray(tuple)) { 146 | let [_name, config] = tuple; 147 | 148 | if (_name === name) { 149 | return util.deepClone(config); 150 | } 151 | } 152 | } 153 | } 154 | 155 | /** 156 | * Returns all Browserify transform/plugin options, except the omitted ones 157 | * 158 | * @param {object} manifest - The project manifest (package.json file) 159 | * @param {string} type - "transform" or "plugins" 160 | * @param {string[]} omit - The names of the transforms to omit 161 | * @returns {array} 162 | */ 163 | function omitBrowserifyOptions (manifest, type, omit) { 164 | let included = []; 165 | 166 | for (let tuple of manifest.browserify[type]) { 167 | let name, config; 168 | 169 | // Each transform can be a string (just the transform name) 170 | // or an array (the transform name and its options) 171 | if (Array.isArray(tuple)) { 172 | [name, config] = tuple; 173 | } 174 | else { 175 | name = tuple; 176 | config = undefined; 177 | } 178 | 179 | // Add the transform, unless it's one of the omitted ones 180 | if (!omit.includes(name)) { 181 | included.push([name, config]); 182 | } 183 | } 184 | 185 | return included; 186 | } 187 | 188 | module.exports = Transforms; 189 | -------------------------------------------------------------------------------- /lib/transforms/istanbul.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const istanbul = require("browserify-istanbul"); 4 | 5 | module.exports = applyIstanbul; 6 | 7 | /** 8 | * Adds the Istanbul transform to the given Browserify or Watchify instance. 9 | * 10 | * @param {Browserify} browserify - The Browserify or Watchify instance 11 | * @param {object} [options] - The Istanbul options, if any 12 | */ 13 | function applyIstanbul (browserify, options) { 14 | options = options || { 15 | // Replace Istanbul's default "ignore" list with our own 16 | defaultIgnore: false, 17 | ignore: [ 18 | "**/node_modules/**", "**/bower_components/**", 19 | "**/*.json", "**/*.html", "**/*.md", "**/*.txt" 20 | ], 21 | }; 22 | 23 | browserify.transform(istanbul(options)); 24 | } 25 | -------------------------------------------------------------------------------- /lib/transforms/tsify.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const path = require("path"); 4 | const cache = require("../fs-cache"); 5 | const tsify = require("tsify"); 6 | 7 | module.exports = applyTSify; 8 | 9 | /** 10 | * Adds the TSify plugin to the given Browserify or Watchify instance. 11 | * 12 | * @param {Browserify} browserify - The Browserify or Watchify instance 13 | * @param {object} [options] - The TSify options, if any 14 | */ 15 | function applyTSify (browserify, options) { 16 | if (!options) { 17 | // No TypeScript options were set in package.json, so look for a tsconfig.json file 18 | let tsConfigPath = path.join(path.dirname(browserify.files.entryFile), "tsconfig.json"); 19 | tsConfigPath = cache.findFile(tsConfigPath); 20 | 21 | if (tsConfigPath) { 22 | // Configure TSify to use the tsconfig.json file 23 | options = { project: tsConfigPath }; 24 | } 25 | else { 26 | // Configure TSify with default options 27 | options = { 28 | project: { 29 | compilerOptions: { 30 | target: "esnext", 31 | module: "commonjs", 32 | moduleResolution: "node", 33 | resolveJsonModule: true, 34 | esModuleInterop: true, 35 | jsx: "react", 36 | }, 37 | 38 | // An empty files array causes TSify to use the Browserify entry file(s) 39 | files: [], 40 | 41 | // Don't transpile stuff in node_modules 42 | exclude: [ 43 | "node_modules" 44 | ], 45 | }, 46 | }; 47 | } 48 | } 49 | 50 | browserify.plugin(tsify, options); 51 | } 52 | -------------------------------------------------------------------------------- /lib/transforms/uglifyify.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const path = require("path"); 4 | const uglify = require("uglify-es"); 5 | const uglifyify = require("uglifyify"); 6 | const util = require("../util"); 7 | 8 | module.exports = applyUglifyify; 9 | 10 | /** 11 | * Adds the Uglifyify transform to the given Browserify or Watchify instance. 12 | * 13 | * Minification is done in two phases, both using UglifyJS: 14 | * 15 | * PHASE 1 - The first phase occurs as a Browserify transform, which minifies each module 16 | * individually. This allows Uglify to eliminate dead code paths within each module. 17 | * 18 | * PHASE 2 - The second phase occurs after Browserify is finished, and minifies the entire 19 | * bundle file. This allows Uglify to achieve the smallest possible file size. 20 | * 21 | * @param {Browserify} browserify - The Browserify or Watchify instance 22 | * @param {object} [options] - The Uglifyify options, if any 23 | */ 24 | function applyUglifyify (browserify, options) { 25 | options = options || {}; 26 | let hasSourcemap = !!browserify.files.mapFile; 27 | let bundlePath = path.resolve(browserify.files.outputFile); 28 | let sourcemapPath = hasSourcemap && path.resolve(browserify.files.mapFile); 29 | 30 | if (options.global === undefined) { 31 | // Apply uglifyify to ALL modules in the bundle, even third-party ones 32 | options.global = true; 33 | } 34 | 35 | if (options.exts === undefined) { 36 | // Apply uglifyify to all JavaScript, JSON, or TypeScript files 37 | options.exts = [".js", ".json", ".es6", ".esm", ".jsm", ".jsx", ".ts", ".tsx"]; 38 | } 39 | 40 | if (options.output === undefined) { 41 | options.output = { 42 | // Keep important comments when minifying 43 | comments: /^!|^\*!|@preserve|@license|@cc_on/, 44 | }; 45 | } 46 | 47 | // PHASE 1 - Minify each module individually 48 | browserify.transform(uglifyify, util.deepClone(options)); 49 | 50 | // PHASE 2 - Minify the entire bundle file 51 | browserify.postProcessing = function () { 52 | return Promise.all( 53 | [ 54 | util.readFile(bundlePath), 55 | hasSourcemap && util.readFile(sourcemapPath), 56 | ]) 57 | .then(phase2) 58 | .then(overwriteBundle) 59 | .then(overwriteSourcemap); 60 | }; 61 | 62 | // Minify the entire bundle using UglifyJS 63 | function phase2 (code) { 64 | return Promise.resolve() 65 | .then(() => { 66 | let bundleCode = code[0]; 67 | let sourcemapCode = code[1]; 68 | 69 | // For PHASE 2, we don't need to perform additional mangling, compressing, 70 | // comment-removal, etc., since that has already been done in PHASE 1 71 | options = { 72 | mangle: false, 73 | compress: false, 74 | output: Object.assign({}, options.output, { 75 | comments: true, 76 | }), 77 | }; 78 | 79 | // If the bundle has a sourcemap, then UglifyJS needs to modify it 80 | if (hasSourcemap) { 81 | options.sourceMap = { 82 | content: sourcemapCode, 83 | url: path.basename(sourcemapPath), 84 | filename: path.basename(bundlePath), 85 | }; 86 | } 87 | 88 | let minified = uglify.minify(bundleCode, options); 89 | 90 | if (minified.error) { 91 | throw minified.error; 92 | } 93 | else { 94 | return minified; 95 | } 96 | }); 97 | } 98 | 99 | // Overwrite the bundle file from PHASE 1 100 | function overwriteBundle (minified) { 101 | return util.writeFile(bundlePath, minified.code) 102 | .then(() => minified); 103 | } 104 | 105 | // Overwrite the sourcemap file from PHASE 1 106 | function overwriteSourcemap (minified) { 107 | if (hasSourcemap) { 108 | // Parse the sourcemap so we format it using JSON.stringify() 109 | let map = JSON.parse(minified.map); 110 | 111 | return util.writeFile(sourcemapPath, JSON.stringify(map, null, 2)); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const mkdirp = require("mkdirp-promise"); 4 | const path = require("path"); 5 | const fs = require("fs"); 6 | 7 | module.exports = { 8 | ensureFileExists, 9 | touchFile, 10 | statFile, 11 | readFile, 12 | writeFile, 13 | deleteFile, 14 | appendToFileName, 15 | isTypeScript, 16 | deepClone, 17 | }; 18 | 19 | /** 20 | * Ensures that the given file path exists, since Browserify throws errors if they don't. 21 | * 22 | * @param {string} file - The absolute file path 23 | * @returns {Promise} 24 | */ 25 | function ensureFileExists (file) { 26 | return Promise.resolve() 27 | .then(() => { 28 | // Try to access the file 29 | return statFile(file); 30 | }) 31 | .catch((error) => { 32 | if (error.code === "ENOENT") { 33 | // The file doesn't exist, so create it 34 | return touchFile(file); 35 | } 36 | else { 37 | throw error; 38 | } 39 | }); 40 | } 41 | 42 | /** 43 | * Asynchronously adds a newline to the end of a file, to trigger any file-modification watchers 44 | * 45 | * @param {string} file - The absolute file path 46 | * @returns {Promise} - Resolves with an fs.Stats object 47 | */ 48 | function touchFile (file) { 49 | return new Promise((resolve, reject) => { 50 | fs.appendFile(file, "\n", (err, stats) => { 51 | if (err) { 52 | if (err.code === "ENOENT") { 53 | mkdirp(path.dirname(file)) 54 | .then(() => { 55 | return touchFile(file); 56 | }) 57 | .then((stats2) => { 58 | resolve(stats2); 59 | }); 60 | } 61 | else { 62 | reject(err); 63 | } 64 | } 65 | else { 66 | resolve(stats); 67 | } 68 | }); 69 | }); 70 | } 71 | 72 | /** 73 | * Asynchronously gets the status of a file 74 | * 75 | * @param {string} file - The absolute file path 76 | * @returns {Promise} - Resolves with an fs.Stats object 77 | */ 78 | function statFile (file) { 79 | return new Promise((resolve, reject) => { 80 | fs.stat(file, (err, stats) => { 81 | if (err) { 82 | reject(err); 83 | } 84 | else { 85 | resolve(stats); 86 | } 87 | }); 88 | }); 89 | } 90 | 91 | /** 92 | * Asynchronously reads the contents of a file 93 | * 94 | * @param {string} file - The absolute file path 95 | * @returns {Promise} - Resolves with the contents of the file, as a UTF8 string 96 | */ 97 | function readFile (file) { 98 | return new Promise((resolve, reject) => { 99 | fs.readFile(file, { encoding: "utf8" }, (err, data) => { 100 | if (err) { 101 | reject(err); 102 | } 103 | else { 104 | resolve(data); 105 | } 106 | }); 107 | }); 108 | } 109 | 110 | /** 111 | * Asynchronously writes the given data to the specified file. 112 | * The file and any parent directories are created if necessary. 113 | * 114 | * @param {string} file - The absolute file path 115 | * @param {string} data - The data to write to the file 116 | * @returns {Promise} - Resolves after the file has been written 117 | */ 118 | function writeFile (file, data) { 119 | return new Promise((resolve, reject) => { 120 | fs.writeFile(file, data, (err) => { 121 | if (err) { 122 | reject(err); 123 | } 124 | else { 125 | resolve(); 126 | } 127 | }); 128 | }); 129 | } 130 | 131 | /** 132 | * Asynchronously deletes a file 133 | * 134 | * @param {string} file - The absolute file path 135 | * @returns {Promise} - Resolves when the file has been deleted 136 | */ 137 | function deleteFile (file) { 138 | return new Promise((resolve, reject) => { 139 | fs.unlink(file, (err) => { 140 | if (err) { 141 | reject(err); 142 | } 143 | else { 144 | resolve(); 145 | } 146 | }); 147 | }); 148 | } 149 | 150 | /** 151 | * Appends the given string to the given file name, without affecting the file extension. 152 | * 153 | * @param {string} file - The original file path and/or name (e.g. "dest/subdir/my-file.js") 154 | * @param {string} append - The string to append to the file name (e.g. ".min") 155 | * @returns {string} 156 | */ 157 | function appendToFileName (file, append) { 158 | let ext = path.extname(file); 159 | return file.substr(0, file.length - ext.length) + append + ext; 160 | } 161 | 162 | /** 163 | * Determines whether the specified file has a ".ts" or ".tsx" extension 164 | */ 165 | function isTypeScript (file) { 166 | let ext = path.extname(file).toLowerCase(); 167 | return ext === ".ts" || ext === ".tsx"; 168 | } 169 | 170 | /** 171 | * A simple recursive cloning function for simple JavaScript values. 172 | * 173 | * @param {*} original 174 | * @returns {*} 175 | */ 176 | function deepClone (original) { 177 | let clone; 178 | 179 | if (original) { 180 | if (typeof original === "object") { 181 | if (original instanceof RegExp) { 182 | return original; 183 | } 184 | else if (original instanceof Date) { 185 | return new Date(original.getTime()); 186 | } 187 | else if (Array.isArray(original)) { 188 | clone = []; 189 | } 190 | else { 191 | clone = {}; 192 | } 193 | } 194 | else { 195 | return original; 196 | } 197 | } 198 | else { 199 | return original; 200 | } 201 | 202 | let keys = Object.keys(original); 203 | for (let i = 0; i < keys.length; i++) { 204 | let key = keys[i]; 205 | let value = original[key]; 206 | 207 | clone[key] = deepClone(value); 208 | } 209 | 210 | return clone; 211 | } 212 | -------------------------------------------------------------------------------- /lib/write-bundles.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Browserify = require("browserify"); 4 | const watchify = require("watchify"); 5 | const exorcist = require("exorcist"); 6 | const fs = require("fs"); 7 | const path = require("path"); 8 | const FileSet = require("./file-set"); 9 | const Transforms = require("./transforms"); 10 | const util = require("./util"); 11 | 12 | module.exports = writeBundles; 13 | 14 | /** 15 | * Writes Browserify bundles for the given entry file. 16 | * At least one bundle is created (the outputFile), but additional ones may be 17 | * created, depending on {@link Options.debug}, {@link Options.minify}, and {@link Options.coverage}. 18 | * 19 | * @param {FileSet} mainFiles - The main input & output files (not the minified or coverage files) 20 | * @param {EventEmitter} events - Browserify events will be propagated to this EventEmitter 21 | * @param {Options} options - Bundling options 22 | */ 23 | function writeBundles (mainFiles, events, options) { 24 | let bundles = []; 25 | 26 | // Read the Browserify transforms from the project manifest (package.json file) 27 | let manifestPath = path.join(path.dirname(mainFiles.entryFile), "package.json"); 28 | let transforms = new Transforms(manifestPath); 29 | 30 | // Determine whether to enable TypeScript 31 | options.typescript = transforms.tsify || util.isTypeScript(mainFiles.entryFile); 32 | 33 | // If no output options are specified, then default to --bundle 34 | if (!options.bundle && !options.minify && !options.coverage) { 35 | options.bundle = true; 36 | } 37 | 38 | if (options.bundle) { 39 | bundles.push(createMainBundle(mainFiles, transforms, events, options)); 40 | } 41 | 42 | if (options.minify) { 43 | bundles.push(createMinifiedBundle(mainFiles, transforms, events, options)); 44 | } 45 | 46 | if (options.coverage) { 47 | bundles.push(createCoverageBundle(mainFiles, transforms, events, options)); 48 | } 49 | 50 | /** 51 | * Build each bundle one-at-a-time, rather than all of them simultaneously. 52 | * This dramatically lowers the total build time, especially on large apps. 53 | * 54 | * @param {number} index - The bundle to build (from the {@link bundles} array) 55 | **/ 56 | function writeBundle (index) { 57 | if (bundles[index]) { 58 | // Write this bundle 59 | bundle(bundles[index]); 60 | 61 | // Write the next bundle when this one finishes 62 | bundles[index].once("end", () => { 63 | writeBundle(index + 1); 64 | }); 65 | } 66 | } 67 | 68 | writeBundle(0); 69 | } 70 | 71 | /** 72 | * Returns a Browserify instance that outputs the main (non-minified) bundle for the given entry file. 73 | * 74 | * @param {FileSet} mainFiles - The input & output files 75 | * @param {Transforms} transforms - The Browserify transforms, and their options 76 | * @param {EventEmitter} events - Browserify events will be propagated to this EventEmitter 77 | * @param {Options} options - Bundling options 78 | * @returns {Browserify} 79 | */ 80 | function createMainBundle (mainFiles, transforms, events, options) { 81 | let browserify = newify(mainFiles, transforms, events, options); 82 | transforms.apply(browserify, { typescript: options.typescript }); 83 | return browserify; 84 | } 85 | 86 | /** 87 | * Returns a Browserify instance that outputs the minified bundle for the given entry file. 88 | * 89 | * @param {FileSet} mainFiles - The input & output files 90 | * @param {Transforms} transforms - The Browserify transforms, and their options 91 | * @param {EventEmitter} events - Browserify events will be propagated to this EventEmitter 92 | * @param {Options} options - Bundling options 93 | * @returns {Browserify} 94 | */ 95 | function createMinifiedBundle (mainFiles, transforms, events, options) { 96 | let minifiedFiles = new FileSet(); 97 | 98 | if (options.bundle || options.coverage) { 99 | // We're creating multiple output files, so append ".min" to the minified file 100 | minifiedFiles.entryFile = mainFiles.entryFile; 101 | minifiedFiles.outputFile = util.appendToFileName(mainFiles.outputFile, ".min"); 102 | minifiedFiles.standalone = mainFiles.standalone; 103 | if (options.debug) { 104 | minifiedFiles.mapFile = minifiedFiles.outputFile + ".map"; 105 | } 106 | } 107 | else { 108 | // We're ONLY creating a minified file, so this is the main output file 109 | minifiedFiles = mainFiles; 110 | } 111 | 112 | let browserify = newify(minifiedFiles, transforms, events, options); 113 | transforms.apply(browserify, { minify: true, typescript: options.typescript }); 114 | return browserify; 115 | } 116 | 117 | /** 118 | * Returns a Browserify instance that outputs the code-coverage bundle for the given entry file. 119 | * 120 | * @param {FileSet} mainFiles - The input & output files 121 | * @param {Transforms} transforms - The Browserify transforms, and their options 122 | * @param {EventEmitter} events - Browserify events will be propagated to this EventEmitter 123 | * @param {Options} options - Bundling options 124 | * @returns {Browserify} 125 | */ 126 | function createCoverageBundle (mainFiles, transforms, events, options) { 127 | let coverageFiles = new FileSet(); 128 | 129 | if (options.bundle || options.minify) { 130 | // We're creating multiple output files, so append ".coverage" to the code-coverage file 131 | coverageFiles.entryFile = mainFiles.entryFile; 132 | coverageFiles.outputFile = util.appendToFileName(mainFiles.outputFile, ".coverage"); 133 | coverageFiles.standalone = mainFiles.standalone; 134 | } 135 | else { 136 | // We're ONLY creating a code-coverage file, so this is the main output file 137 | coverageFiles = mainFiles; 138 | 139 | // Don't produce source maps for code-coverage files (Istanbul doesn't support source maps) 140 | coverageFiles.mapFile = ""; 141 | } 142 | 143 | let browserify = newify(coverageFiles, transforms, events, options); 144 | transforms.apply(browserify, { minify: true, coverage: true, typescript: options.typescript }); 145 | return browserify; 146 | } 147 | 148 | /** 149 | * Creates a new Browserify or Watchify instance 150 | * 151 | * @param {FileSet} fileSet - The input & output files for this bundle 152 | * @param {Transforms} transforms - The Browserify transforms, and their options 153 | * @param {EventEmitter} events - Browserify events will be propagated to this EventEmitter 154 | * @param {Options} options - Bundling options 155 | * @returns {Browserify} 156 | */ 157 | function newify (fileSet, transforms, events, options) { 158 | // We always set these options 159 | let browserifyOptions = { 160 | entries: fileSet.entryFile, 161 | standalone: fileSet.standalone || undefined, 162 | debug: !!fileSet.mapFile, 163 | }; 164 | 165 | // These options are only needed for Watchify 166 | if (options.watch) { 167 | browserifyOptions.cache = {}; 168 | browserifyOptions.packageCache = {}; 169 | } 170 | 171 | // Create the Browserify instance 172 | let browserify = new Browserify(browserifyOptions); 173 | 174 | // Propagate events 175 | browserify.on("error", err => { 176 | events.emit("error", err, fileSet); 177 | }); 178 | browserify.on("end", () => { 179 | events.emit("end", fileSet); 180 | }); 181 | browserify.on("log", msg => { 182 | events.emit("log", msg, fileSet); 183 | }); 184 | browserify.on("update", file => { 185 | events.emit("update", file.toString(), fileSet); 186 | }); 187 | 188 | if (options.watch) { 189 | // Enable Watchify 190 | browserify = watchify(browserify); 191 | 192 | // Re-bundle when a file changes 193 | browserify.on("update", () => { 194 | bundle(browserify); 195 | }); 196 | } 197 | 198 | // Remember the input/output files for this browserify 199 | browserify.files = fileSet; 200 | 201 | // Some transforms (e.g. uglifyify) require post-processing of the bundle file 202 | browserify.postProcessing = () => Promise.resolve(); 203 | 204 | return browserify; 205 | } 206 | 207 | /** 208 | * Writes the output file (and possibly its .map file) for the given Browserify object 209 | * 210 | * @param {Browserify} browserify - The Browserify or Watchify instance to bundle 211 | */ 212 | function bundle (browserify) { 213 | let stream = browserify.bundle(); 214 | stream.on("error", browserify.emit.bind(browserify, "error")); 215 | 216 | Promise.resolve() 217 | .then(() => { 218 | if (browserify.files.mapFile) { 219 | // Create the map file, if necessary, since Exorcist expects it to already exist 220 | return util.ensureFileExists(browserify.files.mapFile); 221 | } 222 | }) 223 | .then(() => { 224 | if (browserify.files.mapFile) { 225 | // Add Exorcist to the pipeline, to extract the sourcemap to a separate file 226 | let dirname = path.dirname(browserify.files.mapFile); 227 | stream = stream.pipe(exorcist(browserify.files.mapFile, null, null, dirname)); 228 | } 229 | 230 | // Create the output file, if necessary, since Browserify expects it to already exist 231 | return util.ensureFileExists(browserify.files.outputFile); 232 | }) 233 | .then(() => { 234 | // Pipe the Browserify output to the output file 235 | stream.pipe(fs.createWriteStream(browserify.files.outputFile)); 236 | }) 237 | .then(() => { 238 | return new Promise((resolve) => stream.on("end", resolve)); 239 | }) 240 | .then(() => { 241 | // The "end" event sometimes gets called before the file(s) have 242 | // been fully-written to disk. So we wait a bit to allow I/O to finish. 243 | return new Promise((resolve) => setTimeout(resolve, 100)); 244 | }) 245 | .then(() => { 246 | // Perform any post-processing on the output file(s), such as minification 247 | return browserify.postProcessing(); 248 | }) 249 | .then(() => { 250 | browserify.emit("end"); 251 | }) 252 | .catch(e => { 253 | browserify.emit("error", e); 254 | }); 255 | } 256 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jsdevtools/simplifyify", 3 | "version": "8.0.4", 4 | "description": "A simplified Browserify and Watchify CLI", 5 | "keywords": [ 6 | "browserify", 7 | "browserify-plugin", 8 | "watchify", 9 | "cli", 10 | "minify", 11 | "uglify", 12 | "uglifyify", 13 | "sourcemap", 14 | "source-map", 15 | "source map", 16 | "exorcist", 17 | "istanbul" 18 | ], 19 | "author": { 20 | "name": "James Messinger", 21 | "url": "https://jamesmessinger.com" 22 | }, 23 | "homepage": "https://jstools.dev/simplifyify", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/JS-DevTools/simplifyify.git" 27 | }, 28 | "license": "MIT", 29 | "main": "lib/index.js", 30 | "bin": { 31 | "simplifyify": "bin/simplifyify.js" 32 | }, 33 | "files": [ 34 | "bin", 35 | "lib" 36 | ], 37 | "engines": { 38 | "node": ">=10" 39 | }, 40 | "scripts": { 41 | "clean": "shx rm -rf .nyc_output coverage", 42 | "lint": "eslint bin lib test/fixtures test/specs", 43 | "test": "mocha && npm run lint", 44 | "coverage": "nyc node_modules/mocha/bin/mocha", 45 | "upgrade": "npm-check -u && npm audit fix", 46 | "bump": "bump --tag --push --all", 47 | "release": "npm run upgrade && npm run clean && npm test && npm run bump" 48 | }, 49 | "dependencies": { 50 | "@jsdevtools/browserify-banner": "^2.0.4", 51 | "@jsdevtools/ono": "^7.1.3", 52 | "browserify": "^17.0.0", 53 | "browserify-istanbul": "^3.0.1", 54 | "commander": "^6.2.1", 55 | "exorcist": "^1.0.0", 56 | "globby": "^11.0.1", 57 | "mkdirp-promise": "^5.0.1", 58 | "shx": "^0.3.3", 59 | "tsify": "^5.0.2", 60 | "uglify-es": "^3.3.7", 61 | "uglifyify": "^5.0.2", 62 | "watchify": "^3.11.1" 63 | }, 64 | "devDependencies": { 65 | "@babel/core": "^7.12.10", 66 | "@babel/preset-env": "^7.12.11", 67 | "@jsdevtools/eslint-config": "^1.1.4", 68 | "@jsdevtools/host-environment": "^2.1.2", 69 | "@jsdevtools/version-bump-prompt": "^6.1.0", 70 | "@types/react": "^17.0.0", 71 | "@types/react-dom": "^17.0.0", 72 | "babelify": "^10.0.0", 73 | "chai": "^4.2.0", 74 | "eslint": "^7.17.0", 75 | "mocha": "^8.2.1", 76 | "npm-check": "^5.9.2", 77 | "nyc": "^15.1.0", 78 | "react": "^17.0.1", 79 | "react-dom": "^17.0.1", 80 | "rmfr": "^2.0.0", 81 | "typescript": "^4.1.3" 82 | }, 83 | "peerDependencies": { 84 | "typescript": "*" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/fixtures/assert.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | const ono = require("@jsdevtools/ono"); 6 | const expect = require("chai").expect; 7 | const isWindows = /^win/.test(process.platform); 8 | const testAppsDir = path.resolve(__dirname, "../test-apps"); 9 | 10 | /** 11 | * Asserts that the given folder is empty. 12 | * 13 | * @param {string} dir - The directory to check 14 | */ 15 | exports.directoryIsEmpty = function (dir) { 16 | let outfiles = ls(dir); 17 | try { 18 | expect(outfiles).to.have.same.members([]); 19 | } 20 | catch (e) { 21 | console.error("Directory is not empty!\nExpected: []\n\nActual: %s", JSON.stringify(outfiles, null, 2)); 22 | throw e; 23 | } 24 | }; 25 | 26 | /** 27 | * Asserts that the directory contains the given files, and no others. 28 | * 29 | * @param {string} [dir] - The directory to check 30 | * @param {string[]} files - The files to check for 31 | */ 32 | exports.directoryContents = function (dir, files) { 33 | if (arguments.length === 1) { 34 | dir = "."; 35 | files = dir; 36 | } 37 | files = Array.isArray(files) ? files : [files]; 38 | 39 | let outfiles = ls(dir); 40 | try { 41 | expect(outfiles).to.have.same.members(files); 42 | } 43 | catch (e) { 44 | console.error("Incorrect directory contents!\nExpected: %s\n\nActual: %s", 45 | JSON.stringify(files, null, 2), JSON.stringify(outfiles, null, 2)); 46 | throw e; 47 | } 48 | }; 49 | 50 | /** 51 | * Calls the given function for the given file(s), passing the contents of the file. 52 | * 53 | * @param {string} [dir] 54 | * @param {string|string[]} files 55 | * @param {function} fn 56 | */ 57 | exports.fileContents = function (dir, files, fn) { 58 | if (typeof files === "function") { 59 | fn = files; 60 | files = dir; 61 | dir = "."; 62 | } 63 | dir = resolve(dir); 64 | files = Array.isArray(files) ? files : [files]; 65 | 66 | for (let file of files) { 67 | let fullPath = path.join(dir, file); 68 | let contents = fs.readFileSync(fullPath).toString(); 69 | 70 | if (file.substr(-4) === ".map") { 71 | // Parse source-map files, and return a POJO instead of a string 72 | contents = JSON.parse(contents); 73 | 74 | if (isWindows) { 75 | // Replace Windows path separators with POSIX separators 76 | contents.sources = contents.sources.map((source) => { 77 | return source.replace(/\\/g, "/"); 78 | }); 79 | } 80 | } 81 | 82 | try { 83 | fn(contents); 84 | } 85 | catch (e) { 86 | throw ono(e, file, "failed an assertion:"); 87 | } 88 | } 89 | }; 90 | 91 | /** 92 | * Asserts that the given file contents start with a banner 93 | * 94 | * @param {string} contents 95 | */ 96 | exports.hasBanner = function (contents) { 97 | expect(contents).to.match(/^\/\*\!\n \* /, "The file does not start with a banner"); 98 | }; 99 | 100 | /** 101 | * Asserts that the given file contents do not contain a banner 102 | * 103 | * @param {string} contents 104 | */ 105 | exports.noBanner = function (contents) { 106 | expect(contents).not.to.match(/^\/\*\!/, "The file contains a banner, but it shouldn't"); 107 | }; 108 | 109 | /** 110 | * Asserts that the given file contents contain the Browserify preamble (non-UMD) 111 | * 112 | * @param {string} contents 113 | */ 114 | exports.hasPreamble = function (contents) { 115 | expect(contents).to.match( 116 | /var \w\s*=\s*["']function["']\s*==\s*typeof require\s*\&\&\s*require;/, 117 | "The file is missing the Browserify preamble (non-UMD)" 118 | ); 119 | }; 120 | 121 | /** 122 | * Asserts that the given file contents contain the minified version of the 123 | * Browserify preamble (non-UMD) 124 | * 125 | * @param {string} contents 126 | */ 127 | exports.hasMinifiedPreamble = function (contents) { 128 | expect(contents).to.match( 129 | /var \w="function"==typeof require\&\&*require;/, 130 | "The file is missing the Browserify preamble (minified, non-UMD)" 131 | ); 132 | }; 133 | 134 | /** 135 | * Asserts that the given file contents contain the Browserify UMD preamble 136 | * 137 | * @param {string} contents 138 | */ 139 | exports.hasUmdPreamble = function (contents) { 140 | let msg = "The file is missing the Browserify preamble (UMD)"; 141 | expect(contents).to.match(/if\(typeof window!=="undefined"\)/, msg); 142 | expect(contents).to.match(/if\(typeof global!=="undefined"\)/, msg); 143 | expect(contents).to.match(/if\(typeof self!=="undefined"\)/, msg); 144 | }; 145 | 146 | /** 147 | * Asserts that the given file contents contain the minified version of the 148 | * Browserify UMD preamble 149 | * 150 | * @param {string} contents 151 | */ 152 | exports.hasMinifiedUmdPreamble = function (contents) { 153 | let msg = "The file is missing the Browserify preamble (minified, UMD)"; 154 | expect(contents).to.match(/if\(typeof window!=="undefined"\)/, msg); 155 | expect(contents).to.match(/if\(typeof global!=="undefined"\)/, msg); 156 | expect(contents).to.match(/if\(typeof self!=="undefined"\)/, msg); 157 | }; 158 | 159 | /** 160 | * Asserts that the given file contents contain an external source map 161 | * 162 | * @param {string} contents 163 | */ 164 | exports.hasSourceMap = function (contents) { 165 | expect(contents).to.match( 166 | /\/\/\# sourceMappingURL=.*\.map\n?$/, 167 | "The file does not end with a sourcemap comment" 168 | ); 169 | }; 170 | 171 | /** 172 | * Asserts that the given file contents DO NOT contain a source map 173 | * 174 | * @param {string} contents 175 | */ 176 | exports.noSourceMap = function (contents) { 177 | expect(contents).not.to.match(/\/\/\# sourceMap/, "The file has a sourcemap, but it shouldn't"); 178 | }; 179 | 180 | /** 181 | * Asserts that the given file contents are minified 182 | * 183 | * @param {string} contents 184 | * @param {boolean} stripComments - Whether the contents should include comments or not 185 | * @param {boolean} beautified - Whether the code has been beautified 186 | */ 187 | exports.isMinified = function (contents, stripComments, beautified) { 188 | if (beautified) { 189 | // Single-quotes and newlines 190 | expect(contents).to.match(/'use strict';\n/, "The file is not minified + beautified"); 191 | } 192 | else { 193 | // Single-quotes become double-quotes, and newline is removed 194 | expect(contents).to.match(/"use strict";\S+/, "The file is not minified"); 195 | } 196 | 197 | if (stripComments) { 198 | // All comments are removed 199 | expect(contents).not.to.match(/\/\/ /, "The file has comments, but shouldn't"); 200 | } 201 | else { 202 | // Non-important comments are removed 203 | expect(contents).not.to.match(/\* @param \{string\}/, "The file contains non-important comments (@param)"); 204 | expect(contents).not.to.match(/\/\/ This is NOT an important comment/, "The file contains non-important inline comments"); 205 | 206 | // Important comments are preserved 207 | expect(contents).to.match(/This is an important comment/, "The file does not contain important comments"); 208 | } 209 | }; 210 | 211 | /** 212 | * Asserts that the given file contents ARE NOT minified 213 | * 214 | * @param {string} contents 215 | */ 216 | exports.notMinified = function (contents) { 217 | // Newlines are preserved 218 | expect(contents).to.match(/['"]use strict['"];\r?\n(\s+|\w+)/, "The file has been minified (newlines were removed)"); 219 | 220 | // Non-important comments are preserved 221 | expect(contents).to.match(/\* @param \{string\}/, "Comments have been removed from the file (@param)"); 222 | expect(contents).to.match(/\/\/ This is NOT an important comment/, "Inline comments have been removed from the file"); 223 | 224 | // Important comments are also preserved 225 | expect(contents).to.match(/This is an important comment/, "Important comments have been removed from the file"); 226 | }; 227 | 228 | /** 229 | * Asserts that the given file contents have been transformed by Babelify 230 | * 231 | * @param {string} contents 232 | */ 233 | exports.isBabelified = function (contents) { 234 | expect(contents).to.match(/Object\.defineProperty\(exports,\s*['"]__esModule['"]/, "The file has not been Babelifieid, but it should have been"); 235 | }; 236 | 237 | /** 238 | * Asserts that the given file contents contain code-coverage instrumentation 239 | * 240 | * @param {string} contents 241 | */ 242 | exports.hasCoverage = function (contents) { 243 | // Check for __cov_ wrappers 244 | expect(contents).to.match(/__coverage__/, "The file is missing code-coverage instrumentation"); 245 | }; 246 | 247 | /** 248 | * Asserts that the given file contents DO NOT contain code-coverage instrumentation 249 | * 250 | * @param {string} contents 251 | */ 252 | exports.noCoverage = function (contents) { 253 | expect(contents).not.to.match(/__coverage__/, "The file contains code-coverage instrumentation, but shouldn't"); 254 | }; 255 | 256 | /** 257 | * Resolves a path, relative to the "test-apps" folder 258 | */ 259 | function resolve (fileOrFolder) { 260 | if (path.isAbsolute(fileOrFolder)) { 261 | return fileOrFolder; 262 | } 263 | else { 264 | return path.resolve(testAppsDir, fileOrFolder); 265 | } 266 | } 267 | 268 | /** 269 | * Returns the contents of the given directory. 270 | * 271 | * @param {string} [dir] - The directory to list 272 | */ 273 | function ls (dir) { 274 | try { 275 | let contents = []; 276 | dir = resolve(dir); 277 | 278 | let names = fs.readdirSync(dir); 279 | 280 | for (let name of names) { 281 | let fullName = path.join(dir, name); 282 | if (fs.statSync(fullName).isDirectory()) { 283 | let childNames = ls(fullName); 284 | 285 | for (let childName of childNames) { 286 | contents.push(name + "/" + childName); // Don't use path.join() here, because of Windows 287 | } 288 | } 289 | else if (![".DS_Store", "Thumbs.db"].includes(name)) { 290 | contents.push(name); 291 | } 292 | } 293 | 294 | return contents; 295 | } 296 | catch (e) { 297 | if (e.code === "ENOENT") { 298 | // The directory doesn't exist, so return an empty list 299 | return []; 300 | } 301 | throw e; 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /test/fixtures/cli.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const spawn = require("child_process").spawn; 4 | const globby = require("globby"); 5 | const rmfr = require("rmfr"); 6 | const path = require("path"); 7 | const isWindows = /^win/.test(process.platform); 8 | const cliPath = path.resolve(__dirname, "../../bin/simplifyify"); 9 | const testAppsDir = path.resolve(__dirname, "../test-apps"); 10 | const mocha = require("./mocha"); 11 | const util = require("../../lib/util"); 12 | 13 | beforeEach("Delete previous test files", function () { 14 | // Allow plenty of time for files to be deleted. This is especially important on Windows, 15 | // where "rmfr" often has to retry several times due to file locks 16 | mocha.increaseTimeout(this, 10000); 17 | 18 | // Clear the output files before each test 19 | return Promise.resolve() 20 | .then(() => { 21 | return globby("test/test-apps/*/dist", { onlyDirectories: true }); 22 | }) 23 | .then(distDirs => { 24 | return Promise.all(distDirs.map(dir => rmfr(dir, { maxBusyTries: 10 }))); 25 | }) 26 | .then(() => { 27 | return globby("test/test-apps/**/*.bundle.*", { onlyFiles: true }); 28 | }) 29 | .then(bundleFiles => { 30 | return Promise.all(bundleFiles.map(file => util.deleteFile(file))); 31 | }) 32 | .then(() => undefined); 33 | }); 34 | 35 | /** 36 | * Runs Simplifyify with the given args 37 | * 38 | * @param {string} args 39 | * @param {function} callback 40 | * @returns {ChildProcess} 41 | */ 42 | exports.run = function run (args, callback) { 43 | let exited = false, stdout = "", stderr = ""; 44 | 45 | // Run simplifyify 46 | args = [cliPath].concat(args ? args.split(" ") : []); 47 | let simplifyify = spawn("node", args, { cwd: testAppsDir }); 48 | 49 | // Capture stdout and stderr 50 | simplifyify.stdout.on("data", (data) => { 51 | stdout += data.toString(); 52 | }); 53 | simplifyify.stderr.on("data", (data) => { 54 | stderr += data.toString(); 55 | }); 56 | 57 | // Handle exits (successful or failure) 58 | simplifyify.on("exit", onExit); 59 | simplifyify.on("error", onExit); 60 | 61 | function onExit (code) { 62 | // onExit can sometimes fire multiple times, so ignore duplicates 63 | if (exited) { 64 | return; 65 | } 66 | exited = true; 67 | 68 | // TEMPORARY HACK to workaround a deprecation warning in Node 7. 69 | // TODO: Remove this code once all dependencies have been updated to eliminate this warning 70 | if (stderr && process.version.substr(0, 3) === "v7." && 71 | /^\(node:\d+\) DeprecationWarning: Using Buffer without `new` will soon stop working/.test(stderr)) { 72 | stderr = ""; 73 | } 74 | 75 | let err = null; 76 | if (code > 0 || stderr) { 77 | err = new Error(stderr || "Simplifyify exited with code " + code); 78 | err.code = code; 79 | } 80 | else if (code instanceof Error) { 81 | err = code; 82 | } 83 | 84 | if (isWindows) { 85 | // Replace Windows path separators with POSIX separators 86 | stdout = stdout.replace(/\\/g, "/"); 87 | stderr = stderr.replace(/\\/g, "/"); 88 | } 89 | 90 | callback(err, stdout.trim(), stderr.trim()); 91 | } 92 | 93 | return simplifyify; 94 | }; 95 | -------------------------------------------------------------------------------- /test/fixtures/mocha.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const host = require("@jsdevtools/host-environment"); 4 | 5 | exports.increaseTimeout = increaseTimeout; 6 | 7 | 8 | /** 9 | * Increases the timeout of a test, if necessary. 10 | */ 11 | function increaseTimeout (test, timeout) { 12 | if (host.ci) { 13 | // Increase timeouts when running in CI because slooooow 14 | timeout *= 4; 15 | } 16 | 17 | let currentTimeout = test.timeout(); 18 | if (currentTimeout >= timeout) { 19 | return currentTimeout; 20 | } 21 | else { 22 | test.timeout(timeout); 23 | test.slow(timeout * 0.75); 24 | return timeout; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/specs/bundle.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --bundle", () => { 8 | it("should bundle a single file by default", (done) => { 9 | cli.run("hello/index.js", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.contain("hello/index.js --> hello/index.bundle.js"); 15 | 16 | assert.directoryContents("hello", [ 17 | "banner.txt", 18 | "hello-world.js", 19 | "index.js", 20 | "index.bundle.js", 21 | "package.json", 22 | "say/index.js" 23 | ]); 24 | 25 | assert.fileContents("hello/index.bundle.js", (contents) => { 26 | assert.hasBanner(contents); 27 | assert.hasPreamble(contents); 28 | assert.notMinified(contents); 29 | assert.noSourceMap(contents); 30 | assert.noCoverage(contents); 31 | }); 32 | done(); 33 | }); 34 | }); 35 | 36 | it("should bundle a single file", (done) => { 37 | cli.run("hello/index.js --bundle", (err, stdout) => { 38 | if (err) { 39 | return done(err); 40 | } 41 | 42 | expect(stdout).to.contain("hello/index.js --> hello/index.bundle.js"); 43 | 44 | assert.directoryContents("hello", [ 45 | "banner.txt", 46 | "hello-world.js", 47 | "index.js", 48 | "index.bundle.js", 49 | "package.json", 50 | "say/index.js" 51 | ]); 52 | 53 | assert.fileContents("hello/index.bundle.js", (contents) => { 54 | assert.hasBanner(contents); 55 | assert.hasPreamble(contents); 56 | assert.notMinified(contents); 57 | assert.noSourceMap(contents); 58 | assert.noCoverage(contents); 59 | }); 60 | done(); 61 | }); 62 | }); 63 | 64 | it("should work with shorthand arguments", (done) => { 65 | cli.run("hello/index.js -b", (err, stdout) => { 66 | if (err) { 67 | return done(err); 68 | } 69 | 70 | expect(stdout).to.contain("hello/index.js --> hello/index.bundle.js"); 71 | 72 | assert.directoryContents("hello", [ 73 | "banner.txt", 74 | "hello-world.js", 75 | "index.js", 76 | "index.bundle.js", 77 | "package.json", 78 | "say/index.js" 79 | ]); 80 | 81 | assert.fileContents("hello/index.bundle.js", (contents) => { 82 | assert.hasBanner(contents); 83 | assert.hasPreamble(contents); 84 | assert.notMinified(contents); 85 | assert.noSourceMap(contents); 86 | assert.noCoverage(contents); 87 | }); 88 | done(); 89 | }); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /test/specs/cli.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | const version = require("../../package").version; 7 | 8 | describe("simplifyify --help", () => { 9 | it("should show help if called without any args", (done) => { 10 | cli.run("", (err, stdout) => { 11 | expect(err).to.be.an.instanceOf(Error); 12 | expect(stdout).to.match(/^Usage: simplifyify \[options\] /); 13 | assert.directoryIsEmpty("es5/dist"); 14 | done(); 15 | }); 16 | }); 17 | 18 | it("should exit with a nonzero if called without any args", (done) => { 19 | cli.run("", (err) => { 20 | expect(err).to.be.an.instanceOf(Error); 21 | expect(err.code).to.equal(1); 22 | done(); 23 | }); 24 | }); 25 | 26 | it("should show help if called with --help", (done) => { 27 | cli.run("--help", (err, stdout) => { 28 | expect(stdout).to.match(/^Usage: simplifyify \[options\] /); 29 | assert.directoryIsEmpty("es5/dist"); 30 | done(); 31 | }); 32 | }); 33 | 34 | it("should exit with zero if called with --help", (done) => { 35 | cli.run("--help", (err) => { 36 | expect(err).to.equal(null); 37 | done(); 38 | }); 39 | }); 40 | 41 | it("should show help if called with -h", (done) => { 42 | cli.run("--help", (err, stdout) => { 43 | expect(stdout).to.match(/^Usage: simplifyify \[options\] /); 44 | assert.directoryIsEmpty("es5/dist"); 45 | done(); 46 | }); 47 | }); 48 | 49 | it("should exit with zero if called with -h", (done) => { 50 | cli.run("--help", (err) => { 51 | expect(err).to.equal(null); 52 | done(); 53 | }); 54 | }); 55 | }); 56 | 57 | describe("simplifyify --version", () => { 58 | it("should output the version number if called --version", (done) => { 59 | cli.run("--version", (err, stdout) => { 60 | if (err) { 61 | return done(err); 62 | } 63 | 64 | expect(stdout).to.equal(version); 65 | assert.directoryIsEmpty("es5/dist"); 66 | done(); 67 | }); 68 | }); 69 | 70 | it("should output the version number if called -V", (done) => { 71 | cli.run("-V", (err, stdout) => { 72 | if (err) { 73 | return done(err); 74 | } 75 | 76 | expect(stdout).to.equal(version); 77 | assert.directoryIsEmpty("es5/dist"); 78 | done(); 79 | }); 80 | }); 81 | }); 82 | 83 | describe("failure tests", () => { 84 | it("should error if called with an unknown option", (done) => { 85 | cli.run("-z", (err, stdout, stderr) => { 86 | expect(err).to.be.an.instanceOf(Error); 87 | expect(stderr).to.contain("unknown option"); 88 | assert.directoryIsEmpty("es5/dist"); 89 | done(); 90 | }); 91 | }); 92 | 93 | it("should error if the entry file does not exist", (done) => { 94 | cli.run("some/file/that/does/not/exist.js --outfile dist/", (err, stdout, stderr) => { 95 | expect(err).to.be.an.instanceOf(Error); 96 | expect(stderr).to.equal("No matching entry files were found"); 97 | assert.directoryIsEmpty("es5/dist"); 98 | done(); 99 | }); 100 | }); 101 | 102 | it("should error if the entry file glob does not match any files", (done) => { 103 | cli.run('"lib/**/*-foo-bar.js" --outfile dist/', (err, stdout, stderr) => { 104 | expect(err).to.be.an.instanceOf(Error); 105 | expect(stderr).to.equal("No matching entry files were found"); 106 | assert.directoryIsEmpty("es5/dist"); 107 | done(); 108 | }); 109 | }); 110 | 111 | it("should error if all matching files are excluded", (done) => { 112 | cli.run('"lib/**/*.js" --exclude **/*.js --outfile dist/', (err, stdout, stderr) => { 113 | expect(err).to.be.an.instanceOf(Error); 114 | expect(stderr).to.equal("No matching entry files were found"); 115 | assert.directoryIsEmpty("es5/dist"); 116 | done(); 117 | }); 118 | }); 119 | 120 | it("should error if the --standalone param is not given", (done) => { 121 | cli.run("lib/index.js --outfile dist/ --standalone", (err, stdout, stderr) => { 122 | expect(err).to.be.an.instanceOf(Error); 123 | expect(stderr).to.contain("argument missing"); 124 | assert.directoryIsEmpty("es5/dist"); 125 | done(); 126 | }); 127 | }); 128 | }); 129 | -------------------------------------------------------------------------------- /test/specs/debug.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --debug", () => { 8 | it("should create source map for a single file", (done) => { 9 | cli.run("es5/lib/index.js --debug --outfile es5/dist/index.js", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 15 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js.map"); 16 | 17 | assert.directoryContents("es5/dist", [ 18 | "index.js", 19 | "index.js.map" 20 | ]); 21 | 22 | assert.fileContents("es5/dist/index.js", (contents) => { 23 | assert.noBanner(contents); 24 | assert.hasPreamble(contents); 25 | assert.notMinified(contents); 26 | assert.hasSourceMap(contents); 27 | assert.noCoverage(contents); 28 | }); 29 | 30 | assert.fileContents("es5/dist/index.js.map", (contents) => { 31 | expect(contents.sources).to.contain.members([ 32 | "../lib/hello-world.js", 33 | "../lib/index.js", 34 | "../lib/say/index.js" 35 | ]); 36 | }); 37 | done(); 38 | }); 39 | }); 40 | 41 | it("should create source maps for multiple files", (done) => { 42 | cli.run("es5/lib/**/*.js --debug --outfile es5/dist/", (err, stdout) => { 43 | if (err) { 44 | return done(err); 45 | } 46 | 47 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 48 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js.map"); 49 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js"); 50 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js.map"); 51 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 52 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js.map"); 53 | 54 | assert.directoryContents("es5/dist", [ 55 | "index.js", 56 | "index.js.map", 57 | "hello-world.js", 58 | "hello-world.js.map", 59 | "say/index.js", 60 | "say/index.js.map" 61 | ]); 62 | 63 | assert.fileContents("es5/dist", ["index.js", "hello-world.js", "say/index.js"], (contents) => { 64 | assert.noBanner(contents); 65 | assert.hasPreamble(contents); 66 | assert.notMinified(contents); 67 | assert.hasSourceMap(contents); 68 | assert.noCoverage(contents); 69 | }); 70 | assert.fileContents("es5/dist/index.js.map", (contents) => { 71 | expect(contents.sources).to.contain.members([ 72 | "../lib/hello-world.js", 73 | "../lib/index.js", 74 | "../lib/say/index.js" 75 | ]); 76 | }); 77 | assert.fileContents("es5/dist/hello-world.js.map", (contents) => { 78 | expect(contents.sources).to.contain.members([ 79 | "../lib/hello-world.js", 80 | "../lib/say/index.js" 81 | ]); 82 | }); 83 | assert.fileContents("es5/dist/say/index.js.map", (contents) => { 84 | expect(contents.sources).to.contain.members([ 85 | "../../lib/say/index.js" 86 | ]); 87 | }); 88 | done(); 89 | }); 90 | }); 91 | 92 | it("should create source maps for multiple minified files", (done) => { 93 | cli.run("es5/lib/**/index.js --bundle --debug --minify --outfile es5/dist/", (err, stdout) => { 94 | if (err) { 95 | return done(err); 96 | } 97 | 98 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 99 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js.map"); 100 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.min.js"); 101 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.min.js.map"); 102 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 103 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js.map"); 104 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.min.js"); 105 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.min.js.map"); 106 | 107 | assert.directoryContents("es5/dist", [ 108 | "index.js", 109 | "index.js.map", 110 | "index.min.js", 111 | "index.min.js.map", 112 | "say/index.js", 113 | "say/index.js.map", 114 | "say/index.min.js", 115 | "say/index.min.js.map" 116 | ]); 117 | 118 | assert.fileContents("es5/dist", ["index.js", "say/index.js"], (contents) => { 119 | assert.noBanner(contents); 120 | assert.hasPreamble(contents); 121 | assert.notMinified(contents); 122 | assert.hasSourceMap(contents); 123 | assert.noCoverage(contents); 124 | }); 125 | assert.fileContents("es5/dist", ["index.min.js", "say/index.min.js"], (contents) => { 126 | assert.noBanner(contents); 127 | assert.hasMinifiedPreamble(contents); 128 | assert.isMinified(contents); 129 | assert.hasSourceMap(contents); 130 | assert.noCoverage(contents); 131 | }); 132 | 133 | assert.fileContents("es5/dist", ["index.js.map", "index.min.js.map"], (contents) => { 134 | expect(contents.sources).to.contain.members([ 135 | "../lib/hello-world.js", 136 | "../lib/index.js", 137 | "../lib/say/index.js" 138 | ]); 139 | }); 140 | assert.fileContents("es5/dist", ["say/index.js.map", "say/index.min.js.map"], (contents) => { 141 | expect(contents.sources).to.contain.members([ 142 | "../../lib/say/index.js" 143 | ]); 144 | }); 145 | done(); 146 | }); 147 | }); 148 | 149 | it('should append ".map" when renaming output files', (done) => { 150 | cli.run("es5/lib/**/*.js --bundle --debug --minify --outfile es5/dist/*.bundle.es", (err, stdout) => { 151 | if (err) { 152 | return done(err); 153 | } 154 | 155 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.bundle.es"); 156 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.bundle.es.map"); 157 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.bundle.min.es"); 158 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.bundle.min.es.map"); 159 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.bundle.es"); 160 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.bundle.es.map"); 161 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.bundle.min.es"); 162 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.bundle.min.es.map"); 163 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.bundle.es"); 164 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.bundle.es.map"); 165 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.bundle.min.es"); 166 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.bundle.min.es.map"); 167 | 168 | assert.directoryContents("es5/dist", [ 169 | "index.bundle.es", 170 | "index.bundle.es.map", 171 | "index.bundle.min.es", 172 | "index.bundle.min.es.map", 173 | "hello-world.bundle.es", 174 | "hello-world.bundle.es.map", 175 | "hello-world.bundle.min.es", 176 | "hello-world.bundle.min.es.map", 177 | "say/index.bundle.es", 178 | "say/index.bundle.es.map", 179 | "say/index.bundle.min.es", 180 | "say/index.bundle.min.es.map" 181 | ]); 182 | 183 | assert.fileContents("es5/dist", ["index.bundle.es", "hello-world.bundle.es", "say/index.bundle.es"], 184 | (contents) => { 185 | assert.noBanner(contents); 186 | assert.hasPreamble(contents); 187 | assert.notMinified(contents); 188 | assert.hasSourceMap(contents); 189 | assert.noCoverage(contents); 190 | }); 191 | assert.fileContents("es5/dist", ["index.bundle.min.es", "hello-world.bundle.min.es", "say/index.bundle.min.es"], 192 | (contents) => { 193 | assert.noBanner(contents); 194 | assert.hasMinifiedPreamble(contents); 195 | assert.isMinified(contents); 196 | assert.hasSourceMap(contents); 197 | assert.noCoverage(contents); 198 | }); 199 | 200 | assert.fileContents("es5/dist", ["index.bundle.es.map", "index.bundle.min.es.map"], (contents) => { 201 | expect(contents.sources).to.contain.members([ 202 | "../lib/hello-world.js", 203 | "../lib/index.js", 204 | "../lib/say/index.js" 205 | ]); 206 | }); 207 | assert.fileContents("es5/dist", ["hello-world.bundle.es.map", "hello-world.bundle.min.es.map"], (contents) => { 208 | expect(contents.sources).to.contain.members([ 209 | "../lib/hello-world.js", 210 | "../lib/say/index.js" 211 | ]); 212 | }); 213 | assert.fileContents("es5/dist", ["say/index.bundle.es.map", "say/index.bundle.min.es.map"], (contents) => { 214 | expect(contents.sources).to.contain.members([ 215 | "../../lib/say/index.js" 216 | ]); 217 | }); 218 | done(); 219 | }); 220 | }); 221 | 222 | it("should create a sourcemap for a bundle with a banner", (done) => { 223 | cli.run("hello/index.js --debug --outfile hello/dist/", (err, stdout) => { 224 | if (err) { 225 | return done(err); 226 | } 227 | 228 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js"); 229 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js.map"); 230 | 231 | assert.directoryContents("hello", [ 232 | "banner.txt", 233 | "hello-world.js", 234 | "index.js", 235 | "package.json", 236 | "say/index.js", 237 | "dist/index.js", 238 | "dist/index.js.map", 239 | ]); 240 | 241 | assert.fileContents("hello/dist/index.js", (contents) => { 242 | assert.hasBanner(contents); 243 | assert.hasPreamble(contents); 244 | assert.notMinified(contents); 245 | assert.hasSourceMap(contents); 246 | assert.noCoverage(contents); 247 | }); 248 | 249 | assert.fileContents("hello/dist", "index.js.map", (contents) => { 250 | expect(contents.sources).to.contain.members([ 251 | "../hello-world.js", 252 | "../index.js", 253 | "../say/index.js" 254 | ]); 255 | 256 | // The first 9 lines of the sourcemap should be blank, since we don't 257 | // have sourcemappings for the banner 258 | expect(contents.mappings).to.match(/^;;;;;;;;;AAAA/); 259 | }); 260 | 261 | done(); 262 | }); 263 | }); 264 | 265 | it("should work with shorthand arguments", (done) => { 266 | cli.run("es5/lib/index.js -do es5/dist/index.js", (err, stdout) => { 267 | if (err) { 268 | return done(err); 269 | } 270 | 271 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 272 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js.map"); 273 | 274 | assert.directoryContents("es5/dist", [ 275 | "index.js", 276 | "index.js.map" 277 | ]); 278 | 279 | assert.fileContents("es5/dist/index.js", (contents) => { 280 | assert.noBanner(contents); 281 | assert.hasPreamble(contents); 282 | assert.notMinified(contents); 283 | assert.hasSourceMap(contents); 284 | assert.noCoverage(contents); 285 | }); 286 | 287 | assert.fileContents("es5/dist/index.js.map", (contents) => { 288 | expect(contents.sources).to.contain.members([ 289 | "../lib/hello-world.js", 290 | "../lib/index.js", 291 | "../lib/say/index.js" 292 | ]); 293 | }); 294 | done(); 295 | }); 296 | }); 297 | }); 298 | -------------------------------------------------------------------------------- /test/specs/exclude.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --exclude", () => { 8 | it("should not exclude anything if nothing matches", (done) => { 9 | cli.run("es5/lib/**/*.js --exclude es5/lib/**/*-foo.js --outfile es5/dist/", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 15 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js"); 16 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 17 | 18 | assert.directoryContents("es5/dist", [ 19 | "index.js", 20 | "hello-world.js", 21 | "say/index.js" 22 | ]); 23 | 24 | assert.fileContents("es5/dist", ["index.js", "hello-world.js", "say/index.js"], (contents) => { 25 | assert.noBanner(contents); 26 | assert.hasPreamble(contents); 27 | assert.notMinified(contents); 28 | assert.noSourceMap(contents); 29 | assert.noCoverage(contents); 30 | }); 31 | done(); 32 | }); 33 | }); 34 | 35 | it("should exclude a single file", (done) => { 36 | cli.run("es5/lib/**/*.js --exclude es5/lib/say/index.js --outfile es5/dist/", (err, stdout) => { 37 | if (err) { 38 | return done(err); 39 | } 40 | 41 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 42 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js"); 43 | expect(stdout).not.to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 44 | 45 | assert.directoryContents("es5/dist", [ 46 | "index.js", 47 | "hello-world.js" 48 | ]); 49 | 50 | assert.fileContents("es5/dist", ["index.js", "hello-world.js"], (contents) => { 51 | assert.noBanner(contents); 52 | assert.hasPreamble(contents); 53 | assert.notMinified(contents); 54 | assert.noSourceMap(contents); 55 | assert.noCoverage(contents); 56 | }); 57 | done(); 58 | }); 59 | }); 60 | 61 | it("should exclude multiple files", (done) => { 62 | cli.run("es5/lib/**/*.js --exclude es5/lib/**/index.js --outfile es5/dist/", (err, stdout) => { 63 | if (err) { 64 | return done(err); 65 | } 66 | 67 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js"); 68 | expect(stdout).not.to.contain("es5/lib/index.js --> es5/dist/index.js"); 69 | expect(stdout).not.to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 70 | 71 | assert.directoryContents("es5/dist", [ 72 | "hello-world.js" 73 | ]); 74 | 75 | assert.fileContents("es5/dist", ["hello-world.js"], (contents) => { 76 | assert.noBanner(contents); 77 | assert.hasPreamble(contents); 78 | assert.notMinified(contents); 79 | assert.noSourceMap(contents); 80 | assert.noCoverage(contents); 81 | }); 82 | done(); 83 | }); 84 | }); 85 | 86 | it("should work with shorthand arguments", (done) => { 87 | cli.run("es5/lib/**/*.js -x es5/lib/**/index.js -o es5/dist/", (err, stdout) => { 88 | if (err) { 89 | return done(err); 90 | } 91 | 92 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js"); 93 | expect(stdout).not.to.contain("es5/lib/index.js --> es5/dist/index.js"); 94 | expect(stdout).not.to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 95 | 96 | assert.directoryContents("es5/dist", [ 97 | "hello-world.js" 98 | ]); 99 | 100 | assert.fileContents("es5/dist", ["hello-world.js"], (contents) => { 101 | assert.noBanner(contents); 102 | assert.hasPreamble(contents); 103 | assert.notMinified(contents); 104 | assert.noSourceMap(contents); 105 | assert.noCoverage(contents); 106 | }); 107 | done(); 108 | }); 109 | }); 110 | }); 111 | -------------------------------------------------------------------------------- /test/specs/minify.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --minify", () => { 8 | it("should minify a single file", (done) => { 9 | cli.run("es5/lib/index.js --minify --outfile es5/dist/", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 15 | 16 | assert.directoryContents("es5/dist", "index.js"); 17 | 18 | assert.fileContents("es5/dist/index.js", (contents) => { 19 | assert.noBanner(contents); 20 | assert.hasMinifiedPreamble(contents); 21 | assert.isMinified(contents); 22 | assert.noSourceMap(contents); 23 | assert.noCoverage(contents); 24 | }); 25 | done(); 26 | }); 27 | }); 28 | 29 | it("should create a minified and non-minified file", (done) => { 30 | cli.run("es5/lib/index.js --bundle --minify --outfile es5/dist/", (err, stdout) => { 31 | if (err) { 32 | return done(err); 33 | } 34 | 35 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 36 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.min.js"); 37 | 38 | assert.directoryContents("es5/dist", [ 39 | "index.js", 40 | "index.min.js" 41 | ]); 42 | 43 | assert.fileContents("es5/dist/index.js", (contents) => { 44 | assert.noBanner(contents); 45 | assert.hasPreamble(contents); 46 | assert.notMinified(contents); 47 | assert.noSourceMap(contents); 48 | assert.noCoverage(contents); 49 | }); 50 | assert.fileContents("es5/dist/index.min.js", (contents) => { 51 | assert.noBanner(contents); 52 | assert.hasMinifiedPreamble(contents); 53 | assert.isMinified(contents); 54 | assert.noSourceMap(contents); 55 | assert.noCoverage(contents); 56 | }); 57 | done(); 58 | }); 59 | }); 60 | 61 | it("should minify multiple files", (done) => { 62 | cli.run("es5/lib/**/index.js --minify --outfile es5/dist/", (err, stdout) => { 63 | if (err) { 64 | return done(err); 65 | } 66 | 67 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 68 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 69 | 70 | assert.directoryContents("es5/dist", [ 71 | "index.js", 72 | "say/index.js", 73 | ]); 74 | 75 | assert.fileContents("es5/dist", ["index.js", "say/index.js"], (contents) => { 76 | assert.noBanner(contents); 77 | assert.hasMinifiedPreamble(contents); 78 | assert.isMinified(contents); 79 | assert.noSourceMap(contents); 80 | assert.noCoverage(contents); 81 | }); 82 | done(); 83 | }); 84 | }); 85 | 86 | it('should NOT append ".min" when renaming output files', (done) => { 87 | cli.run("es5/lib/**/*.js --minify --outfile es5/dist/*.foo.es5", (err, stdout) => { 88 | if (err) { 89 | return done(err); 90 | } 91 | 92 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.es5"); 93 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.es5"); 94 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.es5"); 95 | 96 | assert.directoryContents("es5/dist", [ 97 | "index.foo.es5", 98 | "hello-world.foo.es5", 99 | "say/index.foo.es5", 100 | ]); 101 | 102 | assert.fileContents("es5/dist", ["index.foo.es5", "hello-world.foo.es5", "say/index.foo.es5"], (contents) => { 103 | assert.noBanner(contents); 104 | assert.hasMinifiedPreamble(contents); 105 | assert.isMinified(contents); 106 | assert.noSourceMap(contents); 107 | assert.noCoverage(contents); 108 | }); 109 | done(); 110 | }); 111 | }); 112 | 113 | it('should append ".min" when renaming output files and producing multiple bundles', (done) => { 114 | cli.run("es5/lib/**/*.js --bundle --minify --outfile es5/dist/*.foo.es5", (err, stdout) => { 115 | if (err) { 116 | return done(err); 117 | } 118 | 119 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.es5"); 120 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.min.es5"); 121 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.es5"); 122 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.min.es5"); 123 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.es5"); 124 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.min.es5"); 125 | 126 | assert.directoryContents("es5/dist", [ 127 | "index.foo.es5", 128 | "index.foo.min.es5", 129 | "hello-world.foo.es5", 130 | "hello-world.foo.min.es5", 131 | "say/index.foo.es5", 132 | "say/index.foo.min.es5" 133 | ]); 134 | 135 | assert.fileContents("es5/dist", ["index.foo.es5", "hello-world.foo.es5", "say/index.foo.es5"], (contents) => { 136 | assert.noBanner(contents); 137 | assert.hasPreamble(contents); 138 | assert.notMinified(contents); 139 | assert.noSourceMap(contents); 140 | assert.noCoverage(contents); 141 | }); 142 | assert.fileContents("es5/dist", ["index.foo.min.es5", "hello-world.foo.min.es5", "say/index.foo.min.es5"], 143 | (contents) => { 144 | assert.noBanner(contents); 145 | assert.hasMinifiedPreamble(contents); 146 | assert.isMinified(contents); 147 | assert.noSourceMap(contents); 148 | assert.noCoverage(contents); 149 | }); 150 | done(); 151 | }); 152 | }); 153 | 154 | it("should create a minified bundle with a banner", (done) => { 155 | cli.run("hello/index.js --minify --outfile hello/dist/", (err, stdout) => { 156 | if (err) { 157 | return done(err); 158 | } 159 | 160 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js"); 161 | 162 | assert.directoryContents("hello", [ 163 | "banner.txt", 164 | "hello-world.js", 165 | "index.js", 166 | "package.json", 167 | "say/index.js", 168 | "dist/index.js", 169 | ]); 170 | 171 | assert.fileContents("hello/dist/index.js", (contents) => { 172 | assert.hasBanner(contents); 173 | assert.hasMinifiedPreamble(contents); 174 | assert.isMinified(contents); 175 | assert.noSourceMap(contents); 176 | assert.noCoverage(contents); 177 | }); 178 | done(); 179 | }); 180 | }); 181 | 182 | it("should work with shorthand arguments", (done) => { 183 | cli.run("es5/lib/index.js -bmo es5/dist/", (err, stdout) => { 184 | if (err) { 185 | return done(err); 186 | } 187 | 188 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 189 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.min.js"); 190 | 191 | assert.directoryContents("es5/dist", [ 192 | "index.js", 193 | "index.min.js" 194 | ]); 195 | 196 | assert.fileContents("es5/dist/index.js", (contents) => { 197 | assert.noBanner(contents); 198 | assert.hasPreamble(contents); 199 | assert.notMinified(contents); 200 | assert.noSourceMap(contents); 201 | assert.noCoverage(contents); 202 | }); 203 | assert.fileContents("es5/dist/index.min.js", (contents) => { 204 | assert.noBanner(contents); 205 | assert.hasMinifiedPreamble(contents); 206 | assert.isMinified(contents); 207 | assert.noSourceMap(contents); 208 | assert.noCoverage(contents); 209 | }); 210 | done(); 211 | }); 212 | }); 213 | }); 214 | -------------------------------------------------------------------------------- /test/specs/outfile.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --outfile", () => { 8 | it("should create a single output file, with the an explicit name", (done) => { 9 | cli.run("es5/lib/index.js --outfile es5/dist/my-file.js", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/my-file.js"); 15 | 16 | assert.directoryContents("es5/dist", "my-file.js"); 17 | 18 | assert.fileContents("es5/dist/my-file.js", (contents) => { 19 | assert.noBanner(contents); 20 | assert.hasPreamble(contents); 21 | assert.notMinified(contents); 22 | assert.noSourceMap(contents); 23 | assert.noCoverage(contents); 24 | }); 25 | done(); 26 | }); 27 | }); 28 | 29 | it("should create a single output file, with the entry file name", (done) => { 30 | cli.run("es5/lib/index.js --outfile es5/dist", (err, stdout) => { 31 | if (err) { 32 | return done(err); 33 | } 34 | 35 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/index.js"); 36 | 37 | assert.directoryContents("es5/dist", "index.js"); 38 | 39 | assert.fileContents("es5/dist/index.js", (contents) => { 40 | assert.noBanner(contents); 41 | assert.hasPreamble(contents); 42 | assert.notMinified(contents); 43 | assert.noSourceMap(contents); 44 | assert.noCoverage(contents); 45 | }); 46 | done(); 47 | }); 48 | }); 49 | 50 | it("should create multiple output files, with the entry file names", (done) => { 51 | cli.run("es5/lib/**/index.js --outfile es5/dist", (err, stdout) => { 52 | if (err) { 53 | return done(err); 54 | } 55 | 56 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 57 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 58 | 59 | assert.directoryContents("es5/dist", [ 60 | "index.js", 61 | "say/index.js" 62 | ]); 63 | 64 | assert.fileContents("es5/dist/index.js", (contents) => { 65 | assert.noBanner(contents); 66 | assert.hasPreamble(contents); 67 | assert.notMinified(contents); 68 | assert.noSourceMap(contents); 69 | assert.noCoverage(contents); 70 | }); 71 | assert.fileContents("es5/dist/say/index.js", (contents) => { 72 | assert.noBanner(contents); 73 | assert.hasPreamble(contents); 74 | assert.notMinified(contents); 75 | assert.noSourceMap(contents); 76 | assert.noCoverage(contents); 77 | }); 78 | 79 | done(); 80 | }); 81 | }); 82 | 83 | it("should create a single output file, with a patterned file name", (done) => { 84 | cli.run("es5/lib/index.js --outfile es5/dist/*.foo-bar.es6", (err, stdout) => { 85 | if (err) { 86 | return done(err); 87 | } 88 | 89 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/index.foo-bar.es6"); 90 | 91 | assert.directoryContents("es5/dist", "index.foo-bar.es6"); 92 | 93 | assert.fileContents("es5/dist/index.foo-bar.es6", (contents) => { 94 | assert.noBanner(contents); 95 | assert.hasPreamble(contents); 96 | assert.notMinified(contents); 97 | assert.noSourceMap(contents); 98 | assert.noCoverage(contents); 99 | }); 100 | done(); 101 | }); 102 | }); 103 | 104 | describe("no --outfile specified", () => { 105 | it("should create a single output file, in the entry file directory", (done) => { 106 | cli.run("es5/lib/index.js", (err, stdout) => { 107 | if (err) { 108 | return done(err); 109 | } 110 | 111 | expect(stdout).to.equal("es5/lib/index.js --> es5/lib/index.bundle.js"); 112 | 113 | let filesThatAlreadyExisted = ["hello-world.js", "index.js", "say/index.js"]; 114 | assert.directoryContents("es5/lib", 115 | ["index.bundle.js"].concat(filesThatAlreadyExisted)); 116 | 117 | assert.fileContents("es5/lib/index.bundle.js", (contents) => { 118 | assert.noBanner(contents); 119 | assert.hasPreamble(contents); 120 | assert.notMinified(contents); 121 | assert.noSourceMap(contents); 122 | assert.noCoverage(contents); 123 | }); 124 | done(); 125 | }); 126 | }); 127 | 128 | it("should create multiple output files, in the entry file directories", (done) => { 129 | cli.run("es5/lib/**/*.js --bundle --debug --minify --coverage", (err, stdout) => { 130 | if (err) { 131 | return done(err); 132 | } 133 | 134 | expect(stdout).to.contain("es5/lib/index.js --> es5/lib/index.bundle.js"); 135 | expect(stdout).to.contain("es5/lib/index.js --> es5/lib/index.bundle.js.map"); 136 | expect(stdout).to.contain("es5/lib/index.js --> es5/lib/index.bundle.min.js"); 137 | expect(stdout).to.contain("es5/lib/index.js --> es5/lib/index.bundle.min.js.map"); 138 | expect(stdout).to.contain("es5/lib/index.js --> es5/lib/index.bundle.coverage.js"); 139 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/lib/hello-world.bundle.js"); 140 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/lib/hello-world.bundle.js.map"); 141 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/lib/hello-world.bundle.min.js"); 142 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/lib/hello-world.bundle.min.js.map"); 143 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/lib/hello-world.bundle.coverage.js"); 144 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/lib/say/index.bundle.js"); 145 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/lib/say/index.bundle.js.map"); 146 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/lib/say/index.bundle.min.js"); 147 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/lib/say/index.bundle.min.js.map"); 148 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/lib/say/index.bundle.coverage.js"); 149 | 150 | let filesThatAlreadyExisted = ["hello-world.js", "index.js", "say/index.js"]; 151 | assert.directoryContents("es5/lib", [ 152 | "index.bundle.js", 153 | "index.bundle.js.map", 154 | "index.bundle.min.js", 155 | "index.bundle.min.js.map", 156 | "index.bundle.coverage.js", 157 | "hello-world.bundle.js", 158 | "hello-world.bundle.js.map", 159 | "hello-world.bundle.min.js", 160 | "hello-world.bundle.min.js.map", 161 | "hello-world.bundle.coverage.js", 162 | "say/index.bundle.js", 163 | "say/index.bundle.js.map", 164 | "say/index.bundle.min.js", 165 | "say/index.bundle.min.js.map", 166 | "say/index.bundle.coverage.js" 167 | ].concat(filesThatAlreadyExisted) 168 | ); 169 | 170 | assert.fileContents("es5/lib", [ 171 | "index.bundle.js", "hello-world.bundle.js", "say/index.bundle.js" 172 | ], 173 | (contents) => { 174 | assert.noBanner(contents); 175 | assert.hasPreamble(contents); 176 | assert.notMinified(contents); 177 | assert.hasSourceMap(contents); 178 | assert.noCoverage(contents); 179 | } 180 | ); 181 | assert.fileContents("es5/lib", [ 182 | "index.bundle.min.js", "hello-world.bundle.min.js", "say/index.bundle.min.js" 183 | ], 184 | (contents) => { 185 | assert.noBanner(contents); 186 | assert.hasMinifiedPreamble(contents); 187 | assert.isMinified(contents); 188 | assert.hasSourceMap(contents); 189 | assert.noCoverage(contents); 190 | } 191 | ); 192 | assert.fileContents("es5/lib", [ 193 | "index.bundle.coverage.js", "hello-world.bundle.coverage.js", "say/index.bundle.coverage.js" 194 | ], 195 | (contents) => { 196 | assert.noBanner(contents); 197 | assert.hasMinifiedPreamble(contents); 198 | assert.isMinified(contents, true); 199 | assert.noSourceMap(contents); 200 | assert.hasCoverage(contents); 201 | } 202 | ); 203 | 204 | assert.fileContents("es5/lib", ["index.bundle.js.map", "index.bundle.min.js.map"], 205 | (contents) => { 206 | expect(contents.sources).to.contain.members([ 207 | "hello-world.js", 208 | "index.js", 209 | "say/index.js" 210 | ]); 211 | } 212 | ); 213 | assert.fileContents("es5/lib", ["hello-world.bundle.js.map", "hello-world.bundle.min.js.map"], 214 | (contents) => { 215 | expect(contents.sources).to.contain.members([ 216 | "hello-world.js", 217 | "say/index.js" 218 | ]); 219 | } 220 | ); 221 | assert.fileContents("es5/lib", ["say/index.bundle.js.map", "say/index.bundle.min.js.map"], 222 | (contents) => { 223 | expect(contents.sources).to.contain.members([ 224 | "index.js" 225 | ]); 226 | } 227 | ); 228 | 229 | done(); 230 | }); 231 | }); 232 | }); 233 | 234 | it("should work with shorthand arguments", (done) => { 235 | cli.run("es5/lib/index.js -o es5/dist/my-file.js", (err, stdout) => { 236 | if (err) { 237 | return done(err); 238 | } 239 | 240 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/my-file.js"); 241 | 242 | assert.directoryContents("es5/dist", "my-file.js"); 243 | 244 | assert.fileContents("es5/dist/my-file.js", (contents) => { 245 | assert.noBanner(contents); 246 | assert.hasPreamble(contents); 247 | assert.notMinified(contents); 248 | assert.noSourceMap(contents); 249 | assert.noCoverage(contents); 250 | }); 251 | done(); 252 | }); 253 | }); 254 | }); 255 | -------------------------------------------------------------------------------- /test/specs/standalone.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --standalone", () => { 8 | it("should create a UMD module with the given name", (done) => { 9 | cli.run("es5/lib/index.js --standalone FizzBuzz --outfile es5/dist/", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/index.js"); 15 | 16 | assert.directoryContents("es5/dist", "index.js"); 17 | 18 | assert.fileContents("es5/dist/index.js", (contents) => { 19 | assert.noBanner(contents); 20 | assert.hasUmdPreamble(contents); 21 | assert.notMinified(contents); 22 | assert.noSourceMap(contents); 23 | assert.noCoverage(contents); 24 | expect(contents).to.match(/\.FizzBuzz = /); 25 | }); 26 | done(); 27 | }); 28 | }); 29 | 30 | it("should create a UMD module with a namespaced name", (done) => { 31 | cli.run("es5/lib/index.js --standalone Fizz.Buzz --outfile es5/dist/", (err, stdout) => { 32 | if (err) { 33 | return done(err); 34 | } 35 | 36 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/index.js"); 37 | 38 | assert.directoryContents("es5/dist", "index.js"); 39 | 40 | assert.fileContents("es5/dist/index.js", (contents) => { 41 | assert.noBanner(contents); 42 | assert.hasUmdPreamble(contents); 43 | assert.notMinified(contents); 44 | assert.noSourceMap(contents); 45 | assert.noCoverage(contents); 46 | expect(contents).to.match(/\.Fizz = /); 47 | expect(contents).to.match(/\.Buzz = /); 48 | }); 49 | done(); 50 | }); 51 | }); 52 | 53 | it("should create a UMD bundle with a banner", (done) => { 54 | cli.run("hello/index.js --standalone Fizz.Buzz --outfile hello/dist/", (err, stdout) => { 55 | if (err) { 56 | return done(err); 57 | } 58 | 59 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js"); 60 | 61 | assert.directoryContents("hello", [ 62 | "banner.txt", 63 | "hello-world.js", 64 | "index.js", 65 | "package.json", 66 | "say/index.js", 67 | "dist/index.js", 68 | ]); 69 | 70 | assert.fileContents("hello/dist/index.js", (contents) => { 71 | assert.hasBanner(contents); 72 | assert.hasUmdPreamble(contents); 73 | assert.notMinified(contents); 74 | assert.noSourceMap(contents); 75 | assert.noCoverage(contents); 76 | expect(contents).to.match(/\.Fizz = /); 77 | expect(contents).to.match(/\.Buzz = /); 78 | }); 79 | done(); 80 | }); 81 | }); 82 | 83 | it("should create a UMD bundle with all options", (done) => { 84 | cli.run("hello/index.js --bundle --minify --debug --coverage --standalone Fizz.Buzz --outfile hello/dist/", (err, stdout) => { 85 | if (err) { 86 | return done(err); 87 | } 88 | 89 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js"); 90 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js.map"); 91 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.min.js"); 92 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.min.js.map"); 93 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.coverage.js"); 94 | 95 | assert.directoryContents("hello", [ 96 | "banner.txt", 97 | "hello-world.js", 98 | "index.js", 99 | "package.json", 100 | "say/index.js", 101 | "dist/index.js", 102 | "dist/index.js.map", 103 | "dist/index.min.js", 104 | "dist/index.min.js.map", 105 | "dist/index.coverage.js", 106 | ]); 107 | 108 | assert.fileContents("hello/dist/index.js", (contents) => { 109 | assert.hasBanner(contents); 110 | assert.hasUmdPreamble(contents); 111 | assert.notMinified(contents); 112 | assert.hasSourceMap(contents); 113 | assert.noCoverage(contents); 114 | expect(contents).to.match(/\.Fizz = /); 115 | expect(contents).to.match(/\.Buzz = /); 116 | }); 117 | 118 | assert.fileContents("hello/dist/index.min.js", (contents) => { 119 | assert.hasBanner(contents); 120 | assert.hasMinifiedUmdPreamble(contents); 121 | assert.isMinified(contents); 122 | assert.hasSourceMap(contents); 123 | assert.noCoverage(contents); 124 | expect(contents).to.match(/\.Fizz=/); 125 | expect(contents).to.match(/\.Buzz=/); 126 | }); 127 | 128 | assert.fileContents("hello/dist/index.coverage.js", (contents) => { 129 | assert.hasBanner(contents); 130 | assert.hasMinifiedUmdPreamble(contents); 131 | assert.isMinified(contents, true); 132 | assert.noSourceMap(contents); 133 | assert.hasCoverage(contents); 134 | expect(contents).to.match(/\.Fizz=/); 135 | expect(contents).to.match(/\.Buzz=/); 136 | }); 137 | 138 | assert.fileContents("hello/dist", ["index.js.map", "index.min.js.map"], (contents) => { 139 | expect(contents.sources).to.contain.members([ 140 | "../hello-world.js", 141 | "../index.js", 142 | "../say/index.js" 143 | ]); 144 | }); 145 | 146 | done(); 147 | }); 148 | }); 149 | 150 | it("should create multiple UMD bundles with names derived from pattern", (done) => { 151 | cli.run("es5/lib/**/*.js --standalone Fizz.* --outfile es5/dist/", (err, stdout) => { 152 | if (err) { 153 | return done(err); 154 | } 155 | 156 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 157 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.js"); 158 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 159 | 160 | assert.directoryContents("es5/dist", [ 161 | "index.js", 162 | "hello-world.js", 163 | "say/index.js" 164 | ]); 165 | 166 | 167 | assert.fileContents("es5/dist/index.js", (contents) => { 168 | assert.noBanner(contents); 169 | assert.hasUmdPreamble(contents); 170 | assert.notMinified(contents); 171 | assert.noSourceMap(contents); 172 | assert.noCoverage(contents); 173 | expect(contents).to.match(/\.Fizz = /); 174 | expect(contents).to.match(/\.index = /); 175 | }); 176 | assert.fileContents("es5/dist/hello-world.js", (contents) => { 177 | assert.noBanner(contents); 178 | assert.hasUmdPreamble(contents); 179 | assert.notMinified(contents); 180 | assert.noSourceMap(contents); 181 | assert.noCoverage(contents); 182 | expect(contents).to.match(/\.Fizz = /); 183 | expect(contents).to.match(/\.helloWorld = /); 184 | }); 185 | assert.fileContents("es5/dist/say/index.js", (contents) => { 186 | assert.noBanner(contents); 187 | assert.hasUmdPreamble(contents); 188 | assert.notMinified(contents); 189 | assert.noSourceMap(contents); 190 | assert.noCoverage(contents); 191 | expect(contents).to.match(/\.Fizz = /); 192 | expect(contents).to.match(/\.say = /); 193 | expect(contents).to.match(/\.index = /); 194 | }); 195 | 196 | done(); 197 | }); 198 | }); 199 | 200 | it("should create a bundle and sourcemap for a universal library", (done) => { 201 | cli.run("universal-lib/lib/browser.js --outfile universal-lib/dist/universal-lib.js --standalone universal --bundle --debug --minify", (err, stdout) => { 202 | if (err) { 203 | return done(err); 204 | } 205 | 206 | expect(stdout).to.contain("universal-lib/lib/browser.js --> universal-lib/dist/universal-lib.js"); 207 | expect(stdout).to.contain("universal-lib/lib/browser.js --> universal-lib/dist/universal-lib.js.map"); 208 | 209 | assert.directoryContents("universal-lib", [ 210 | "banner.txt", 211 | "bower.json", 212 | "dist/universal-lib.js", 213 | "dist/universal-lib.js.map", 214 | "dist/universal-lib.min.js", 215 | "dist/universal-lib.min.js.map", 216 | "lib/browser.js", 217 | "lib/node.js", 218 | "lib/resolve.js", 219 | "package.json", 220 | ]); 221 | 222 | assert.fileContents("universal-lib/dist/universal-lib.js", (contents) => { 223 | assert.hasBanner(contents); 224 | assert.hasPreamble(contents); 225 | assert.notMinified(contents); 226 | assert.hasSourceMap(contents); 227 | assert.noCoverage(contents); 228 | }); 229 | 230 | assert.fileContents("universal-lib/dist/universal-lib.min.js", (contents) => { 231 | assert.hasBanner(contents); 232 | assert.hasMinifiedUmdPreamble(contents); 233 | assert.isMinified(contents); 234 | assert.hasSourceMap(contents); 235 | assert.noCoverage(contents); 236 | }); 237 | 238 | assert.fileContents("universal-lib/dist", ["universal-lib.js.map", "universal-lib.min.js.map"], (contents) => { 239 | expect(contents.sources).to.contain.members([ 240 | "../lib/browser.js", 241 | "../lib/resolve.js", 242 | ]); 243 | 244 | // The first 9 lines of the sourcemap should be blank, since we don't 245 | // have sourcemappings for the banner 246 | expect(contents.mappings).to.match(/^;;;;;;;;(C|A)AAA/); 247 | }); 248 | 249 | done(); 250 | }); 251 | }); 252 | 253 | it("should work with shorthand arguments", (done) => { 254 | cli.run("es5/lib/index.js -s FizzBuzz -o es5/dist/", (err, stdout) => { 255 | if (err) { 256 | return done(err); 257 | } 258 | 259 | expect(stdout).to.equal("es5/lib/index.js --> es5/dist/index.js"); 260 | 261 | assert.directoryContents("es5/dist", "index.js"); 262 | 263 | assert.fileContents("es5/dist/index.js", (contents) => { 264 | assert.noBanner(contents); 265 | assert.hasUmdPreamble(contents); 266 | assert.notMinified(contents); 267 | assert.noSourceMap(contents); 268 | assert.noCoverage(contents); 269 | expect(contents).to.match(/\.FizzBuzz = /); 270 | }); 271 | done(); 272 | }); 273 | }); 274 | 275 | }); 276 | -------------------------------------------------------------------------------- /test/specs/test.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const assert = require("../fixtures/assert"); 5 | const expect = require("chai").expect; 6 | 7 | describe("simplifyify --coverage", () => { 8 | it("should add code-coverage to a single file", (done) => { 9 | cli.run("es5/lib/index.js --coverage --outfile es5/dist/", (err, stdout) => { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 15 | 16 | assert.directoryContents("es5/dist", "index.js"); 17 | 18 | assert.fileContents("es5/dist/index.js", (contents) => { 19 | assert.noBanner(contents); 20 | assert.hasMinifiedPreamble(contents); 21 | assert.isMinified(contents, true); 22 | assert.noSourceMap(contents); 23 | assert.hasCoverage(contents); 24 | }); 25 | done(); 26 | }); 27 | }); 28 | 29 | it("should create a code-coverage and normal file", (done) => { 30 | cli.run("es5/lib/index.js --bundle --coverage --outfile es5/dist/", (err, stdout) => { 31 | if (err) { 32 | return done(err); 33 | } 34 | 35 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 36 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.coverage.js"); 37 | 38 | assert.directoryContents("es5/dist", [ 39 | "index.js", 40 | "index.coverage.js" 41 | ]); 42 | 43 | assert.fileContents("es5/dist/index.js", (contents) => { 44 | assert.noBanner(contents); 45 | assert.hasPreamble(contents); 46 | assert.notMinified(contents); 47 | assert.noSourceMap(contents); 48 | assert.noCoverage(contents); 49 | }); 50 | assert.fileContents("es5/dist/index.coverage.js", (contents) => { 51 | assert.noBanner(contents); 52 | assert.hasMinifiedPreamble(contents); 53 | assert.isMinified(contents, true); 54 | assert.noSourceMap(contents); 55 | assert.hasCoverage(contents); 56 | }); 57 | done(); 58 | }); 59 | }); 60 | 61 | it("should add code-coverage to multiple files", (done) => { 62 | cli.run("es5/lib/**/index.js --coverage --outfile es5/dist/", (err, stdout) => { 63 | if (err) { 64 | return done(err); 65 | } 66 | 67 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 68 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.js"); 69 | 70 | assert.directoryContents("es5/dist", [ 71 | "index.js", 72 | "say/index.js", 73 | ]); 74 | 75 | assert.fileContents("es5/dist", ["index.js", "say/index.js"], (contents) => { 76 | assert.noBanner(contents); 77 | assert.hasMinifiedPreamble(contents); 78 | assert.isMinified(contents, true); 79 | assert.noSourceMap(contents); 80 | assert.hasCoverage(contents); 81 | }); 82 | done(); 83 | }); 84 | }); 85 | 86 | it('should NOT create a ".map" file for test bundles, even if --debug is set', (done) => { 87 | cli.run("es5/lib/**/*.js --coverage --debug --outfile es5/dist/*.foo.es5", (err, stdout) => { 88 | if (err) { 89 | return done(err); 90 | } 91 | 92 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.es5"); 93 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.es5"); 94 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.es5"); 95 | 96 | assert.directoryContents("es5/dist", [ 97 | "index.foo.es5", 98 | "hello-world.foo.es5", 99 | "say/index.foo.es5", 100 | ]); 101 | 102 | assert.fileContents("es5/dist", ["index.foo.es5", "hello-world.foo.es5", "say/index.foo.es5"], (contents) => { 103 | assert.noBanner(contents); 104 | assert.hasMinifiedPreamble(contents); 105 | assert.isMinified(contents, true); 106 | assert.noSourceMap(contents); 107 | assert.hasCoverage(contents); 108 | }); 109 | 110 | done(); 111 | }); 112 | }); 113 | 114 | it('should NOT append ".test" when renaming output files', (done) => { 115 | cli.run("es5/lib/**/*.js --coverage --outfile es5/dist/*.foo.es5", (err, stdout) => { 116 | if (err) { 117 | return done(err); 118 | } 119 | 120 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.es5"); 121 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.es5"); 122 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.es5"); 123 | 124 | assert.directoryContents("es5/dist", [ 125 | "index.foo.es5", 126 | "hello-world.foo.es5", 127 | "say/index.foo.es5", 128 | ]); 129 | 130 | assert.fileContents("es5/dist", ["index.foo.es5", "hello-world.foo.es5", "say/index.foo.es5"], (contents) => { 131 | assert.noBanner(contents); 132 | assert.hasMinifiedPreamble(contents); 133 | assert.isMinified(contents, true); 134 | assert.noSourceMap(contents); 135 | assert.hasCoverage(contents); 136 | }); 137 | 138 | done(); 139 | }); 140 | }); 141 | 142 | it('should append ".test" when renaming output files and producing multiple bundles', (done) => { 143 | cli.run("es5/lib/**/*.js --coverage --bundle --minify --debug --outfile es5/dist/*.foo.es5", (err, stdout) => { 144 | if (err) { 145 | return done(err); 146 | } 147 | 148 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.es5"); 149 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.es5.map"); 150 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.min.es5"); 151 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.min.es5.map"); 152 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.foo.coverage.es5"); 153 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.es5"); 154 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.es5.map"); 155 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.min.es5"); 156 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.min.es5.map"); 157 | expect(stdout).to.contain("es5/lib/hello-world.js --> es5/dist/hello-world.foo.coverage.es5"); 158 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.es5"); 159 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.es5.map"); 160 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.min.es5"); 161 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.min.es5.map"); 162 | expect(stdout).to.contain("es5/lib/say/index.js --> es5/dist/say/index.foo.coverage.es5"); 163 | 164 | assert.directoryContents("es5/dist", [ 165 | "index.foo.es5", 166 | "index.foo.es5.map", 167 | "index.foo.min.es5", 168 | "index.foo.min.es5.map", 169 | "index.foo.coverage.es5", 170 | "hello-world.foo.es5", 171 | "hello-world.foo.es5.map", 172 | "hello-world.foo.min.es5", 173 | "hello-world.foo.min.es5.map", 174 | "hello-world.foo.coverage.es5", 175 | "say/index.foo.es5", 176 | "say/index.foo.es5.map", 177 | "say/index.foo.min.es5", 178 | "say/index.foo.min.es5.map", 179 | "say/index.foo.coverage.es5" 180 | ]); 181 | 182 | assert.fileContents("es5/dist", ["index.foo.es5", "hello-world.foo.es5", "say/index.foo.es5"], (contents) => { 183 | assert.noBanner(contents); 184 | assert.hasPreamble(contents); 185 | assert.notMinified(contents); 186 | assert.hasSourceMap(contents); 187 | assert.noCoverage(contents); 188 | }); 189 | assert.fileContents("es5/dist", ["index.foo.min.es5", "hello-world.foo.min.es5", "say/index.foo.min.es5"], 190 | (contents) => { 191 | assert.noBanner(contents); 192 | assert.hasMinifiedPreamble(contents); 193 | assert.isMinified(contents); 194 | assert.hasSourceMap(contents); 195 | assert.noCoverage(contents); 196 | }); 197 | assert.fileContents("es5/dist", ["index.foo.coverage.es5", "hello-world.foo.coverage.es5", "say/index.foo.coverage.es5"], 198 | (contents) => { 199 | assert.noBanner(contents); 200 | assert.hasMinifiedPreamble(contents); 201 | assert.isMinified(contents, true); 202 | assert.noSourceMap(contents); 203 | assert.hasCoverage(contents); 204 | }); 205 | 206 | assert.fileContents("es5/dist", ["index.foo.es5.map", "index.foo.min.es5.map"], (contents) => { 207 | expect(contents.sources).to.contain.members([ 208 | "../lib/hello-world.js", 209 | "../lib/index.js", 210 | "../lib/say/index.js" 211 | ]); 212 | }); 213 | assert.fileContents("es5/dist", ["hello-world.foo.es5.map", "hello-world.foo.min.es5.map"], (contents) => { 214 | expect(contents.sources).to.contain.members([ 215 | "../lib/hello-world.js", 216 | "../lib/say/index.js" 217 | ]); 218 | }); 219 | assert.fileContents("es5/dist", ["say/index.foo.es5.map", "say/index.foo.min.es5.map"], (contents) => { 220 | expect(contents.sources).to.contain.members([ 221 | "../../lib/say/index.js" 222 | ]); 223 | }); 224 | done(); 225 | }); 226 | }); 227 | 228 | it("should create a test bundle with a banner", (done) => { 229 | cli.run("hello/index.js --coverage --outfile hello/dist/", (err, stdout) => { 230 | if (err) { 231 | return done(err); 232 | } 233 | 234 | expect(stdout).to.contain("hello/index.js --> hello/dist/index.js"); 235 | 236 | assert.directoryContents("hello", [ 237 | "banner.txt", 238 | "hello-world.js", 239 | "index.js", 240 | "package.json", 241 | "say/index.js", 242 | "dist/index.js", 243 | ]); 244 | 245 | assert.fileContents("hello/dist/index.js", (contents) => { 246 | assert.hasBanner(contents); 247 | assert.hasMinifiedPreamble(contents); 248 | assert.isMinified(contents, true); 249 | assert.noSourceMap(contents); 250 | assert.hasCoverage(contents); 251 | }); 252 | done(); 253 | }); 254 | }); 255 | 256 | it("should work with shorthand arguments", (done) => { 257 | cli.run("es5/lib/index.js -bco es5/dist/", (err, stdout) => { 258 | if (err) { 259 | return done(err); 260 | } 261 | 262 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.js"); 263 | expect(stdout).to.contain("es5/lib/index.js --> es5/dist/index.coverage.js"); 264 | 265 | assert.directoryContents("es5/dist", [ 266 | "index.js", 267 | "index.coverage.js" 268 | ]); 269 | 270 | assert.fileContents("es5/dist/index.js", (contents) => { 271 | assert.noBanner(contents); 272 | assert.hasPreamble(contents); 273 | assert.notMinified(contents); 274 | assert.noSourceMap(contents); 275 | assert.noCoverage(contents); 276 | }); 277 | assert.fileContents("es5/dist/index.coverage.js", (contents) => { 278 | assert.noBanner(contents); 279 | assert.hasMinifiedPreamble(contents); 280 | assert.isMinified(contents, true); 281 | assert.noSourceMap(contents); 282 | assert.hasCoverage(contents); 283 | }); 284 | done(); 285 | }); 286 | }); 287 | }); 288 | -------------------------------------------------------------------------------- /test/specs/transform.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const mocha = require("../fixtures/mocha"); 5 | const assert = require("../fixtures/assert"); 6 | const expect = require("chai").expect; 7 | 8 | describe("browserify transforms", () => { 9 | beforeEach(function () { 10 | // Increase the test timeouts to allow sufficient time for Browserify transforms 11 | mocha.increaseTimeout(this.currentTest, 15000); 12 | }); 13 | 14 | it("should use the browserify.transform field in package.json", (done) => { 15 | cli.run("es6/src/**/*.js --bundle --minify --debug --coverage --outfile es6/dist/", (err, stdout) => { 16 | if (err) { 17 | return done(err); 18 | } 19 | 20 | expect(stdout).to.contain("es6/src/index.js --> es6/dist/index.js"); 21 | expect(stdout).to.contain("es6/src/index.js --> es6/dist/index.js.map"); 22 | expect(stdout).to.contain("es6/src/index.js --> es6/dist/index.min.js"); 23 | expect(stdout).to.contain("es6/src/index.js --> es6/dist/index.min.js.map"); 24 | expect(stdout).to.contain("es6/src/index.js --> es6/dist/index.coverage.js"); 25 | expect(stdout).to.contain("es6/src/hello-world.js --> es6/dist/hello-world.js"); 26 | expect(stdout).to.contain("es6/src/hello-world.js --> es6/dist/hello-world.js.map"); 27 | expect(stdout).to.contain("es6/src/hello-world.js --> es6/dist/hello-world.min.js"); 28 | expect(stdout).to.contain("es6/src/hello-world.js --> es6/dist/hello-world.min.js.map"); 29 | expect(stdout).to.contain("es6/src/hello-world.js --> es6/dist/hello-world.coverage.js"); 30 | expect(stdout).to.contain("es6/src/say/index.js --> es6/dist/say/index.js"); 31 | expect(stdout).to.contain("es6/src/say/index.js --> es6/dist/say/index.js.map"); 32 | expect(stdout).to.contain("es6/src/say/index.js --> es6/dist/say/index.min.js"); 33 | expect(stdout).to.contain("es6/src/say/index.js --> es6/dist/say/index.min.js.map"); 34 | expect(stdout).to.contain("es6/src/say/index.js --> es6/dist/say/index.coverage.js"); 35 | 36 | assert.directoryContents("es6/dist", [ 37 | "index.js", 38 | "index.js.map", 39 | "index.min.js", 40 | "index.min.js.map", 41 | "index.coverage.js", 42 | "hello-world.js", 43 | "hello-world.js.map", 44 | "hello-world.min.js", 45 | "hello-world.min.js.map", 46 | "hello-world.coverage.js", 47 | "say/index.js", 48 | "say/index.js.map", 49 | "say/index.min.js", 50 | "say/index.min.js.map", 51 | "say/index.coverage.js", 52 | ]); 53 | 54 | assert.fileContents("es6/dist", ["index.js", "hello-world.js", "say/index.js"], (contents) => { 55 | assert.noBanner(contents); 56 | assert.notMinified(contents); 57 | assert.hasPreamble(contents); 58 | assert.hasSourceMap(contents); 59 | assert.noCoverage(contents); 60 | assert.isBabelified(contents); 61 | }); 62 | 63 | assert.fileContents("es6/dist", ["index.min.js", "hello-world.min.js", "say/index.min.js"], (contents) => { 64 | assert.noBanner(contents); 65 | assert.hasMinifiedPreamble(contents); 66 | assert.isMinified(contents); 67 | assert.hasSourceMap(contents); 68 | assert.noCoverage(contents); 69 | assert.isBabelified(contents); 70 | }); 71 | 72 | assert.fileContents("es6/dist", ["index.coverage.js", "hello-world.coverage.js", "say/index.coverage.js"], (contents) => { 73 | assert.noBanner(contents); 74 | assert.hasMinifiedPreamble(contents); 75 | assert.isMinified(contents, true); 76 | assert.noSourceMap(contents); 77 | assert.hasCoverage(contents); 78 | assert.isBabelified(contents); 79 | }); 80 | 81 | assert.fileContents("es6/dist", ["index.js.map", "index.min.js.map"], (contents) => { 82 | expect(contents.sources).to.contain.members([ 83 | "../src/hello-world.js", 84 | "../src/index.js", 85 | "../src/say/index.js" 86 | ]); 87 | }); 88 | 89 | assert.fileContents("es6/dist", ["hello-world.js.map", "hello-world.min.js.map"], (contents) => { 90 | expect(contents.sources).to.contain.members([ 91 | "../src/hello-world.js", 92 | "../src/say/index.js" 93 | ]); 94 | }); 95 | 96 | assert.fileContents("es6/dist/say", ["index.js.map", "index.min.js.map"], (contents) => { 97 | expect(contents.sources).to.contain.members([ 98 | "../../src/say/index.js" 99 | ]); 100 | }); 101 | 102 | done(); 103 | }); 104 | }); 105 | 106 | it("should use the transform options in the browserify.transform field", (done) => { 107 | cli.run("es6-with-options/src/**/*.js --bundle --minify --debug --coverage --outfile es6-with-options/dist/", (err, stdout) => { 108 | if (err) { 109 | return done(err); 110 | } 111 | 112 | expect(stdout).to.contain("es6-with-options/src/index.js --> es6-with-options/dist/index.js"); 113 | expect(stdout).to.contain("es6-with-options/src/index.js --> es6-with-options/dist/index.js.map"); 114 | expect(stdout).to.contain("es6-with-options/src/index.js --> es6-with-options/dist/index.min.js"); 115 | expect(stdout).to.contain("es6-with-options/src/index.js --> es6-with-options/dist/index.min.js.map"); 116 | expect(stdout).to.contain("es6-with-options/src/index.js --> es6-with-options/dist/index.coverage.js"); 117 | expect(stdout).to.contain("es6-with-options/src/hello-world.js --> es6-with-options/dist/hello-world.js"); 118 | expect(stdout).to.contain("es6-with-options/src/hello-world.js --> es6-with-options/dist/hello-world.js.map"); 119 | expect(stdout).to.contain("es6-with-options/src/hello-world.js --> es6-with-options/dist/hello-world.min.js"); 120 | expect(stdout).to.contain("es6-with-options/src/hello-world.js --> es6-with-options/dist/hello-world.min.js.map"); 121 | expect(stdout).to.contain("es6-with-options/src/hello-world.js --> es6-with-options/dist/hello-world.coverage.js"); 122 | expect(stdout).to.contain("es6-with-options/src/say/index.js --> es6-with-options/dist/say/index.js"); 123 | expect(stdout).to.contain("es6-with-options/src/say/index.js --> es6-with-options/dist/say/index.js.map"); 124 | expect(stdout).to.contain("es6-with-options/src/say/index.js --> es6-with-options/dist/say/index.min.js"); 125 | expect(stdout).to.contain("es6-with-options/src/say/index.js --> es6-with-options/dist/say/index.min.js.map"); 126 | expect(stdout).to.contain("es6-with-options/src/say/index.js --> es6-with-options/dist/say/index.coverage.js"); 127 | 128 | assert.directoryContents("es6-with-options/dist", [ 129 | "index.js", 130 | "index.js.map", 131 | "index.min.js", 132 | "index.min.js.map", 133 | "index.coverage.js", 134 | "hello-world.js", 135 | "hello-world.js.map", 136 | "hello-world.min.js", 137 | "hello-world.min.js.map", 138 | "hello-world.coverage.js", 139 | "say/index.js", 140 | "say/index.js.map", 141 | "say/index.min.js", 142 | "say/index.min.js.map", 143 | "say/index.coverage.js", 144 | ]); 145 | 146 | assert.fileContents("es6-with-options/dist", ["index.js", "hello-world.js", "say/index.js"], (contents) => { 147 | assert.noBanner(contents); 148 | assert.hasPreamble(contents); 149 | assert.notMinified(contents); 150 | assert.hasSourceMap(contents); 151 | assert.noCoverage(contents); 152 | assert.isBabelified(contents); 153 | }); 154 | 155 | assert.fileContents("es6-with-options/dist", ["index.min.js", "hello-world.min.js", "say/index.min.js"], (contents) => { 156 | assert.noBanner(contents); 157 | assert.hasMinifiedPreamble(contents); 158 | assert.isMinified(contents); 159 | assert.hasSourceMap(contents); 160 | assert.noCoverage(contents); 161 | assert.isBabelified(contents); 162 | }); 163 | 164 | assert.fileContents("es6-with-options/dist", ["index.coverage.js", "hello-world.coverage.js", "say/index.coverage.js"], (contents) => { 165 | assert.noBanner(contents); 166 | assert.hasMinifiedPreamble(contents); 167 | assert.isMinified(contents, true); 168 | assert.noSourceMap(contents); 169 | assert.hasCoverage(contents); 170 | assert.isBabelified(contents); 171 | }); 172 | 173 | assert.fileContents("es6-with-options/dist", ["index.js.map", "index.min.js.map"], (contents) => { 174 | expect(contents.sources).to.contain.members([ 175 | "../src/hello-world.js", 176 | "../src/index.js", 177 | "../src/say/index.js" 178 | ]); 179 | }); 180 | 181 | assert.fileContents("es6-with-options/dist", ["hello-world.js.map", "hello-world.min.js.map"], (contents) => { 182 | expect(contents.sources).to.contain.members([ 183 | "../src/hello-world.js", 184 | "../src/say/index.js" 185 | ]); 186 | }); 187 | 188 | assert.fileContents("es6-with-options/dist/say", ["index.js.map", "index.min.js.map"], (contents) => { 189 | expect(contents.sources).to.contain.members([ 190 | "../../src/say/index.js" 191 | ]); 192 | }); 193 | 194 | done(); 195 | }); 196 | }); 197 | 198 | it("should use the browserify.transform field for built-in transforms", (done) => { 199 | cli.run("transform-options/src/**/*.js --bundle --minify --debug --coverage --outfile transform-options/dist/", (err, stdout) => { 200 | if (err) { 201 | return done(err); 202 | } 203 | 204 | expect(stdout).to.contain("transform-options/src/index.js --> transform-options/dist/index.js"); 205 | expect(stdout).to.contain("transform-options/src/index.js --> transform-options/dist/index.js.map"); 206 | expect(stdout).to.contain("transform-options/src/index.js --> transform-options/dist/index.min.js"); 207 | expect(stdout).to.contain("transform-options/src/index.js --> transform-options/dist/index.min.js.map"); 208 | expect(stdout).to.contain("transform-options/src/index.js --> transform-options/dist/index.coverage.js"); 209 | expect(stdout).to.contain("transform-options/src/hello-world.js --> transform-options/dist/hello-world.js"); 210 | expect(stdout).to.contain("transform-options/src/hello-world.js --> transform-options/dist/hello-world.js.map"); 211 | expect(stdout).to.contain("transform-options/src/hello-world.js --> transform-options/dist/hello-world.min.js"); 212 | expect(stdout).to.contain("transform-options/src/hello-world.js --> transform-options/dist/hello-world.min.js.map"); 213 | expect(stdout).to.contain("transform-options/src/hello-world.js --> transform-options/dist/hello-world.coverage.js"); 214 | expect(stdout).to.contain("transform-options/src/say/index.js --> transform-options/dist/say/index.js"); 215 | expect(stdout).to.contain("transform-options/src/say/index.js --> transform-options/dist/say/index.js.map"); 216 | expect(stdout).to.contain("transform-options/src/say/index.js --> transform-options/dist/say/index.min.js"); 217 | expect(stdout).to.contain("transform-options/src/say/index.js --> transform-options/dist/say/index.min.js.map"); 218 | expect(stdout).to.contain("transform-options/src/say/index.js --> transform-options/dist/say/index.coverage.js"); 219 | 220 | assert.directoryContents("transform-options/dist", [ 221 | "index.js", 222 | "index.js.map", 223 | "index.min.js", 224 | "index.min.js.map", 225 | "index.coverage.js", 226 | "hello-world.js", 227 | "hello-world.js.map", 228 | "hello-world.min.js", 229 | "hello-world.min.js.map", 230 | "hello-world.coverage.js", 231 | "say/index.js", 232 | "say/index.js.map", 233 | "say/index.min.js", 234 | "say/index.min.js.map", 235 | "say/index.coverage.js", 236 | ]); 237 | 238 | assert.fileContents("transform-options/dist", ["index.js", "hello-world.js", "say/index.js"], (contents) => { 239 | assert.hasBanner(contents); 240 | assert.hasPreamble(contents); 241 | assert.notMinified(contents); 242 | assert.hasSourceMap(contents); 243 | assert.noCoverage(contents); 244 | assert.isBabelified(contents); 245 | }); 246 | 247 | assert.fileContents("transform-options/dist", ["index.min.js", "hello-world.min.js", "say/index.min.js"], (contents) => { 248 | assert.hasBanner(contents); 249 | assert.hasPreamble(contents); 250 | assert.notMinified(contents); 251 | assert.hasSourceMap(contents); 252 | assert.noCoverage(contents); 253 | assert.isBabelified(contents); 254 | }); 255 | 256 | assert.fileContents("transform-options/dist", ["index.coverage.js", "hello-world.coverage.js", "say/index.coverage.js"], (contents) => { 257 | assert.hasBanner(contents); 258 | assert.hasPreamble(contents); 259 | assert.notMinified(contents); 260 | assert.noSourceMap(contents); 261 | assert.hasCoverage(contents); 262 | assert.isBabelified(contents); 263 | }); 264 | 265 | assert.fileContents("transform-options/dist", ["index.js.map", "index.min.js.map"], (contents) => { 266 | expect(contents.sources).to.contain.members([ 267 | "../src/hello-world.js", 268 | "../src/index.js", 269 | "../src/say/index.js" 270 | ]); 271 | }); 272 | 273 | assert.fileContents("transform-options/dist", ["hello-world.js.map", "hello-world.min.js.map"], (contents) => { 274 | expect(contents.sources).to.contain.members([ 275 | "../src/hello-world.js", 276 | "../src/say/index.js" 277 | ]); 278 | }); 279 | 280 | assert.fileContents("transform-options/dist/say", ["index.js.map", "index.min.js.map"], (contents) => { 281 | expect(contents.sources).to.contain.members([ 282 | "../../src/say/index.js" 283 | ]); 284 | }); 285 | 286 | done(); 287 | }); 288 | }); 289 | }); 290 | -------------------------------------------------------------------------------- /test/specs/typescript.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const cli = require("../fixtures/cli"); 4 | const mocha = require("../fixtures/mocha"); 5 | const assert = require("../fixtures/assert"); 6 | const expect = require("chai").expect; 7 | 8 | describe("TypeScript support", () => { 9 | beforeEach(function () { 10 | // Increase the test timeouts to allow sufficient time for Browserify transforms 11 | mocha.increaseTimeout(this.currentTest, 90000); 12 | }); 13 | 14 | it("should automatically enable TypeScript if the entry file has a .ts extenstion", (done) => { 15 | cli.run("typescript/src/index.ts --bundle --minify --debug --coverage --outfile typescript/dist/", (err, stdout) => { 16 | if (err) { 17 | return done(err); 18 | } 19 | 20 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.js"); 21 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.js.map"); 22 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.min.js"); 23 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.min.js.map"); 24 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.coverage.js"); 25 | 26 | assert.directoryContents("typescript/dist", [ 27 | "index.js", 28 | "index.js.map", 29 | "index.min.js", 30 | "index.min.js.map", 31 | "index.coverage.js", 32 | ]); 33 | 34 | assert.fileContents("typescript/dist", "index.js", (contents) => { 35 | assert.noBanner(contents); 36 | assert.notMinified(contents); 37 | assert.hasPreamble(contents); 38 | assert.hasSourceMap(contents); 39 | assert.noCoverage(contents); 40 | assert.isBabelified(contents); 41 | }); 42 | 43 | assert.fileContents("typescript/dist", "index.min.js", (contents) => { 44 | assert.noBanner(contents); 45 | assert.hasMinifiedPreamble(contents); 46 | assert.isMinified(contents); 47 | assert.hasSourceMap(contents); 48 | assert.noCoverage(contents); 49 | assert.isBabelified(contents); 50 | }); 51 | 52 | assert.fileContents("typescript/dist", "index.coverage.js", (contents) => { 53 | assert.noBanner(contents); 54 | assert.hasMinifiedPreamble(contents); 55 | assert.isMinified(contents, true); 56 | assert.noSourceMap(contents); 57 | assert.hasCoverage(contents); 58 | assert.isBabelified(contents); 59 | }); 60 | 61 | assert.fileContents("typescript/dist", ["index.js.map", "index.min.js.map"], (contents) => { 62 | expect(contents.sources).to.contain.members([ 63 | "../src/hello-world.tsx", 64 | "../src/index.ts", 65 | "../src/say/index.ts" 66 | ]); 67 | }); 68 | 69 | done(); 70 | }); 71 | }); 72 | 73 | it("should automatically enable TypeScript if the entry files has a .tsx extenstion", (done) => { 74 | cli.run("typescript/src/hello-world.tsx --bundle --minify --debug --coverage --outfile typescript/dist/", (err, stdout) => { 75 | if (err) { 76 | return done(err); 77 | } 78 | 79 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.js"); 80 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.js.map"); 81 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.min.js"); 82 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.min.js.map"); 83 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.coverage.js"); 84 | 85 | assert.directoryContents("typescript/dist", [ 86 | "hello-world.js", 87 | "hello-world.js.map", 88 | "hello-world.min.js", 89 | "hello-world.min.js.map", 90 | "hello-world.coverage.js", 91 | ]); 92 | 93 | assert.fileContents("typescript/dist", "hello-world.js", (contents) => { 94 | assert.noBanner(contents); 95 | assert.notMinified(contents); 96 | assert.hasPreamble(contents); 97 | assert.hasSourceMap(contents); 98 | assert.noCoverage(contents); 99 | assert.isBabelified(contents); 100 | }); 101 | 102 | assert.fileContents("typescript/dist", "hello-world.min.js", (contents) => { 103 | assert.noBanner(contents); 104 | assert.hasMinifiedPreamble(contents); 105 | assert.isMinified(contents); 106 | assert.hasSourceMap(contents); 107 | assert.noCoverage(contents); 108 | assert.isBabelified(contents); 109 | }); 110 | 111 | assert.fileContents("typescript/dist", "hello-world.coverage.js", (contents) => { 112 | assert.noBanner(contents); 113 | assert.hasMinifiedPreamble(contents); 114 | assert.isMinified(contents, true); 115 | assert.noSourceMap(contents); 116 | assert.hasCoverage(contents); 117 | assert.isBabelified(contents); 118 | }); 119 | 120 | assert.fileContents("typescript/dist", ["hello-world.js.map", "hello-world.min.js.map"], (contents) => { 121 | expect(contents.sources).to.contain.members([ 122 | "../src/hello-world.tsx", 123 | "../src/say/index.ts", 124 | ]); 125 | }); 126 | 127 | done(); 128 | }); 129 | }); 130 | 131 | it("should automatically enable TypeScript for all entry files that have a .ts or .tsx extenstion", (done) => { 132 | cli.run("typescript/src/**/*.ts* --bundle --minify --debug --coverage --outfile typescript/dist/", (err, stdout) => { 133 | if (err) { 134 | return done(err); 135 | } 136 | 137 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.js"); 138 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.js.map"); 139 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.min.js"); 140 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.min.js.map"); 141 | expect(stdout).to.contain("typescript/src/index.ts --> typescript/dist/index.coverage.js"); 142 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.js"); 143 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.js.map"); 144 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.min.js"); 145 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.min.js.map"); 146 | expect(stdout).to.contain("typescript/src/hello-world.tsx --> typescript/dist/hello-world.coverage.js"); 147 | expect(stdout).to.contain("typescript/src/say/index.ts --> typescript/dist/say/index.js"); 148 | expect(stdout).to.contain("typescript/src/say/index.ts --> typescript/dist/say/index.js.map"); 149 | expect(stdout).to.contain("typescript/src/say/index.ts --> typescript/dist/say/index.min.js"); 150 | expect(stdout).to.contain("typescript/src/say/index.ts --> typescript/dist/say/index.min.js.map"); 151 | expect(stdout).to.contain("typescript/src/say/index.ts --> typescript/dist/say/index.coverage.js"); 152 | 153 | assert.directoryContents("typescript/dist", [ 154 | "hello-world.coverage.js", 155 | "hello-world.js", 156 | "hello-world.js.map", 157 | "hello-world.min.js", 158 | "hello-world.min.js.map", 159 | "index.coverage.js", 160 | "index.js", 161 | "index.js.map", 162 | "index.min.js", 163 | "index.min.js.map", 164 | "say/index.coverage.js", 165 | "say/index.js", 166 | "say/index.js.map", 167 | "say/index.min.js", 168 | "say/index.min.js.map", 169 | ]); 170 | 171 | assert.fileContents("typescript/dist", ["index.js", "hello-world.js", "say/index.js"], (contents) => { 172 | assert.noBanner(contents); 173 | assert.notMinified(contents); 174 | assert.hasPreamble(contents); 175 | assert.hasSourceMap(contents); 176 | assert.noCoverage(contents); 177 | assert.isBabelified(contents); 178 | }); 179 | 180 | assert.fileContents("typescript/dist", ["index.min.js", "hello-world.min.js", "say/index.min.js"], (contents) => { 181 | assert.noBanner(contents); 182 | assert.hasMinifiedPreamble(contents); 183 | assert.isMinified(contents); 184 | assert.hasSourceMap(contents); 185 | assert.noCoverage(contents); 186 | assert.isBabelified(contents); 187 | }); 188 | 189 | assert.fileContents("typescript/dist", ["index.coverage.js", "hello-world.coverage.js", "say/index.coverage.js"], (contents) => { 190 | assert.noBanner(contents); 191 | assert.hasMinifiedPreamble(contents); 192 | assert.isMinified(contents, true); 193 | assert.noSourceMap(contents); 194 | assert.hasCoverage(contents); 195 | assert.isBabelified(contents); 196 | }); 197 | 198 | assert.fileContents("typescript/dist", ["index.js.map", "index.min.js.map"], (contents) => { 199 | expect(contents.sources).to.contain.members([ 200 | "../src/index.ts", 201 | "../src/hello-world.tsx", 202 | "../src/say/index.ts", 203 | ]); 204 | }); 205 | 206 | assert.fileContents("typescript/dist", ["hello-world.js.map", "hello-world.min.js.map"], (contents) => { 207 | expect(contents.sources).to.contain.members([ 208 | "../src/hello-world.tsx", 209 | "../src/say/index.ts", 210 | ]); 211 | }); 212 | 213 | assert.fileContents("typescript/dist", ["say/index.js.map", "say/index.min.js.map"], (contents) => { 214 | expect(contents.sources).to.contain.members([ 215 | "../../src/say/index.ts", 216 | ]); 217 | }); 218 | 219 | done(); 220 | }); 221 | }); 222 | 223 | it("should get TSify options from tsconfig.json", (done) => { 224 | cli.run("typescript-tsconfig/src/index.ts --bundle --minify --debug --coverage --outfile typescript-tsconfig/dist/", (err, stdout) => { 225 | if (err) { 226 | return done(err); 227 | } 228 | 229 | expect(stdout).to.contain("typescript-tsconfig/src/index.ts --> typescript-tsconfig/dist/index.js"); 230 | expect(stdout).to.contain("typescript-tsconfig/src/index.ts --> typescript-tsconfig/dist/index.js.map"); 231 | expect(stdout).to.contain("typescript-tsconfig/src/index.ts --> typescript-tsconfig/dist/index.min.js"); 232 | expect(stdout).to.contain("typescript-tsconfig/src/index.ts --> typescript-tsconfig/dist/index.min.js.map"); 233 | expect(stdout).to.contain("typescript-tsconfig/src/index.ts --> typescript-tsconfig/dist/index.coverage.js"); 234 | 235 | assert.directoryContents("typescript-tsconfig/dist", [ 236 | "index.js", 237 | "index.js.map", 238 | "index.min.js", 239 | "index.min.js.map", 240 | "index.coverage.js", 241 | ]); 242 | 243 | assert.fileContents("typescript-tsconfig/dist", "index.js", (contents) => { 244 | assert.noBanner(contents); 245 | assert.notMinified(contents); 246 | assert.hasPreamble(contents); 247 | assert.hasSourceMap(contents); 248 | assert.noCoverage(contents); 249 | assert.isBabelified(contents); 250 | }); 251 | 252 | assert.fileContents("typescript-tsconfig/dist", "index.min.js", (contents) => { 253 | assert.noBanner(contents); 254 | assert.hasMinifiedPreamble(contents); 255 | assert.isMinified(contents); 256 | assert.hasSourceMap(contents); 257 | assert.noCoverage(contents); 258 | assert.isBabelified(contents); 259 | }); 260 | 261 | assert.fileContents("typescript-tsconfig/dist", "index.coverage.js", (contents) => { 262 | assert.noBanner(contents); 263 | assert.hasMinifiedPreamble(contents); 264 | assert.isMinified(contents, true); 265 | assert.noSourceMap(contents); 266 | assert.hasCoverage(contents); 267 | assert.isBabelified(contents); 268 | }); 269 | 270 | assert.fileContents("typescript-tsconfig/dist", ["index.js.map", "index.min.js.map"], (contents) => { 271 | expect(contents.sources).to.contain.members([ 272 | "../src/hello-world.tsx", 273 | "../src/index.ts", 274 | "../src/say/index.ts" 275 | ]); 276 | }); 277 | 278 | done(); 279 | }); 280 | }); 281 | 282 | it("should get TSify options from package.json", (done) => { 283 | cli.run("typescript-options/src/index.ts --bundle --minify --debug --coverage --outfile typescript-options/dist/", (err, stdout) => { 284 | if (err) { 285 | return done(err); 286 | } 287 | 288 | expect(stdout).to.contain("typescript-options/src/index.ts --> typescript-options/dist/index.js"); 289 | expect(stdout).to.contain("typescript-options/src/index.ts --> typescript-options/dist/index.js.map"); 290 | expect(stdout).to.contain("typescript-options/src/index.ts --> typescript-options/dist/index.min.js"); 291 | expect(stdout).to.contain("typescript-options/src/index.ts --> typescript-options/dist/index.min.js.map"); 292 | expect(stdout).to.contain("typescript-options/src/index.ts --> typescript-options/dist/index.coverage.js"); 293 | 294 | assert.directoryContents("typescript-options/dist", [ 295 | "index.js", 296 | "index.js.map", 297 | "index.min.js", 298 | "index.min.js.map", 299 | "index.coverage.js", 300 | ]); 301 | 302 | assert.fileContents("typescript-options/dist", "index.js", (contents) => { 303 | assert.hasBanner(contents); 304 | assert.notMinified(contents); 305 | assert.hasPreamble(contents); 306 | assert.hasSourceMap(contents); 307 | assert.noCoverage(contents); 308 | assert.isBabelified(contents); 309 | }); 310 | 311 | assert.fileContents("typescript-options/dist", "index.min.js", (contents) => { 312 | assert.hasBanner(contents); 313 | assert.hasMinifiedPreamble(contents); 314 | assert.isMinified(contents); 315 | assert.hasSourceMap(contents); 316 | assert.noCoverage(contents); 317 | assert.isBabelified(contents); 318 | }); 319 | 320 | assert.fileContents("typescript-options/dist", "index.coverage.js", (contents) => { 321 | assert.hasBanner(contents); 322 | assert.hasMinifiedPreamble(contents); 323 | assert.isMinified(contents, true); 324 | assert.noSourceMap(contents); 325 | assert.hasCoverage(contents); 326 | assert.isBabelified(contents); 327 | }); 328 | 329 | assert.fileContents("typescript-options/dist", ["index.js.map", "index.min.js.map"], (contents) => { 330 | expect(contents.sources).to.contain.members([ 331 | "../src/hello-world.tsx", 332 | "../src/index.ts", 333 | "../src/say/index.ts" 334 | ]); 335 | }); 336 | 337 | done(); 338 | }); 339 | }); 340 | 341 | }); 342 | -------------------------------------------------------------------------------- /test/test-apps/error/error.js: -------------------------------------------------------------------------------- 1 | console.log('this is an error')) 2 | -------------------------------------------------------------------------------- /test/test-apps/es5/hello-world.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es5/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es5/lib/hello-world.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var say = require('./say'); 4 | 5 | /** 6 | * Says hello. 7 | * 8 | * @param {string} [name] - Who to say hello to 9 | */ 10 | module.exports = function hello(name) { 11 | // This is NOT an important comment 12 | say('hello', name || 'world'); 13 | }; 14 | -------------------------------------------------------------------------------- /test/test-apps/es5/lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @preserve This is an important comment 5 | */ 6 | module.exports = { 7 | say: require('./say'), 8 | hello: require('./hello-world') 9 | }; 10 | -------------------------------------------------------------------------------- /test/test-apps/es5/lib/say/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Says something to somebody. 5 | * 6 | * @param {string} what - What to say 7 | * @param {string} [who] - Who to say goodbye to 8 | */ 9 | module.exports = function say(what, who) { 10 | //! This is an important comment 11 | // This is NOT an important comment 12 | console.log('%s, %s!', what, who); 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /test/test-apps/es5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-package", 3 | "version": "0.0.1", 4 | "main": "lib/index.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/test-apps/es5/say/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/hello-world.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-package", 3 | "version": "0.0.1", 4 | "main": "lib/index.js", 5 | "browser": "src/index.js", 6 | "browserify": { 7 | "transform": [ 8 | ["babelify", { 9 | "presets": ["@babel/preset-env"] 10 | }] 11 | ] 12 | }, 13 | "devDependencies": { 14 | "@babel/preset-env": "^7.0.0", 15 | "babelify": "^10.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/say/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/src/hello-world.js: -------------------------------------------------------------------------------- 1 | import say from './say'; 2 | 3 | /** 4 | * Says hello. 5 | * 6 | * @param {string} [name] - Who to say hello to 7 | */ 8 | export default function hello(name) { 9 | // This is NOT an important comment 10 | let words = ['hello', name || world]; 11 | say(...words); 12 | } 13 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve This is an important comment 3 | */ 4 | import say from './say'; 5 | import hello from './hello-world'; 6 | 7 | export {say}; 8 | export {hello}; 9 | -------------------------------------------------------------------------------- /test/test-apps/es6-with-options/src/say/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Says something to somebody. 3 | * 4 | * @param {string} what - What to say 5 | * @param {string} [who] - Who to say goodbye to 6 | */ 7 | export default function say(what, who) { 8 | //! This is an important comment 9 | // This is NOT an important comment 10 | console.log(`${what} ${who}`); 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/es6/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /test/test-apps/es6/hello-world.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-package", 3 | "version": "0.0.1", 4 | "main": "lib/index.js", 5 | "browser": "src/index.js", 6 | "browserify": { 7 | "transform": [ 8 | ["babelify", { 9 | "presets": ["@babel/preset-env"] 10 | }] 11 | ] 12 | }, 13 | "devDependencies": { 14 | "@babel/preset-env": "^7.0.0", 15 | "babelify": "^10.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/test-apps/es6/say/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/es6/src/hello-world.js: -------------------------------------------------------------------------------- 1 | import say from './say'; 2 | 3 | /** 4 | * Says hello. 5 | * 6 | * @param {string} [name] - Who to say hello to 7 | */ 8 | export default function hello(name) { 9 | // This is NOT an important comment 10 | let words = ['hello', name || world]; 11 | say(...words); 12 | } 13 | -------------------------------------------------------------------------------- /test/test-apps/es6/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve This is an important comment 3 | */ 4 | import say from './say'; 5 | import hello from './hello-world'; 6 | 7 | export {say}; 8 | export {hello}; 9 | -------------------------------------------------------------------------------- /test/test-apps/es6/src/say/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Says something to somebody. 3 | * 4 | * @param {string} what - What to say 5 | * @param {string} [who] - Who to say goodbye to 6 | */ 7 | export default function say(what, who) { 8 | //! This is an important comment 9 | // This is NOT an important comment 10 | console.log(`${what} ${who}`); 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/hello/banner.txt: -------------------------------------------------------------------------------- 1 | <%= _.startCase(pkg.name) %> v<%= pkg.version %> (<%= moment().format('MMMM Do YYYY') %>) 2 | <%= pkg.description %> 3 | 4 | <%= pkg.homepage %> 5 | 6 | @author <%= pkg.author.name %> (<%= pkg.author.url %>) 7 | @license <%= pkg.license %> 8 | -------------------------------------------------------------------------------- /test/test-apps/hello/hello-world.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var say = require('./say'); 4 | 5 | /** 6 | * Says hello. 7 | * 8 | * @param {string} [name] - Who to say hello to 9 | */ 10 | module.exports = function hello(name) { 11 | // This is NOT an important comment 12 | say('hello', name || 'world'); 13 | }; 14 | -------------------------------------------------------------------------------- /test/test-apps/hello/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @preserve This is an important comment 5 | */ 6 | module.exports = { 7 | say: require('./say'), 8 | hello: require('./hello-world') 9 | }; 10 | -------------------------------------------------------------------------------- /test/test-apps/hello/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-world", 3 | "version": "1.23.456", 4 | "main": "index.js", 5 | "description": "Says hello... to the whole world", 6 | "author": { 7 | "name": "John Doe", 8 | "url": "http://john-doe-software.com" 9 | }, 10 | "license": "MIT", 11 | "homepage": "https://hello-world.com" 12 | } 13 | -------------------------------------------------------------------------------- /test/test-apps/hello/say/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Says something to somebody. 5 | * 6 | * @param {string} what - What to say 7 | * @param {string} [who] - Who to say goodbye to 8 | */ 9 | module.exports = function say(what, who) { 10 | //! This is an important comment 11 | // This is NOT an important comment 12 | console.log('%s, %s!', what, who); 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/hello-world.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-package", 3 | "version": "0.0.1", 4 | "main": "lib/index.js", 5 | "browser": "src/index.js", 6 | "browserify": { 7 | "transform": [ 8 | ["babelify", { 9 | "presets": ["@babel/preset-env"] 10 | }], 11 | ["uglifyify", { 12 | "mangle": false, 13 | "compress": false, 14 | "output": { 15 | "beautify": true, 16 | "indent_start": 2, 17 | "indent_level": 2, 18 | "quote_style": 1, 19 | "comments": true 20 | } 21 | }] 22 | ], 23 | "plugins": [ 24 | ["browserify-banner", { "template": "<%= pkg.name %> v<%= pkg.version %>" }] 25 | ] 26 | }, 27 | "devDependencies": { 28 | "@babel/preset-env": "^7.0.0", 29 | "babelify": "^10.0.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/say/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/src/hello-world.js: -------------------------------------------------------------------------------- 1 | import say from './say'; 2 | 3 | /** 4 | * Says hello. 5 | * 6 | * @param {string} [name] - Who to say hello to 7 | */ 8 | export default function hello(name) { 9 | // This is NOT an important comment 10 | let words = ['hello', name || world]; 11 | say(...words); 12 | } 13 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve This is an important comment 3 | */ 4 | import say from './say'; 5 | import hello from './hello-world'; 6 | 7 | export {say}; 8 | export {hello}; 9 | -------------------------------------------------------------------------------- /test/test-apps/transform-options/src/say/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Says something to somebody. 3 | * 4 | * @param {string} what - What to say 5 | * @param {string} [who] - Who to say goodbye to 6 | */ 7 | export default function say(what, who) { 8 | //! This is an important comment 9 | // This is NOT an important comment 10 | console.log(`${what} ${who}`); 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/typescript-error/error.ts: -------------------------------------------------------------------------------- 1 | // This is a syntax error because the "to" parameter doesn't have a type 2 | // and the "noImplicitAny" option is enabled in tsconfig.json 3 | function say(what: string, to): string { 4 | return `${what}, ${to}`; 5 | } 6 | -------------------------------------------------------------------------------- /test/test-apps/typescript-error/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "noImplicitAny": true 7 | }, 8 | "include": [ 9 | "*.ts" 10 | ], 11 | "exclude": [ 12 | "node_modules" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/hello-world.tsx: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/index.ts: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-package", 3 | "version": "0.0.1", 4 | "main": "lib/index.js", 5 | "browser": "src/index.js", 6 | "browserify": { 7 | "plugins": [ 8 | ["browserify-banner", { "template": "<%= pkg.name %> v<%= pkg.version %>" }], 9 | ["tsify", { 10 | "target": "esnext", 11 | "module": "commonjs", 12 | "moduleResolution": "node", 13 | "jsx": "react" 14 | }] 15 | ] 16 | }, 17 | "devDependencies": { 18 | "@babel/preset-env": "^7.0.0", 19 | "babelify": "^10.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/say/index.ts: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/src/hello-world.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import say from './say'; 3 | 4 | /** 5 | * Says hello. 6 | * 7 | * @param {string} [name] - Who to say hello to 8 | */ 9 | export function Hello(name: string = 'world') { 10 | // This is NOT an important comment 11 | let hello = say('hello', name); 12 | return
{hello}
; 13 | } 14 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/src/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve This is an important comment 3 | */ 4 | export { Hello } from './hello-world'; 5 | export * from './say'; 6 | -------------------------------------------------------------------------------- /test/test-apps/typescript-options/src/say/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Says something to somebody. 3 | * 4 | * @param {string} [what] - What to say 5 | * @param {string} [who] - Who to say it to 6 | */ 7 | export default function say(what: string, who: string): string { 8 | //! This is an important comment 9 | // This is NOT an important comment 10 | return `${what} ${who}`; 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/hello-world.tsx: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/index.ts: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/say/index.ts: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/src/hello-world.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import say from './say'; 3 | 4 | /** 5 | * Says hello. 6 | * 7 | * @param {string} [name] - Who to say hello to 8 | */ 9 | export function Hello(name: string = 'world') { 10 | // This is NOT an important comment 11 | let hello = say('hello', name); 12 | return
{hello}
; 13 | } 14 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/src/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve This is an important comment 3 | */ 4 | export { Hello } from './hello-world'; 5 | export * from './say'; 6 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/src/say/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Says something to somebody. 3 | * 4 | * @param {string} [what] - What to say 5 | * @param {string} [who] - Who to say it to 6 | */ 7 | export default function say(what: string, who: string): string { 8 | //! This is an important comment 9 | // This is NOT an important comment 10 | return `${what} ${who}`; 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/typescript-tsconfig/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "jsx": "react" 7 | }, 8 | "include": [ 9 | "src/**/*.ts", 10 | "src/**/*.tsx" 11 | ], 12 | "exclude": [ 13 | "node_modules" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /test/test-apps/typescript/hello-world.tsx: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript/index.ts: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript/say/index.ts: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript/src/hello-world.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import say from './say'; 3 | 4 | /** 5 | * Says hello. 6 | * 7 | * @param {string} [name] - Who to say hello to 8 | */ 9 | export function Hello(name: string = 'world') { 10 | // This is NOT an important comment 11 | let hello = say('hello', name); 12 | return
{hello}
; 13 | } 14 | -------------------------------------------------------------------------------- /test/test-apps/typescript/src/index.js: -------------------------------------------------------------------------------- 1 | If simplifyify's glob patterns are working properly, 2 | this file will NOT be included in the bundle 3 | -------------------------------------------------------------------------------- /test/test-apps/typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve This is an important comment 3 | */ 4 | export { Hello } from './hello-world'; 5 | export * from './say'; 6 | -------------------------------------------------------------------------------- /test/test-apps/typescript/src/say/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Says something to somebody. 3 | * 4 | * @param {string} [what] - What to say 5 | * @param {string} [who] - Who to say it to 6 | */ 7 | export default function say(what: string, who: string): string { 8 | //! This is an important comment 9 | // This is NOT an important comment 10 | return `${what} ${who}`; 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/universal-lib/banner.txt: -------------------------------------------------------------------------------- 1 | <%= _.startCase(pkg.name) %> v<%= pkg.version %> (<%= moment().format('MMMM Do YYYY') %>) 2 | 3 | <%= pkg.homepage %> 4 | 5 | @author <%= pkg.author.name %> (<%= pkg.author.url %>) 6 | @license <%= pkg.license %> 7 | -------------------------------------------------------------------------------- /test/test-apps/universal-lib/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "universal-lib", 3 | "main": "dist/universal-lib.js", 4 | "description": "A JavaScript library for Node.js and web browsers", 5 | "author": { 6 | "name": "John Doe", 7 | "url": "http://john-doe-software.com" 8 | }, 9 | "license": "MIT", 10 | "homepage": "https://hello-world.com" 11 | } 12 | -------------------------------------------------------------------------------- /test/test-apps/universal-lib/lib/browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var resolve = require('./resolve'); 4 | var cwd = getCurrentDirectory(); 5 | 6 | module.exports = { 7 | resolve: resolve.bind(null, cwd), 8 | }; 9 | 10 | /** 11 | * Gets the current directory in the web browser. 12 | * 13 | * @returns {string} 14 | */ 15 | function getCurrentDirectory () { 16 | var path = location.href; 17 | var segments = path.split('/'); 18 | var lastSegment = segments[segments.length - 1]; 19 | 20 | if (/\.\w+$/.test(lastSegment)) { 21 | // The URL is a file path (e.g. "http://example.com/dir/index.html") 22 | // So return all but the last segment (e.g. "http://example.com/dir/") 23 | segments.pop(); 24 | return segments.join('/') + '/'; 25 | } 26 | else { 27 | // The URL is a directory path (e.g. "http://example.com/dir") 28 | if (path[path.length - 1] === '/') { 29 | return path; 30 | } 31 | else { 32 | return path + '/'; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/test-apps/universal-lib/lib/node.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var resolve = require('./resolve'); 4 | var cwd = process.cwd() + '/'; 5 | 6 | module.exports = { 7 | resolve: resolve.bind(null, cwd), 8 | }; 9 | -------------------------------------------------------------------------------- /test/test-apps/universal-lib/lib/resolve.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = resolve; 4 | 5 | /** 6 | * Resolves a relative path to an absolute path 7 | * 8 | * @param {string} cwd - The current directory path (absolute) 9 | * @param {string} path - The relative path to resolve 10 | * @returns {string} 11 | */ 12 | function resolve (cwd, path) { 13 | //! This is an important comment 14 | // This is NOT an important comment 15 | return cwd + path; 16 | } 17 | -------------------------------------------------------------------------------- /test/test-apps/universal-lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "universal-lib", 3 | "version": "1.23.456", 4 | "main": "lib/index.js", 5 | "browser": "dist/universal-lib.js", 6 | "description": "A JavaScript library for Node.js and web browsers", 7 | "author": { 8 | "name": "John Doe", 9 | "url": "http://john-doe-software.com" 10 | }, 11 | "license": "MIT", 12 | "homepage": "https://hello-world.com" 13 | } 14 | --------------------------------------------------------------------------------