├── .editorconfig ├── .gitignore ├── .nvmrc ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build └── .gitkeep ├── docs └── in-depth.md ├── package-lock.json ├── package.json ├── src ├── Logo.png ├── acorn-benchmark.js ├── acorn-benchmark.test.js ├── babel-benchmark.js ├── babel-benchmark.test.js ├── babel-minify-benchmark.js ├── babel-minify-benchmarkt.test.js ├── babylon-benchmark.js ├── babylon-benchmark.test.js ├── bootstrap.js ├── buble-benchmark.js ├── buble-benchmark.test.js ├── chai-benchmark.js ├── chai-benchmark.test.js ├── cli-flags-helper.js ├── cli.js ├── coffeescript-benchmark.js ├── coffeescript-benchmark.test.js ├── espree-benchmark.js ├── espree-benchmark.test.js ├── esprima-benchmark.js ├── esprima-benchmark.test.js ├── index.html ├── jshint-benchmark.js ├── jshint-benchmark.test.js ├── lebab-benchmark.js ├── lebab-benchmark.test.js ├── mocks │ ├── dummy.js │ └── nested-rules.js ├── postcss-benchmark.js ├── postcss-benchmark.test.js ├── prepack-benchmark.js ├── prepack-benchmark.test.js ├── prettier-benchmark.js ├── prettier-benchmark.test.js ├── source-map-benchmark.js ├── source-map-benchmark.test.js ├── style.css ├── suite.js ├── terser-benchmark.js ├── terser-benchmark.test.js ├── typescript-benchmark.js ├── typescript-benchmark.test.js ├── uglify-js-benchmark.js ├── uglify-js-benchmark.test.js └── vfs.js ├── third_party ├── angular-material-1.1.8.css ├── backbone-1.1.0.js ├── bootstrap-4.0.0.css ├── coffeescript-lexer-2.0.1.coffee ├── foundation-6.4.2.css ├── jquery-3.2.1.js ├── lodash.core-4.17.4.js ├── lodash.min-4.17.4.js.map ├── mootools-core-1.6.0.js ├── preact-8.2.5.js ├── preact-8.2.5.js.map ├── redux.min-3.7.2.js ├── source-map.min-0.5.7.js.map ├── speedometer-es2015-test-2.0.js ├── todomvc │ ├── react │ │ ├── app.jsx │ │ ├── footer.jsx │ │ └── todoItem.jsx │ └── typescript-angular.ts ├── underscore-1.8.3.js ├── underscore.min-1.8.3.js.map └── vue.runtime.esm-nobuble-2.4.4.js ├── tools └── hooks │ └── pre-commit.js └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs. 2 | # More information at http://EditorConfig.org 3 | 4 | # No .editorconfig files above the root directory 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | dist/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "9" 5 | - "10" 6 | script: 7 | - npm run build 8 | - npm test 9 | - node dist/cli.js 10 | sudo: false 11 | branches: 12 | only: 13 | - master 14 | 15 | deploy: 16 | local_dir: dist 17 | email: bmeurer@chromium.org 18 | name: Benedikt Meurer 19 | project_name: web-tooling-benchmark 20 | provider: pages 21 | skip_cleanup: true 22 | github_token: $GITHUB_TOKEN # Set in travis-ci.org dashboard 23 | on: 24 | branch: master 25 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at benedikt.meurer@googlemail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome, no matter how large or small. Before 4 | contributing, please read the 5 | [code of conduct](https://github.com/v8/web-tooling-benchmark/blob/master/CODE_OF_CONDUCT.md). 6 | 7 | ## Setup locally 8 | 9 | > The Web Tooling Benchmark doesn't officially support any version of [Node](https://www.nodejs.org/) prior to Node 8, it currently works with Node 6 and Node 7, but that might change at any point in time. 10 | 11 | To start developing on the Web Tooling Benchmark you only need to install its dependencies: 12 | 13 | ```bash 14 | git clone https://github.com/v8/web-tooling-benchmark 15 | cd web-tooling-benchmark 16 | npm install 17 | ``` 18 | 19 | ## Tests 20 | 21 | There's no formal test suite yet. For now the process is roughly: 22 | 23 | - [ ] Check that `npm install` passes. 24 | - [ ] Check that `npm test` passes. 25 | - [ ] Check that the suite runs in `node`, via `node src/cli.js`. 26 | - [ ] Check that the suite runs in `d8` via `/path/to/d8 dist/cli.js`. 27 | - [ ] Check that the browser bundle works by pointing your browser to `dist/index.html`. 28 | 29 | ## Creating a new benchmark 30 | 31 | - Create a new issue that describes the motivation for including the benchmark. Include any relevant information. 32 | - The pull request should include: 33 | - [ ] An update to the [in-depth.md](https://github.com/v8/web-tooling-benchmark/blob/master/docs/in-depth.md) document. Add a new entry to that list for the new benchmark, which describes the tool and the concrete benchmark case. 34 | - [ ] Add a new file `src/foo-benchmark.js`, which includes the actual driver code for the benchmark (see the [`src/babylon-benchmark.js`](https://github.com/v8/web-tooling-benchmark/blob/master/src/babylon-benchmark.js) for example). 35 | - [ ] Add a new file `src/foo-benchmark.test.js`, which checks that the benchmark in `src/foo-benchmark.js` at least runs to completion. 36 | - [ ] `npm install --save-exact` any necessary dependencies, and be sure to include the `package.json` changes in your pull request. 37 | - [ ] Put any assets used by the benchmark into the `third_party` folder and hook them up with the virtual file system in `src/vfs.js`. 38 | 39 | Many of the steps above can be automated with the `npm run new-benchmark` script. It uses [`wtb-generate`](https://github.com/alopezsanchez/web-tooling-benchmark-generator), which is a CLI tool that automates some repetitive task when creating new benchmarks. 40 | 41 | ## Sign the CLA 42 | 43 | Before we can use your code you have to sign the [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual), which you can do online. This is mainly because you own the copyright to your changes, even after your contribution becomes part of our codebase, so we need your permission to use and distribute your code. We also need to be sure of various other things, for instance that you’ll tell us if you know that your code infringes on other people’s patents. You don’t have to do this until after you’ve submitted your code for review and a member has approved it, but you will have to do it before we can put your code into our codebase. 44 | 45 | Contributions made by corporations are covered by a different agreement than the one above, the [Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). 46 | 47 | Sign them online [here](https://cla.developers.google.com/). 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This license applies to all parts of web-tooling-benchmark that are not 2 | externally maintained libraries. The externally maintained libraries 3 | used by web-tooling-benchmark are: 4 | 5 | - The Backbone.js distribution, located in third_party/backbone-1.1.0.js. 6 | This is copyrighted by Jeremy Ashkenas, DocumentCloud, and released 7 | under the terms of the MIT license. 8 | 9 | - The lexer from the CoffeeScript project, located in 10 | third_party/coffeescript-lexer-2.0.1.coffee, which is copyrighted by 11 | Jeremy Ashkenas, and relased under the terms of the MIT license. 12 | 13 | - The jQuery distribution, located in third_party/jquery-3.2.1.js. This 14 | is copyrighted by the JS Foundation and other contributors, and 15 | released under the terms of the MIT license. 16 | 17 | - The Lodash distribution, located in third_party/lodash.core-4.17.4.js 18 | and third_party/lodash.min-4.17.4.js.map. This is copyrighted by 19 | the JS Foundation and other contributors, and released under the 20 | terms of the MIT license. 21 | 22 | - The MooTools distribution, located in third_party/mootools-core-1.6.0.js. 23 | This is copyrighted by Valerio Proietti, and released under the 24 | terms of the MIT license. 25 | 26 | - The Preact distribution, located in third_party/preact-8.2.5.js and 27 | third_party/preact-8.2.5.js.map. This is copyrighted by Jason Miller, 28 | and released under the terms of the MIT license. 29 | 30 | - The Redux distribution, located in third_party/redux.min-3.7.2.js. 31 | This is copyrighted by Dan Abramov, and released under the terms 32 | of the MIT license. 33 | 34 | - The source-map distribution, located in 35 | third_party/source-map.min-0.5.7.map. This is copyrighted by the 36 | Mozilla Foundation and contributors, and released under the terms 37 | of a 3-clause BSD license. 38 | 39 | - Several tests from the TodoMVC distribution, located in 40 | third_party/speedometer-es2015-test-2.0.js and third_party/todomvc. 41 | These are copyrighted by Addy Osmani, Sindre Sorhus, Pascal 42 | Hartig, Stephen Sawchuk, and released under the terms of the 43 | MIT license. 44 | 45 | - The Underscore.js distribution, located in 46 | third_party/underscore-1.8.3.js and 47 | third_party/underscore.min-1.8.3.js.map. This is copyrighted by 48 | Jeremy Ashkenas, and released under the terms of the MIT license. 49 | 50 | - The VueJS distribution, located in 51 | third_party/vue.runtime.esm-nobuble-2.4.4.js. This is copyrighted 52 | Yuxi (Evan) You, and released under the terms of the MIT license. 53 | 54 | These libraries have their own licenses; we recommend you read them, 55 | as their terms may differ from the terms below. 56 | 57 | Copyright 2017, the V8 project authors. All rights reserved. 58 | Redistribution and use in source and binary forms, with or without 59 | modification, are permitted provided that the following conditions are 60 | met: 61 | 62 | * Redistributions of source code must retain the above copyright 63 | notice, this list of conditions and the following disclaimer. 64 | * Redistributions in binary form must reproduce the above 65 | copyright notice, this list of conditions and the following 66 | disclaimer in the documentation and/or other materials provided 67 | with the distribution. 68 | * Neither the name of Google Inc. nor the names of its 69 | contributors may be used to endorse or promote products derived 70 | from this software without specific prior written permission. 71 | 72 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 73 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 74 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 75 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 76 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 77 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 78 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 79 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 80 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 81 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 82 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Tooling Benchmark 2 | 3 | [![Build Status](https://travis-ci.org/v8/web-tooling-benchmark.svg?branch=master)](https://travis-ci.org/v8/web-tooling-benchmark) [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 4 | 5 | This is a benchmark suite designed to measure the JavaScript-related 6 | workloads commonly used by web developers, such as the 7 | core workloads in popular tools like [Babel](https://github.com/babel/babel) 8 | or [TypeScript](https://github.com/Microsoft/TypeScript). The goal is to measure **only** the 9 | JavaScript performance aspect (which is affected by the JavaScript engine) and not measure I/O 10 | or other unrelated aspects. 11 | 12 | See the [in-depth 13 | analysis](https://github.com/v8/web-tooling-benchmark/blob/master/docs/in-depth.md) 14 | for a detailed description of the tests included in this benchmark suite. 15 | 16 | The latest browser version of the benchmark is available at 17 | . 18 | 19 | ## Support 20 | 21 | The Web Tooling Benchmark supports the latest [active 22 | LTS](https://github.com/nodejs/Release#release-schedule) version of Node.js. To see the supported 23 | Node.js versions of the current version of the benchmark, see [the `node_js` section of our CI 24 | configuration](https://github.com/v8/web-tooling-benchmark/blob/master/.travis.yml). 25 | 26 | ## Building 27 | 28 | To build the benchmark suite, run 29 | 30 | ``` 31 | $ npm install 32 | ``` 33 | 34 | assuming that you have a working [Node.js](https://nodejs.org) installation. Once 35 | the command is done, it produces a bundled version that is suitable to run in 36 | JS shells (i.e. `d8`, `jsc` or `jsshell`) in `dist/cli.js` and another bundle 37 | in `dist/browser.js` that is used by the browser version in `dist/index.html`. 38 | 39 | To build an individual benchmark rather than the entire suite, pass the `--env.only` 40 | CLI flag: 41 | 42 | ``` 43 | $ npm run build -- --env.only babel 44 | ``` 45 | 46 | ## Running 47 | 48 | You can either run the benchmark suite directly via [Node](https://nodejs.org/), 49 | i.e. like this: 50 | 51 | ``` 52 | $ node dist/cli.js 53 | Running Web Tooling Benchmark v0.5.2… 54 | ------------------------------------- 55 | acorn: 5.50 runs/s 56 | babel: 6.10 runs/s 57 | babel-minify: 9.13 runs/s 58 | babylon: 8.00 runs/s 59 | buble: 4.77 runs/s 60 | chai: 14.47 runs/s 61 | coffeescript: 5.62 runs/s 62 | espree: 4.05 runs/s 63 | esprima: 6.68 runs/s 64 | jshint: 7.84 runs/s 65 | lebab: 7.52 runs/s 66 | postcss: 5.06 runs/s 67 | prepack: 6.26 runs/s 68 | prettier: 5.97 runs/s 69 | source-map: 8.60 runs/s 70 | terser: 16.40 runs/s 71 | typescript: 10.04 runs/s 72 | uglify-js: 3.81 runs/s 73 | ------------------------------------- 74 | Geometric mean: 6.98 runs/s 75 | ``` 76 | 77 | Or you open a web browser and point it to `dist/index.html`, or you can use one 78 | of the engine JS shells to run the special bundle in `dist/cli.js`. The easiest 79 | way to install recent versions of the supported JS engine shells is to run 80 | [`jsvu`](https://github.com/GoogleChromeLabs/jsvu). Afterwards, you can run the 81 | benchmark as follows: 82 | 83 | ```sh 84 | $ chakra dist/cli.js 85 | $ javascriptcore dist/cli.js 86 | $ spidermonkey dist/cli.js 87 | $ v8 dist/cli.js 88 | ``` 89 | 90 | To run an individual benchmark rather than the entire suite via Node, pass the 91 | `--only` CLI flag: 92 | 93 | ``` 94 | $ npm run build -- --env.only babel && npm run benchmark 95 | ``` 96 | -------------------------------------------------------------------------------- /build/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v8/web-tooling-benchmark/4a12828c6a1eed02a70c011bd080445dd319a05f/build/.gitkeep -------------------------------------------------------------------------------- /docs/in-depth.md: -------------------------------------------------------------------------------- 1 | # In-depth Analysis 2 | 3 | The Web Tooling Benchmark contains interesting JavaScript workloads from a variety of 4 | commonly used web developer tools. It executes these core workloads a couple of times 5 | reports a single score at the end that balances them using geometric mean. 6 | 7 | Note that scores of different versions of the Web Tooling Benchmark are not comparable 8 | to each other. 9 | 10 | ## acorn 11 | 12 | [Acorn](https://github.com/ternjs/acorn) is a tiny, fast JavaScript parser, written 13 | completely in JavaScript. Acorn is the basis for many other JavaScript compiler 14 | and code analysis tools, i.e. [webpack](https://webpack.js.org) uses acorn and 15 | the [Babylon](https://github.com/babel/babylon) parser used by 16 | [Babel](http://babeljs.io) today is also based on acorn. 17 | 18 | This benchmarks runs the Acorn tokenizer, the parser and the full AST (Abstract 19 | Syntax Tree) walker on several popular inputs, including 20 | - the [Preact](https://github.com/developit/preact) 8.2.5 bundle, 21 | - the [lodash](https://lodash.com) 4.17.4 bundle, 22 | - the [underscore](http://underscorejs.org/) 1.8.3 bundle, 23 | - an ES2015 module containing the untranspiled [Vue](https://github.com/vuejs/vue) bundle, 24 | - the [jQuery](http://jquery.com) 3.2.1 distribution, 25 | - the minified [Redux](https://redux.js.org) 3.7.2 distribution, 26 | - the [Backbone.js](http://backbonejs.org) 1.1.0 bundle, 27 | - and the (concatenated) JavaScript source for the Vanilla ES2015 test in the [Speedometer](https://browserbench.org/Speedometer). 28 | 29 | ## babel 30 | 31 | [Babel](https://github.com/babel/babel) is a transpiler that compiles modern JavaScipt 32 | (i.e. ES2015 and later) to an older JavaScript dialect (i.e. ES3 or ES5) that is understood by a broad set of browsers. It's probably the most popular transpiler at 33 | this point in time and used in the vast majority of web projects nowadays. 34 | 35 | This benchmark runs the Babel transformation logic using the `es2015` preset on a 196KiB 36 | ES2015 module containing the untranspiled [Vue](https://github.com/vuejs/vue) bundle. 37 | Note that this explicitly excludes the [Babylon](https://github.com/babel/babylon) parser 38 | and only measures the throughput of the actual transformations. The parser is tested 39 | separately by the `babylon` benchmark below. 40 | 41 | ## babel-minify 42 | 43 | [Babel Minify](https://github.com/babel/minify) is an ES2015+ aware minifier based on the Babel toolchain. It is written as a set of Babel plugins. 44 | 45 | This benchmark stresses the babel minifier on the (concatenated) JavaScript source for the ES2015 test in the [Speedometer](https://browserbench.org/Speedometer) 2.0 benchmark. 46 | 47 | ## babylon 48 | 49 | [Babylon](https://github.com/babel/babylon) is the frontend for the Babel transpiler and 50 | deals with transforming the JavaScript input into a so-called AST (Abstract Syntax Tree) 51 | that can be consumed by the core transformation logic in Babel. It is built on top of 52 | [Acorn](https://github.com/ternjs/acorn) nowadays. 53 | 54 | This benchmark runs the Babylon parser on different popular inputs, including the 55 | [Preact](https://github.com/developit/preact) 8.2.5 bundle, the [lodash](https://lodash.com) 56 | 4.17.4 bundle, the JSX files from the React TodoMVC example app, the 57 | [underscore](http://underscorejs.org/) 1.8.3 bundle, an ES2015 module containing the 58 | untranspiled [Vue](https://github.com/vuejs/vue) bundle, the [jQuery](http://jquery.com) 59 | 3.2.1 distribution, the minified [Redux](https://redux.js.org) 3.7.2 distribution, and 60 | the (concatenated) JavaScript source for the Vanilla ES2015 test in the 61 | [Speedometer](https://browserbench.org/Speedometer). 62 | 63 | ## buble 64 | 65 | A test to stress the [Buble](https://github.com/Rich-Harris/buble) 66 | ES2015 compiler, both the parser and the actual transformation 67 | logic, on the same 196K ES2015 module containing the untranspiled 68 | [Vue](https://github.com/vuejs/vue) source code that is also used 69 | to stress by the `babel` and `babylon` tests. 70 | 71 | ## chai 72 | 73 | [Chai](http://chaijs.com) is a popular BDD / TDD assertion library for 74 | [Node](https://www.nodejs.org) and the browser that can be delightfully 75 | paired with any test driver framework for JavaScript. It is commonly used 76 | to write unit and integration tests. As such this test is not just a good 77 | benchmark for web tooling on the [Node](https://www.nodejs.org) side, but 78 | is also very relevant to the browser as tests often need to be run in the 79 | browser too. 80 | 81 | This benchmark is based on the test suite that comes with Chai and 82 | essentially uses the Chai BDD style interface to test the Chai library 83 | itself. 84 | 85 | ## coffeescript 86 | 87 | [CoffeeScript](http://coffeescript.org/) is a little language that attempts to expose 88 | the good parts of JavaScript in a simple way. At some point CoffeeScript was very 89 | popular. 90 | 91 | This benchmark runs the CoffeeScript compiler on the [`lexer.coffee`](https://github.com/v8/web-tooling-benchmark/blob/third_party/coffeescript-lexer-2.0.1.coffee) 92 | file from the CoffeeScript 2.0.1 distribution. 93 | 94 | ## espree 95 | 96 | [Espree](https://github.com/eslint/espree) started out as a fork of Esprima v1.2.2, 97 | the last stable published released of Esprima before work on ECMAScript 6 began. 98 | Espree is now built on top of Acorn, which has a modular architecture that allows 99 | extension of core functionality. The goal of Espree is to produce output that is 100 | similar to Esprima with a similar API so that it can be used in place of Esprima. 101 | The popular analysis framework [ESLint](https://eslint.org) is built on Espree 102 | today. 103 | 104 | This benchmark runs Espree on a several common scripts, including 105 | - the [Backbone.js](http://backbonejs.org) 1.1.0 bundle, 106 | - the [jQuery](http://jquery.com) 3.2.1 distribution, 107 | - the [MooTools](https://mootools.net) 1.6.0 bundle, 108 | - and the [underscore](http://underscorejs.org/) 1.8.3 bundle. 109 | 110 | ## esprima 111 | 112 | [Esprima](http://esprima.org) is a high performance, standard-compliant ECMAScript parser 113 | written in ECMAScript, which can be used to perform [lexical analysis](https://en.wikipedia.org/wiki/Lexical_analysis) 114 | (tokenization) or [syntactic analysis](https://en.wikipedia.org/wiki/Parsing) (parsing) 115 | of an ECMAScript program. Esprima was initially used as the basis for several tools like 116 | ESLint and Babel, and is still in use by a lot of analysis tools. 117 | 118 | This benchmark runs both the tokenizer and the parser on a variety of common scripts, 119 | including 120 | - the [Backbone.js](http://backbonejs.org) 1.1.0 bundle, 121 | - the [jQuery](http://jquery.com) 3.2.1 distribution, 122 | - the [MooTools](https://mootools.net) 1.6.0 bundle, 123 | - and the [underscore](http://underscorejs.org/) 1.8.3 bundle. 124 | 125 | ## jshint 126 | 127 | [JSHint](http://jshint.com) is a program that flags suspicious usage in programs written 128 | in JavaScript. At some point it was very popular, but nowadays it seems that many projects 129 | have switch or are switching to [ESLint](https://eslint.org). 130 | 131 | This benchmark runs JSHint on 132 | - the [lodash](https://lodash.com) 4.17.4 bundle, 133 | - the [Preact](http://preactjs.com) 8.2.5 bundle, 134 | - and the [underscore](http://underscorejs.org) 1.8.3 distribution. 135 | 136 | ## lebab 137 | 138 | [Lebab](https://github.com/lebab/lebab) transpiles your ES5 code to ES6/ES7, thus 139 | performing the opposite of what [Babel](https://github.com/babel/babel) does. 140 | 141 | This benchmark runs the Lebal ES5 to ES6/ES7 transpiler on the 142 | [Preact](http://preactjs.com) 8.2.5 bundle. 143 | 144 | ## postcss 145 | 146 | [PostCSS](https://github.com/postcss/postcss) is a tool for transforming styles with JS plugins. 147 | These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, 148 | inline images, and more. 149 | 150 | This benchmark runs the PostCSS processor with [Autoprefixer](https://github.com/postcss/autoprefixer) 151 | and [postcss-nested](https://github.com/postcss/postcss-nested) plugins on 152 | - the [Bootstrap](https://getbootstrap.com/) 4.0.0 bundle. 153 | - the [Foundation](https://foundation.zurb.com/) 6.4.2 bundle. 154 | - the [Angular Material](https://material.angularjs.org) 1.1.8 bundle. 155 | 156 | ## prepack 157 | 158 | [Prepack](https://prepack.io) is a tool that optimizes JavaScript source code: 159 | Computations that can be done at compile-time instead of run-time get eliminated. 160 | Prepack replaces the global code of a JavaScript bundle with equivalent code that 161 | is a simple sequence of assignments. This gets rid of most intermediate computations 162 | and object allocations. It currently focuses on React Native use cases. 163 | 164 | This benchmark runs prepack on both 165 | - the [Preact](https://github.com/developit/preact) 8.2.5 bundle (unminified) as well as 166 | - the [Redux](https://github.com/reactjs/redux) 3.7.2 bundle (minified). 167 | 168 | ## prettier 169 | 170 | [Prettier](https://github.com/prettier/prettier) is an opinionated code formatter 171 | which removes all the original styling and ensures that all outputted code conforms 172 | to a consistent style. It is often used in web projects today to automatically format 173 | JavaScript, HTML, CSS and other files. 174 | 175 | This benchmark runs prettier on different inputs, including 176 | - the [lodash](https://lodash.com) 4.17.4 bundle, 177 | - the [Preact](http://preactjs.com) 8.2.5 bundle, and 178 | - the JSX files from the React [todomvc](https://github.com/tastejs/todomvc) example app. 179 | 180 | ## source-map 181 | 182 | [Source Map](https://github.com/mozilla/source-map) is a library developed by Mozilla 183 | to generate and consume source maps, which in turn are used by browsers to display 184 | proper JavaScript when debugging a minified application. 185 | 186 | This benchmark stresses the source-map tool on both parsing and serializing a 187 | variety of different source maps, including the [Preact](http://preactjs.com) 188 | 8.2.5 source map. 189 | 190 | ## terser 191 | 192 | [terser](https://github.com/fabiosantoscode/terser) is a fork of `uglify-es` that retains API and CLI compatibility with `uglify-es` and `uglify-js@3`. 193 | 194 | This benchmark stresses the new ES2015-and-beyond minifier on the (concatenated) JavaScript source for the ES2015 test in the [Speedometer](https://browserbench.org/Speedometer) 2.0 benchmark. 195 | 196 | ## typescript 197 | 198 | [TypeScript](https://github.com/Microsoft/TypeScript) is a language for 199 | application-scale JavaScript. It adds optional types, classes, and modules 200 | to JavaScript, and compiles to readable, standards-based JavaScript. 201 | 202 | This benchmark stresses the TypeScript compiler by running it on the 203 | [`typescript-angular`](https://github.com/tastejs/todomvc/tree/master/examples/typescript-angular) 204 | example from [todomvc](https://github.com/tastejs/todomvc). 205 | 206 | ## uglify-js 207 | 208 | [UglifyJS](https://github.com/mishoo/UglifyJS2) is a JavaScript parser, minifier, 209 | compressor and beautifier toolkit, which is commonly used to minimize JavaScript 210 | bundles. 211 | 212 | This benchmark runs the UglifyJS minifier on the (concatenated) JavaScript source for 213 | the ES2015 test in the [Lodash](https://lodash.com) module. 214 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-tooling-benchmark", 3 | "description": "JavaScript benchmark for common web developer workloads", 4 | "version": "0.5.3", 5 | "repository": "https://github.com/v8/web-tooling-benchmark", 6 | "main": "src/cli.js", 7 | "scripts": { 8 | "benchmark": "node dist/cli.js", 9 | "build:terser-bundled": "node node_modules/terser/bin/uglifyjs -b preamble=\"'const Terser = module.exports = {};'\" --self > build/terser-bundled.js", 10 | "build:uglify-js-bundled": "node node_modules/uglify-js/bin/uglifyjs -b preamble=\"'const UglifyJS = module.exports = {};'\" --self > build/uglify-js-bundled.js", 11 | "build": "webpack", 12 | "postinstall": "npm run build:terser-bundled && npm run build:uglify-js-bundled && npm run build", 13 | "precommit": "node tools/hooks/pre-commit.js && lint-staged", 14 | "test": "jest", 15 | "update-lock": "npm install --package-lock", 16 | "new-benchmark": "wtb-generate" 17 | }, 18 | "lint-staged": { 19 | "src/**/*.css": [ 20 | "prettier --write", 21 | "git add" 22 | ], 23 | "src/**/*.js": [ 24 | "prettier --write", 25 | "git add" 26 | ], 27 | "webpack.config.js": [ 28 | "prettier --write", 29 | "git add" 30 | ] 31 | }, 32 | "browserslist": [ 33 | "Chrome 50", 34 | "Firefox 50" 35 | ], 36 | "author": { 37 | "name": "Benedikt Meurer", 38 | "email": "bmeurer@chromium.org", 39 | "url": "http://benediktmeurer.de" 40 | }, 41 | "license": "BSD-3-Clause", 42 | "dependencies": { 43 | "@babel/standalone": "7.0.0-beta.32", 44 | "acorn": "5.5.3", 45 | "autoprefixer": "8.2.0", 46 | "babel-minify": "0.4.3", 47 | "babylon": "7.0.0-beta.32", 48 | "benchmark": "^2.1.4", 49 | "buble": "0.19.3", 50 | "chai": "4.1.2", 51 | "coffeescript": "2.2.3", 52 | "compute-gmean": "^1.1.0", 53 | "espree": "3.5.4", 54 | "esprima": "4.0.0", 55 | "jshint": "2.9.7", 56 | "lebab": "2.7.7", 57 | "postcss": "6.0.21", 58 | "postcss-nested": "3.0.0", 59 | "prepack": "0.2.25", 60 | "prettier": "1.9.2", 61 | "source-map": "0.6.1", 62 | "string-align": "^0.2.0", 63 | "terser": "3.8.2", 64 | "typescript": "3.3.1", 65 | "uglify-js": "3.3.16", 66 | "virtualfs": "^2.1.0" 67 | }, 68 | "devDependencies": { 69 | "copy-webpack-plugin": "^4.2.0", 70 | "html-webpack-plugin": "^2.30.1", 71 | "husky": "^0.14.3", 72 | "jest": "^21.2.1", 73 | "lint-staged": "^4.3.0", 74 | "node-libs-browser": "^2.1.0", 75 | "os-browserify": "^0.3.0", 76 | "raw-loader": "github:bmeurer/raw-loader#escape", 77 | "semver": "^5.5.0", 78 | "web-tooling-benchmark-generator": "^1.0.2", 79 | "webpack": "^3.8.1" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v8/web-tooling-benchmark/4a12828c6a1eed02a70c011bd080445dd319a05f/src/Logo.png -------------------------------------------------------------------------------- /src/acorn-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const acorn = require("acorn"); 6 | const fs = require("fs"); 7 | const walk = require("acorn/dist/walk"); 8 | 9 | const payloads = [ 10 | { 11 | name: "backbone-1.1.0.js", 12 | options: { ecmaVersion: 5, sourceType: "script" } 13 | }, 14 | { 15 | name: "jquery-3.2.1.js", 16 | options: { ecmaVersion: 5, sourceType: "script" } 17 | }, 18 | { 19 | name: "lodash.core-4.17.4.js", 20 | options: { ecmaVersion: 5, sourceType: "script" } 21 | }, 22 | { 23 | name: "preact-8.2.5.js", 24 | options: { ecmaVersion: 5, sourceType: "script" } 25 | }, 26 | { 27 | name: "redux.min-3.7.2.js", 28 | options: { ecmaVersion: 5, sourceType: "script" } 29 | }, 30 | { 31 | name: "speedometer-es2015-test-2.0.js", 32 | options: { ecmaVersion: 6, sourceType: "script" } 33 | }, 34 | { 35 | name: "underscore-1.8.3.js", 36 | options: { ecmaVersion: 5, sourceType: "script" } 37 | }, 38 | { 39 | name: "vue.runtime.esm-nobuble-2.4.4.js", 40 | options: { ecmaVersion: 7, sourceType: "module" } 41 | } 42 | ].map(({ name, options }) => ({ 43 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 44 | options: Object.assign(options, { locations: true }, { ranges: true }) 45 | })); 46 | 47 | module.exports = { 48 | name: "acorn", 49 | fn() { 50 | return payloads.map(({ payload, options }) => { 51 | let count = 0; 52 | 53 | // Test the tokenizer by counting the resulting tokens. 54 | for (const token of acorn.tokenizer(payload, options)) { 55 | count++; 56 | } 57 | 58 | // Test the parser. 59 | const ast = acorn.parse(payload, options); 60 | 61 | // Test the AST walker. 62 | walk.full(ast, node => count++); 63 | return count; 64 | }); 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /src/acorn-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const acornBenchmark = require("./acorn-benchmark"); 6 | 7 | it("acorn-benchmark runs to completion", () => void acornBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/babel-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const Babel = require("@babel/standalone"); 6 | const babylon = require("babylon"); 7 | const fs = require("fs"); 8 | 9 | const payloads = [ 10 | { 11 | name: "vue.runtime.esm-nobuble-2.4.4.js", 12 | options: { presets: ["es2015"], sourceType: "module" } 13 | } 14 | ].map(({ name, options }) => { 15 | const code = fs.readFileSync(`third_party/${name}`, "utf8"); 16 | const ast = babylon.parse(code, options); 17 | return { ast, code, options }; 18 | }); 19 | 20 | module.exports = { 21 | name: "babel", 22 | fn() { 23 | return payloads.map(({ ast, code, options }) => 24 | Babel.transformFromAst(ast, code, options) 25 | ); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/babel-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const babelBenchmark = require("./babel-benchmark"); 6 | 7 | it("babel-benchmark runs to completion", () => void babelBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/babel-minify-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const babelMinify = require("babel-minify"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | { 10 | name: "speedometer-es2015-test-2.0.js", 11 | options: {} 12 | } 13 | ].map(({ name, options }) => ({ 14 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 15 | options 16 | })); 17 | 18 | module.exports = { 19 | name: "babel-minify", 20 | fn() { 21 | return payloads.map(({ payload, options }) => 22 | babelMinify(payload, options) 23 | ); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/babel-minify-benchmarkt.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const babelMinifyBenchmark = require("./babel-minify-benchmark"); 6 | 7 | it("babel-minify-benchmark runs to completion", () => 8 | void babelMinifyBenchmark.fn()); 9 | -------------------------------------------------------------------------------- /src/babylon-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const babylon = require("babylon"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | { 10 | name: "jquery-3.2.1.js", 11 | options: { sourceType: "script" } 12 | }, 13 | { 14 | name: "lodash.core-4.17.4.js", 15 | options: { sourceType: "script" } 16 | }, 17 | { 18 | name: "preact-8.2.5.js", 19 | options: { sourceType: "script" } 20 | }, 21 | { 22 | name: "redux.min-3.7.2.js", 23 | options: { sourceType: "script" } 24 | }, 25 | { 26 | name: "speedometer-es2015-test-2.0.js", 27 | options: { sourceType: "script" } 28 | }, 29 | { 30 | name: "todomvc/react/app.jsx", 31 | options: { sourceType: "script", plugins: ["jsx"] } 32 | }, 33 | { 34 | name: "todomvc/react/footer.jsx", 35 | options: { sourceType: "script", plugins: ["jsx"] } 36 | }, 37 | { 38 | name: "todomvc/react/todoItem.jsx", 39 | options: { sourceType: "script", plugins: ["jsx"] } 40 | }, 41 | { 42 | name: "underscore-1.8.3.js", 43 | options: { sourceType: "script" } 44 | }, 45 | { 46 | name: "vue.runtime.esm-nobuble-2.4.4.js", 47 | options: { sourceType: "module" } 48 | } 49 | ].map(({ name, options }) => ({ 50 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 51 | options 52 | })); 53 | 54 | module.exports = { 55 | name: "babylon", 56 | fn() { 57 | return payloads.map(({ payload, options }) => 58 | babylon.parse(payload, options) 59 | ); 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /src/babylon-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const babylonBenchmark = require("./babylon-benchmark"); 6 | 7 | it("babylon-benchmark runs to completion", () => void babylonBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/bootstrap.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const gmean = require("compute-gmean"); 6 | const package = require("../package.json"); 7 | const suite = require("./suite"); 8 | 9 | function displayStatusMessage(message) { 10 | const element = document.getElementById("status"); 11 | element.innerHTML = `${message}`; 12 | } 13 | 14 | function displayResultMessage(name, message, style) { 15 | const element = document.getElementById("results-cell-" + name); 16 | element.innerHTML = message || "—"; 17 | if (element.classList) { 18 | element.classList.remove("result"); 19 | element.classList.remove("highlighted-result"); 20 | element.classList.add(style); 21 | } else { 22 | element.className = style; 23 | } 24 | } 25 | 26 | function reset() { 27 | const resultSummaryDiv = document.getElementById("result-summary"); 28 | resultSummaryDiv.textContent = ""; 29 | 30 | const benchmarks = []; 31 | suite.forEach(benchmark => benchmarks.push(benchmark)); 32 | 33 | const numColumns = 2; 34 | const columnHeight = Math.ceil((benchmarks.length + 1) / numColumns); 35 | const resultsTable = document.getElementById("results"); 36 | let text = 37 | "" + "BenchmarkRuns/Sec".repeat(numColumns) + ""; 38 | for (let i = 0; i < columnHeight; ++i) { 39 | text += ""; 40 | for (let j = 0; j < numColumns; ++j) { 41 | const index = j * columnHeight + i; 42 | if (index > benchmarks.length) break; 43 | if (index == benchmarks.length) { 44 | text += `Geometric Mean`; 45 | text += `—`; 46 | } else { 47 | const benchmark = benchmarks[index]; 48 | text += ``; 49 | text += `${benchmark.name}`; 52 | text += `—`; 55 | } 56 | } 57 | text += ""; 58 | } 59 | resultsTable.innerHTML = text; 60 | } 61 | 62 | function initialize() { 63 | reset(); 64 | 65 | document.title = `Web Tooling Benchmark v${package.version}`; 66 | 67 | const versionDiv = document.getElementById("version"); 68 | versionDiv.innerHTML = `v${package.version}`; 69 | 70 | const statusDiv = document.getElementById("status"); 71 | statusDiv.innerHTML = `Start test`; 72 | statusDiv.firstChild.onclick = start; 73 | } 74 | 75 | function start() { 76 | reset(); 77 | 78 | const statusDiv = document.getElementById("status"); 79 | statusDiv.innerHTML = "Running test suite\u2026"; 80 | suite.run({ async: true }); 81 | } 82 | 83 | window.onerror = () => { 84 | // TODO(bmeurer): Provide some sane error page here. 85 | console.log("SOMETHING WENT WRONG!"); 86 | }; 87 | window.onload = initialize; 88 | 89 | // Helpers for automated runs in Telemetry/Catapult. 90 | window.automated = { 91 | // Set to true when the whole suite is completed. 92 | completed: false, 93 | // The result array of {name, score} pairs. 94 | results: [], 95 | // The function that starts the run. 96 | start 97 | }; 98 | 99 | suite.forEach(benchmark => { 100 | benchmark.on("start", event => { 101 | if (suite.aborted) return; 102 | displayResultMessage( 103 | benchmark.name, 104 | "Running...", 105 | "highlighted-result" 106 | ); 107 | displayStatusMessage(`Running iteration 1 of ${benchmark.name}...`); 108 | }); 109 | benchmark.on("cycle", event => { 110 | if (suite.aborted) return; 111 | const iteration = benchmark.stats.sample.length + 1; 112 | displayStatusMessage( 113 | `Running iteration ${iteration} of ${benchmark.name}...` 114 | ); 115 | }); 116 | benchmark.on("complete", event => { 117 | if (suite.aborted) return; 118 | displayResultMessage( 119 | benchmark.name, 120 | `${benchmark.hz.toFixed(2)}`, 121 | "result" 122 | ); 123 | const iterations = benchmark.stats.sample.length; 124 | displayStatusMessage( 125 | `Ran ${iterations} iterations of ${benchmark.name}...` 126 | ); 127 | }); 128 | }); 129 | 130 | suite.on("complete", event => { 131 | window.automated.completed = true; 132 | if (suite.aborted) return; 133 | const hz = gmean(suite.map(benchmark => benchmark.hz)); 134 | window.automated.results = suite.map(benchmark => { 135 | return { name: benchmark.name, score: benchmark.hz }; 136 | }); 137 | window.automated.results.push({ name: "total", score: hz }); 138 | displayResultMessage("geomean", `${hz.toFixed(2)}`, "highlighted-result"); 139 | 140 | const statusDiv = document.getElementById("status"); 141 | statusDiv.innerHTML = `Test again`; 142 | statusDiv.firstChild.onclick = start; 143 | 144 | const resultSummaryDiv = document.getElementById("result-summary"); 145 | resultSummaryDiv.innerHTML = `
${hz.toFixed( 146 | 2 147 | )}`; 148 | }); 149 | 150 | suite.on("error", event => { 151 | window.automated.completed = true; 152 | const benchmark = event.target; 153 | const error = benchmark.error; 154 | const name = benchmark.name; 155 | document.body.innerHTML = `

ERROR

Encountered errors during execution of ${name} test. Refusing to run a partial benchmark suite.

${
156 |     error.stack
157 |   }
`; 158 | console.error(error); 159 | suite.abort(); 160 | }); 161 | -------------------------------------------------------------------------------- /src/buble-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const buble = require("buble"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | { 10 | name: "vue.runtime.esm-nobuble-2.4.4.js", 11 | options: {} 12 | } 13 | ].map(({ name, options }) => ({ 14 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 15 | options: { transforms: { modules: false } } 16 | })); 17 | 18 | module.exports = { 19 | name: "buble", 20 | fn() { 21 | return payloads.map(({ payload, options }) => 22 | buble.transform(payload, options) 23 | ); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/buble-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const bubleBenchmark = require("./buble-benchmark"); 6 | 7 | it("buble-benchmark runs to completion", () => void bubleBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/chai-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const chaiBenchmark = require("./chai-benchmark"); 6 | 7 | it("chai-benchmark runs to completion", () => void chaiBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/cli-flags-helper.js: -------------------------------------------------------------------------------- 1 | const targetList = new Set([ 2 | "acorn", 3 | "babel", 4 | "babel-minify", 5 | "babylon", 6 | "buble", 7 | "chai", 8 | "coffeescript", 9 | "espree", 10 | "esprima", 11 | "jshint", 12 | "lebab", 13 | "postcss", 14 | "prepack", 15 | "prettier", 16 | "source-map", 17 | "terser", 18 | "typescript", 19 | "uglify-js" 20 | ]); 21 | 22 | function getOnlyFlag() { 23 | const onlyIndex = process.argv.indexOf("--only"); 24 | if (onlyIndex != -1) { 25 | return process.argv[onlyIndex + 1]; 26 | } 27 | } 28 | 29 | module.exports = { 30 | getTarget: () => { 31 | const onlyArg = getOnlyFlag(); 32 | if (targetList.has(onlyArg)) { 33 | return [onlyArg]; 34 | } else if (typeof ONLY != "undefined" && targetList.has(ONLY)) { 35 | return [ONLY]; 36 | } else { 37 | return [...targetList]; 38 | } 39 | }, 40 | targetList: targetList 41 | }; 42 | -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const align = require("string-align"); 6 | const gmean = require("compute-gmean"); 7 | const packageJson = require("../package.json"); 8 | const suite = require("./suite"); 9 | 10 | console.log(`Running Web Tooling Benchmark v${packageJson.version}…`); 11 | console.log("-------------------------------------"); 12 | 13 | suite.on("error", event => { 14 | const benchmark = event.target; 15 | const name = benchmark.name; 16 | const error = benchmark.error; 17 | console.log(`Encountered error running benchmark ${name}, aborting…`); 18 | console.log(error.stack); 19 | suite.abort(); 20 | }); 21 | 22 | suite.on("cycle", event => { 23 | if (suite.aborted) return; 24 | const benchmark = event.target; 25 | const name = benchmark.name; 26 | const hz = benchmark.hz; 27 | const stats = benchmark.stats; 28 | console.log( 29 | `${align(name, 14, "right")}: ${align(hz.toFixed(2), 5, "right")} runs/s` 30 | ); 31 | }); 32 | 33 | suite.on("complete", event => { 34 | if (suite.aborted) return; 35 | const hz = gmean(suite.map(benchmark => benchmark.hz)); 36 | console.log("-------------------------------------"); 37 | console.log(`Geometric mean: ${align(hz.toFixed(2), 5, "right")} runs/s`); 38 | }); 39 | 40 | suite.run(); 41 | -------------------------------------------------------------------------------- /src/coffeescript-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const CoffeeScript = require("coffeescript"); 6 | const fs = require("fs"); 7 | 8 | const input = fs.readFileSync( 9 | "third_party/coffeescript-lexer-2.0.1.coffee", 10 | "utf8" 11 | ); 12 | 13 | module.exports = { 14 | name: "coffeescript", 15 | fn() { 16 | return CoffeeScript.compile(input); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/coffeescript-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const coffeescriptBenchmark = require("./coffeescript-benchmark"); 6 | 7 | it("coffeescript-benchmark runs to completion", () => 8 | void coffeescriptBenchmark.fn()); 9 | -------------------------------------------------------------------------------- /src/espree-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const espree = require("espree"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | "backbone-1.1.0.js", 10 | "jquery-3.2.1.js", 11 | "mootools-core-1.6.0.js", 12 | "underscore-1.8.3.js" 13 | ].map(name => fs.readFileSync(`third_party/${name}`, "utf8")); 14 | 15 | module.exports = { 16 | name: "espree", 17 | fn() { 18 | return payloads.map(payload => { 19 | let count = 0; 20 | count += espree.tokenize(payload, { loc: true, range: true }).length; 21 | count += espree.parse(payload, { loc: true, range: true }).body.length; 22 | return count; 23 | }); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/espree-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const espreeBenchmark = require("./espree-benchmark"); 6 | 7 | it("espree-benchmark runs to completion", () => void espreeBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/esprima-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const esprima = require("esprima"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | "backbone-1.1.0.js", 10 | "jquery-3.2.1.js", 11 | "mootools-core-1.6.0.js", 12 | "underscore-1.8.3.js" 13 | ].map(name => fs.readFileSync(`third_party/${name}`, "utf8")); 14 | 15 | module.exports = { 16 | name: "esprima", 17 | fn() { 18 | return payloads.map(payload => { 19 | let count = 0; 20 | count += esprima.tokenize(payload, { loc: true, range: true }).length; 21 | count += esprima.parse(payload, { loc: true, range: true }).body.length; 22 | return count; 23 | }); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/esprima-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const esprimaBenchmark = require("./esprima-benchmark"); 6 | 7 | it("esprima-benchmark runs to completion", () => void esprimaBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | Web Tooling Benchmark 12 | 13 | <%=htmlWebpackPlugin.files.webpackManifest%> 14 | 15 | 16 | 17 |
18 | 19 | 20 |

21 | The Web Tooling Benchmark is a performance test suite focused on JavaScript related workloads found 22 | in common web developer tools these days. For more information, read the 23 | in-depth 24 | analysis. Bigger scores are better. 25 |

26 | 27 |
28 |
Start test
29 | 30 |
31 | 32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/jshint-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const fs = require("fs"); 6 | const jshint = require("jshint"); 7 | 8 | const inputs = [ 9 | "lodash.core-4.17.4.js", 10 | "preact-8.2.5.js", 11 | "underscore-1.8.3.js" 12 | ].map(name => fs.readFileSync(`third_party/${name}`, "utf8")); 13 | 14 | module.exports = { 15 | name: "jshint", 16 | fn() { 17 | return inputs.forEach(input => jshint.JSHINT(input)); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/jshint-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const jshintBenchmark = require("./jshint-benchmark"); 6 | 7 | it("jshint-benchmark runs to completion", () => void jshintBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/lebab-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const fs = require("fs"); 6 | const lebab = require("lebab"); 7 | 8 | const payloads = [ 9 | { 10 | name: "preact-8.2.5.js", 11 | options: [ 12 | "arg-rest", 13 | "arg-spread", 14 | "arrow", 15 | "class", 16 | "for-of", 17 | "let", 18 | "template", 19 | "includes", 20 | "obj-method", 21 | "obj-shorthand" 22 | ] 23 | } 24 | ].map(({ name, options }) => ({ 25 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 26 | options 27 | })); 28 | 29 | module.exports = { 30 | name: "lebab", 31 | fn() { 32 | return payloads.map(({ payload, options }) => 33 | lebab.transform(payload, options) 34 | ); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/lebab-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const lebabBenchmark = require("./lebab-benchmark"); 6 | 7 | it("lebab-benchmark runs to completion", () => void lebabBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/mocks/dummy.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | module.exports = {}; 6 | -------------------------------------------------------------------------------- /src/mocks/nested-rules.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | module.exports = ` 6 | .phone { 7 | &_title { 8 | width: 500px; 9 | @media (max-width: 500px) { 10 | width: auto; 11 | } 12 | body.is_dark & { 13 | color: white; 14 | } 15 | } 16 | img { 17 | display: block; 18 | } 19 | }`; 20 | -------------------------------------------------------------------------------- /src/postcss-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const fs = require("fs"); 6 | const postcss = require("postcss"); 7 | const nested = require("postcss-nested"); 8 | const autoprefixer = require("autoprefixer"); 9 | 10 | const nestedRules = require("./mocks/nested-rules"); 11 | 12 | const cleaner = postcss([autoprefixer({ add: false, browsers: [] })]); 13 | const processor = postcss([autoprefixer, nested]); 14 | 15 | const payloads = [ 16 | { 17 | name: "bootstrap-4.0.0.css", 18 | options: { from: `third_party/${this.name}`, map: false } 19 | }, 20 | { 21 | name: "foundation-6.4.2.css", 22 | options: { from: `third_party/${this.name}`, map: false } 23 | }, 24 | { 25 | name: "angular-material-1.1.8.css", 26 | options: { from: `third_party/${this.name}`, map: false } 27 | } 28 | ].map(({ name, options }) => { 29 | // Clean prefixes. 30 | const source = fs.readFileSync(`third_party/${name}`, "utf8"); 31 | // Add some nested rules. 32 | const css = cleaner.process(source).css + nestedRules; 33 | 34 | return { 35 | payload: css, 36 | options 37 | }; 38 | }); 39 | 40 | module.exports = { 41 | name: "postcss", 42 | fn() { 43 | return payloads.map( 44 | ({ payload, options }) => processor.process(payload, options).css 45 | ); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /src/postcss-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const postcssBenchmark = require("./postcss-benchmark"); 6 | 7 | it("postcss-benchmark runs to completion", () => void postcssBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/prepack-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const fs = require("fs"); 6 | const prepack = require("prepack"); 7 | 8 | const sourceFiles = [ 9 | "third_party/preact-8.2.5.js", 10 | "third_party/redux.min-3.7.2.js" 11 | ].map(filePath => ({ 12 | filePath, 13 | fileContents: fs.readFileSync(filePath, "utf8") 14 | })); 15 | 16 | module.exports = { 17 | name: "prepack", 18 | fn() { 19 | return prepack.prepackSources(sourceFiles); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/prepack-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const prepackBenchmark = require("./prepack-benchmark"); 6 | 7 | it("prepack-benchmark runs to completion", () => void prepackBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/prettier-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const fs = require("fs"); 6 | const prettier = require("prettier"); 7 | 8 | const payloads = [ 9 | { 10 | name: "preact-8.2.5.js", 11 | options: { semi: false, useTabs: false } 12 | }, 13 | { 14 | name: "lodash.core-4.17.4.js", 15 | options: { semi: true, useTabs: true } 16 | }, 17 | { 18 | name: "todomvc/react/app.jsx", 19 | options: { semi: false, useTabs: true } 20 | }, 21 | { 22 | name: "todomvc/react/footer.jsx", 23 | options: { jsxBracketSameLine: true, semi: true, useTabs: true } 24 | }, 25 | { 26 | name: "todomvc/react/todoItem.jsx", 27 | options: { semi: false, singleQuote: true, useTabs: true } 28 | } 29 | ].map(({ name, options }) => ({ 30 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 31 | options 32 | })); 33 | 34 | module.exports = { 35 | name: "prettier", 36 | fn() { 37 | return payloads.map(({ payload, options }) => 38 | prettier.format(payload, options) 39 | ); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /src/prettier-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const prettierBenchmark = require("./prettier-benchmark"); 6 | 7 | it("prettier-benchmark runs to completion", () => void prettierBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/source-map-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const sourceMap = require("source-map"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | "lodash.min-4.17.4.js.map", 10 | "preact-8.2.5.js.map", 11 | "source-map.min-0.5.7.js.map", 12 | "underscore.min-1.8.3.js.map" 13 | ].map(name => fs.readFileSync(`third_party/${name}`, "utf8")); 14 | 15 | module.exports = { 16 | name: "source-map", 17 | fn() { 18 | payloads.forEach(payload => { 19 | // Parse the source map first... 20 | const smc = new sourceMap.SourceMapConsumer(payload); 21 | // ...then serialize the parsed source map to a String. 22 | const smg = sourceMap.SourceMapGenerator.fromSourceMap(smc); 23 | 24 | // Create a SourceNode from the generated code and a SourceMapConsumer. 25 | const fswsm = sourceMap.SourceNode.fromStringWithSourceMap(payload, smc); 26 | 27 | return [smg.toString(), fswsm.toString()]; 28 | }); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/source-map-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const sourceMapBenchmark = require("./source-map-benchmark"); 6 | 7 | it("source-map-benchmark runs to completion", () => 8 | void sourceMapBenchmark.fn()); 9 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2017 the V8 project authors. All rights reserved. 3 | * Use of this source code is governed by a BSD-style license that can be 4 | * found in the LICENSE file. 5 | */ 6 | 7 | body { 8 | font-family: Roboto, Helvetica, Verdana, sans-serif; 9 | font-size: 16px; 10 | line-height: 19px; 11 | padding-bottom: 00px; 12 | } 13 | 14 | body main { 15 | display: block; 16 | width: 850px; 17 | margin: auto; 18 | text-align: center; 19 | padding: 10px; 20 | } 21 | 22 | ::selection { 23 | background-color: rgb(19, 156, 7); 24 | color: white; 25 | } 26 | 27 | p.summary { 28 | margin: 18px auto 5px; 29 | background-image: -webkit-linear-gradient( 30 | right, 31 | white 70%, 32 | rgba(255, 255, 255, 0) 33 | ); 34 | background-image: -moz-linear-gradient( 35 | right, 36 | white 70%, 37 | rgba(255, 255, 255, 0) 38 | ); 39 | background-image: linear-gradient( 40 | to right, 41 | white 70%, 42 | rgba(255, 255, 255, 0) 43 | ); 44 | padding: 15px 125px 0; 45 | text-align: center; 46 | } 47 | 48 | h1 { 49 | color: rgb(19, 156, 7); 50 | text-align: left; 51 | margin-top: 40px; 52 | } 53 | 54 | p { 55 | text-align: left; 56 | text-indent: 20px; 57 | } 58 | 59 | p:first-of-type { 60 | text-indent: 0; 61 | } 62 | 63 | div#status { 64 | margin-top: 20px; 65 | height: 20px; 66 | } 67 | 68 | div#status a:link { 69 | font-weight: bold; 70 | } 71 | 72 | div#result-summary:empty { 73 | display: none; 74 | } 75 | 76 | div#result-summary { 77 | margin-top: 20px; 78 | } 79 | 80 | div#result-summary label { 81 | font-weight: bold; 82 | } 83 | 84 | div#result-summary .score { 85 | font-weight: bold; 86 | font-size: 48px; 87 | line-height: 48px; 88 | color: rgb(19, 156, 7); 89 | } 90 | 91 | div#result-summary .score { 92 | display: block; 93 | font-size: 18px; 94 | line-height: 18px; 95 | font-weight: normal; 96 | } 97 | 98 | div#version { 99 | margin-top: 60px; 100 | font-size: 12px; 101 | font-style: italic; 102 | color: darkgrey; 103 | } 104 | 105 | a:link, 106 | a:visited { 107 | color: rgb(19, 156, 7); 108 | text-decoration: none; 109 | } 110 | 111 | a:link:hover { 112 | text-decoration: underline; 113 | } 114 | 115 | table#results { 116 | border-spacing: 0; 117 | border-collapse: collapse; 118 | margin-top: 15px; 119 | width: 100%; 120 | table-layout: fixed; 121 | } 122 | 123 | td, 124 | th { 125 | padding: 4px 8px; 126 | } 127 | 128 | th { 129 | font-size: 14px; 130 | } 131 | 132 | tr:first-child > th:nth-child(odd):not(:first-child) { 133 | border-left: 15px solid white; 134 | } 135 | 136 | tr:first-child > th:nth-child(odd) { 137 | text-align: left; 138 | } 139 | 140 | tr:first-child > th:nth-child(even) { 141 | width: px; 142 | } 143 | 144 | tr:nth-child(even):not(:first-child) { 145 | background-color: rgb(238, 247, 238); 146 | } 147 | 148 | .result { 149 | color: rgb(19, 156, 7); 150 | white-space: nowrap; 151 | } 152 | 153 | .highlighted-result { 154 | background-color: rgb(19, 156, 7); 155 | color: white; 156 | } 157 | 158 | .benchmark-name { 159 | text-align: left; 160 | white-space: nowrap; 161 | } 162 | 163 | .geometric-mean, 164 | .benchmark-name.category, 165 | .result.category { 166 | font-weight: bold; 167 | } 168 | 169 | .benchmark-name:not(.category):not(.geometric-mean) { 170 | text-indent: 0.5em; 171 | } 172 | 173 | .benchmark-name:not(:first-child) { 174 | border-left: 15px solid white; 175 | } 176 | 177 | .benchmark-name a:link, 178 | .benchmark-name a:visited { 179 | color: black; 180 | } 181 | -------------------------------------------------------------------------------- /src/suite.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const Benchmark = require("benchmark"); 6 | const getTarget = require("./cli-flags-helper").getTarget; 7 | 8 | // We need to run deterministically, so we set 'maxTime' to 0, which 9 | // disables the variable iteration count feature of benchmark.js, 10 | // and specify 'minSamples' as 20 to have it collect exactly 20 11 | // samples. We leave the 'initCount' to the default of 1. See 12 | // https://github.com/v8/web-tooling-benchmark/issues/6 for details. 13 | const defaultOptions = { 14 | maxTime: 0, 15 | minSamples: 20 16 | }; 17 | 18 | const suite = new Benchmark.Suite(); 19 | 20 | getTarget().forEach(target => { 21 | suite.add( 22 | Object.assign({}, require(`./${target}-benchmark`), defaultOptions) 23 | ); 24 | }); 25 | 26 | module.exports = suite; 27 | -------------------------------------------------------------------------------- /src/terser-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const Terser = require("../build/terser-bundled"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | { 10 | name: "speedometer-es2015-test-2.0.js", 11 | options: { compress: { passes: 1, sequences: false } } 12 | } 13 | ].map(({ name, options }) => ({ 14 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 15 | options 16 | })); 17 | 18 | module.exports = { 19 | name: "terser", 20 | fn() { 21 | return payloads.map(({ payload, options }) => 22 | Terser.minify(payload, options) 23 | ); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/terser-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const terserBenchmark = require("./terser-benchmark"); 6 | 7 | it("terser-benchmark runs to completion", () => void terserBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/typescript-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const fs = require("fs"); 6 | const ts = require("typescript"); 7 | 8 | const payloads = [ 9 | { 10 | // Compile typescript-angular.ts to ES3 (default) 11 | name: "todomvc/typescript-angular.ts", 12 | transpileOptions: { 13 | compilerOptions: { 14 | module: ts.ModuleKind.CommonJS, 15 | target: ts.ScriptTarget.ES3 16 | } 17 | } 18 | }, 19 | { 20 | // Compile typescript-angular.ts to ESNext (latest) 21 | name: "todomvc/typescript-angular.ts", 22 | transpileOptions: { 23 | compilerOptions: { 24 | module: ts.ModuleKind.CommonJS, 25 | target: ts.ScriptTarget.ESNext 26 | } 27 | } 28 | } 29 | ].map(({ name, transpileOptions }) => ({ 30 | input: fs.readFileSync(`third_party/${name}`, "utf8"), 31 | transpileOptions 32 | })); 33 | 34 | module.exports = { 35 | name: "typescript", 36 | fn() { 37 | return payloads.map(({ input, transpileOptions }) => 38 | ts.transpileModule(input, transpileOptions) 39 | ); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /src/typescript-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const typescriptBenchmark = require("./typescript-benchmark"); 6 | 7 | it("typescript-benchmark runs to completion", () => 8 | void typescriptBenchmark.fn()); 9 | -------------------------------------------------------------------------------- /src/uglify-js-benchmark.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const UglifyJS = require("../build/uglify-js-bundled"); 6 | const fs = require("fs"); 7 | 8 | const payloads = [ 9 | { 10 | name: "lodash.core-4.17.4.js", 11 | options: { compress: { passes: 1 } } 12 | } 13 | ].map(({ name, options }) => ({ 14 | payload: fs.readFileSync(`third_party/${name}`, "utf8"), 15 | options 16 | })); 17 | 18 | module.exports = { 19 | name: "uglify-js", 20 | fn() { 21 | return payloads.map(({ payload, options }) => 22 | UglifyJS.minify(payload, options) 23 | ); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/uglify-js-benchmark.test.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const uglifyJsBenchmark = require("./uglify-js-benchmark"); 6 | 7 | it("uglify-js-benchmark runs to completion", () => void uglifyJsBenchmark.fn()); 8 | -------------------------------------------------------------------------------- /src/vfs.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const virtualfs = require("virtualfs"); 6 | 7 | // Setup the virtual file system. 8 | const fs = new virtualfs.VirtualFS(); 9 | fs.mkdirpSync("third_party/todomvc/react"); 10 | fs.writeFileSync( 11 | "third_party/angular-material-1.1.8.css", 12 | require("raw-loader!../third_party/angular-material-1.1.8.css") 13 | ); 14 | fs.writeFileSync( 15 | "third_party/backbone-1.1.0.js", 16 | require("raw-loader!../third_party/backbone-1.1.0.js") 17 | ); 18 | fs.writeFileSync( 19 | "third_party/bootstrap-4.0.0.css", 20 | require("raw-loader!../third_party/bootstrap-4.0.0.css") 21 | ); 22 | fs.writeFileSync( 23 | "third_party/foundation-6.4.2.css", 24 | require("raw-loader!../third_party/foundation-6.4.2.css") 25 | ); 26 | fs.writeFileSync( 27 | "third_party/jquery-3.2.1.js", 28 | require("raw-loader!../third_party/jquery-3.2.1.js") 29 | ); 30 | fs.writeFileSync( 31 | "third_party/coffeescript-lexer-2.0.1.coffee", 32 | require("raw-loader!../third_party/coffeescript-lexer-2.0.1.coffee") 33 | ); 34 | fs.writeFileSync( 35 | "third_party/lodash.core-4.17.4.js", 36 | require("raw-loader!../third_party/lodash.core-4.17.4.js") 37 | ); 38 | fs.writeFileSync( 39 | "third_party/lodash.min-4.17.4.js.map", 40 | require("raw-loader!../third_party/lodash.min-4.17.4.js.map") 41 | ); 42 | fs.writeFileSync( 43 | "third_party/mootools-core-1.6.0.js", 44 | require("raw-loader!../third_party/mootools-core-1.6.0.js") 45 | ); 46 | fs.writeFileSync( 47 | "third_party/preact-8.2.5.js", 48 | require("raw-loader!../third_party/preact-8.2.5.js") 49 | ); 50 | fs.writeFileSync( 51 | "third_party/preact-8.2.5.js.map", 52 | require("raw-loader!../third_party/preact-8.2.5.js.map") 53 | ); 54 | fs.writeFileSync( 55 | "third_party/redux.min-3.7.2.js", 56 | require("raw-loader!../third_party/redux.min-3.7.2.js") 57 | ); 58 | fs.writeFileSync( 59 | "third_party/source-map.min-0.5.7.js.map", 60 | require("raw-loader!../third_party/source-map.min-0.5.7.js.map") 61 | ); 62 | fs.writeFileSync( 63 | "third_party/speedometer-es2015-test-2.0.js", 64 | require("raw-loader!../third_party/speedometer-es2015-test-2.0.js") 65 | ); 66 | fs.writeFileSync( 67 | "third_party/todomvc/react/app.jsx", 68 | require("raw-loader!../third_party/todomvc/react/app.jsx") 69 | ); 70 | fs.writeFileSync( 71 | "third_party/todomvc/react/footer.jsx", 72 | require("raw-loader!../third_party/todomvc/react/footer.jsx") 73 | ); 74 | fs.writeFileSync( 75 | "third_party/todomvc/react/todoItem.jsx", 76 | require("raw-loader!../third_party/todomvc/react/todoItem.jsx") 77 | ); 78 | fs.writeFileSync( 79 | "third_party/todomvc/typescript-angular.ts", 80 | require("raw-loader!../third_party/todomvc/typescript-angular.ts") 81 | ); 82 | fs.writeFileSync( 83 | "third_party/underscore-1.8.3.js", 84 | require("raw-loader!../third_party/underscore-1.8.3.js") 85 | ); 86 | fs.writeFileSync( 87 | "third_party/underscore.min-1.8.3.js.map", 88 | require("raw-loader!../third_party/underscore.min-1.8.3.js.map") 89 | ); 90 | fs.writeFileSync( 91 | "third_party/vue.runtime.esm-nobuble-2.4.4.js", 92 | require("raw-loader!../third_party/vue.runtime.esm-nobuble-2.4.4.js") 93 | ); 94 | 95 | module.exports = fs; 96 | -------------------------------------------------------------------------------- /third_party/preact-8.2.5.js: -------------------------------------------------------------------------------- 1 | !function() { 2 | 'use strict'; 3 | function VNode() {} 4 | function h(nodeName, attributes) { 5 | var lastSimple, child, simple, i, children = EMPTY_CHILDREN; 6 | for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]); 7 | if (attributes && null != attributes.children) { 8 | if (!stack.length) stack.push(attributes.children); 9 | delete attributes.children; 10 | } 11 | while (stack.length) if ((child = stack.pop()) && void 0 !== child.pop) for (i = child.length; i--; ) stack.push(child[i]); else { 12 | if ('boolean' == typeof child) child = null; 13 | if (simple = 'function' != typeof nodeName) if (null == child) child = ''; else if ('number' == typeof child) child = String(child); else if ('string' != typeof child) simple = !1; 14 | if (simple && lastSimple) children[children.length - 1] += child; else if (children === EMPTY_CHILDREN) children = [ child ]; else children.push(child); 15 | lastSimple = simple; 16 | } 17 | var p = new VNode(); 18 | p.nodeName = nodeName; 19 | p.children = children; 20 | p.attributes = null == attributes ? void 0 : attributes; 21 | p.key = null == attributes ? void 0 : attributes.key; 22 | if (void 0 !== options.vnode) options.vnode(p); 23 | return p; 24 | } 25 | function extend(obj, props) { 26 | for (var i in props) obj[i] = props[i]; 27 | return obj; 28 | } 29 | function cloneElement(vnode, props) { 30 | return h(vnode.nodeName, extend(extend({}, vnode.attributes), props), arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children); 31 | } 32 | function enqueueRender(component) { 33 | if (!component.__d && (component.__d = !0) && 1 == items.push(component)) (options.debounceRendering || defer)(rerender); 34 | } 35 | function rerender() { 36 | var p, list = items; 37 | items = []; 38 | while (p = list.pop()) if (p.__d) renderComponent(p); 39 | } 40 | function isSameNodeType(node, vnode, hydrating) { 41 | if ('string' == typeof vnode || 'number' == typeof vnode) return void 0 !== node.splitText; 42 | if ('string' == typeof vnode.nodeName) return !node._componentConstructor && isNamedNode(node, vnode.nodeName); else return hydrating || node._componentConstructor === vnode.nodeName; 43 | } 44 | function isNamedNode(node, nodeName) { 45 | return node.__n === nodeName || node.nodeName.toLowerCase() === nodeName.toLowerCase(); 46 | } 47 | function getNodeProps(vnode) { 48 | var props = extend({}, vnode.attributes); 49 | props.children = vnode.children; 50 | var defaultProps = vnode.nodeName.defaultProps; 51 | if (void 0 !== defaultProps) for (var i in defaultProps) if (void 0 === props[i]) props[i] = defaultProps[i]; 52 | return props; 53 | } 54 | function createNode(nodeName, isSvg) { 55 | var node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName); 56 | node.__n = nodeName; 57 | return node; 58 | } 59 | function removeNode(node) { 60 | var parentNode = node.parentNode; 61 | if (parentNode) parentNode.removeChild(node); 62 | } 63 | function setAccessor(node, name, old, value, isSvg) { 64 | if ('className' === name) name = 'class'; 65 | if ('key' === name) ; else if ('ref' === name) { 66 | if (old) old(null); 67 | if (value) value(node); 68 | } else if ('class' === name && !isSvg) node.className = value || ''; else if ('style' === name) { 69 | if (!value || 'string' == typeof value || 'string' == typeof old) node.style.cssText = value || ''; 70 | if (value && 'object' == typeof value) { 71 | if ('string' != typeof old) for (var i in old) if (!(i in value)) node.style[i] = ''; 72 | for (var i in value) node.style[i] = 'number' == typeof value[i] && !1 === IS_NON_DIMENSIONAL.test(i) ? value[i] + 'px' : value[i]; 73 | } 74 | } else if ('dangerouslySetInnerHTML' === name) { 75 | if (value) node.innerHTML = value.__html || ''; 76 | } else if ('o' == name[0] && 'n' == name[1]) { 77 | var useCapture = name !== (name = name.replace(/Capture$/, '')); 78 | name = name.toLowerCase().substring(2); 79 | if (value) { 80 | if (!old) node.addEventListener(name, eventProxy, useCapture); 81 | } else node.removeEventListener(name, eventProxy, useCapture); 82 | (node.__l || (node.__l = {}))[name] = value; 83 | } else if ('list' !== name && 'type' !== name && !isSvg && name in node) { 84 | setProperty(node, name, null == value ? '' : value); 85 | if (null == value || !1 === value) node.removeAttribute(name); 86 | } else { 87 | var ns = isSvg && name !== (name = name.replace(/^xlink\:?/, '')); 88 | if (null == value || !1 === value) if (ns) node.removeAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase()); else node.removeAttribute(name); else if ('function' != typeof value) if (ns) node.setAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase(), value); else node.setAttribute(name, value); 89 | } 90 | } 91 | function setProperty(node, name, value) { 92 | try { 93 | node[name] = value; 94 | } catch (e) {} 95 | } 96 | function eventProxy(e) { 97 | return this.__l[e.type](options.event && options.event(e) || e); 98 | } 99 | function flushMounts() { 100 | var c; 101 | while (c = mounts.pop()) { 102 | if (options.afterMount) options.afterMount(c); 103 | if (c.componentDidMount) c.componentDidMount(); 104 | } 105 | } 106 | function diff(dom, vnode, context, mountAll, parent, componentRoot) { 107 | if (!diffLevel++) { 108 | isSvgMode = null != parent && void 0 !== parent.ownerSVGElement; 109 | hydrating = null != dom && !('__preactattr_' in dom); 110 | } 111 | var ret = idiff(dom, vnode, context, mountAll, componentRoot); 112 | if (parent && ret.parentNode !== parent) parent.appendChild(ret); 113 | if (!--diffLevel) { 114 | hydrating = !1; 115 | if (!componentRoot) flushMounts(); 116 | } 117 | return ret; 118 | } 119 | function idiff(dom, vnode, context, mountAll, componentRoot) { 120 | var out = dom, prevSvgMode = isSvgMode; 121 | if (null == vnode || 'boolean' == typeof vnode) vnode = ''; 122 | if ('string' == typeof vnode || 'number' == typeof vnode) { 123 | if (dom && void 0 !== dom.splitText && dom.parentNode && (!dom._component || componentRoot)) { 124 | if (dom.nodeValue != vnode) dom.nodeValue = vnode; 125 | } else { 126 | out = document.createTextNode(vnode); 127 | if (dom) { 128 | if (dom.parentNode) dom.parentNode.replaceChild(out, dom); 129 | recollectNodeTree(dom, !0); 130 | } 131 | } 132 | out.__preactattr_ = !0; 133 | return out; 134 | } 135 | var vnodeName = vnode.nodeName; 136 | if ('function' == typeof vnodeName) return buildComponentFromVNode(dom, vnode, context, mountAll); 137 | isSvgMode = 'svg' === vnodeName ? !0 : 'foreignObject' === vnodeName ? !1 : isSvgMode; 138 | vnodeName = String(vnodeName); 139 | if (!dom || !isNamedNode(dom, vnodeName)) { 140 | out = createNode(vnodeName, isSvgMode); 141 | if (dom) { 142 | while (dom.firstChild) out.appendChild(dom.firstChild); 143 | if (dom.parentNode) dom.parentNode.replaceChild(out, dom); 144 | recollectNodeTree(dom, !0); 145 | } 146 | } 147 | var fc = out.firstChild, props = out.__preactattr_, vchildren = vnode.children; 148 | if (null == props) { 149 | props = out.__preactattr_ = {}; 150 | for (var a = out.attributes, i = a.length; i--; ) props[a[i].name] = a[i].value; 151 | } 152 | if (!hydrating && vchildren && 1 === vchildren.length && 'string' == typeof vchildren[0] && null != fc && void 0 !== fc.splitText && null == fc.nextSibling) { 153 | if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0]; 154 | } else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML); 155 | diffAttributes(out, vnode.attributes, props); 156 | isSvgMode = prevSvgMode; 157 | return out; 158 | } 159 | function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) { 160 | var j, c, f, vchild, child, originalChildren = dom.childNodes, children = [], keyed = {}, keyedLen = 0, min = 0, len = originalChildren.length, childrenLen = 0, vlen = vchildren ? vchildren.length : 0; 161 | if (0 !== len) for (var i = 0; i < len; i++) { 162 | var _child = originalChildren[i], props = _child.__preactattr_, key = vlen && props ? _child._component ? _child._component.__k : props.key : null; 163 | if (null != key) { 164 | keyedLen++; 165 | keyed[key] = _child; 166 | } else if (props || (void 0 !== _child.splitText ? isHydrating ? _child.nodeValue.trim() : !0 : isHydrating)) children[childrenLen++] = _child; 167 | } 168 | if (0 !== vlen) for (var i = 0; i < vlen; i++) { 169 | vchild = vchildren[i]; 170 | child = null; 171 | var key = vchild.key; 172 | if (null != key) { 173 | if (keyedLen && void 0 !== keyed[key]) { 174 | child = keyed[key]; 175 | keyed[key] = void 0; 176 | keyedLen--; 177 | } 178 | } else if (!child && min < childrenLen) for (j = min; j < childrenLen; j++) if (void 0 !== children[j] && isSameNodeType(c = children[j], vchild, isHydrating)) { 179 | child = c; 180 | children[j] = void 0; 181 | if (j === childrenLen - 1) childrenLen--; 182 | if (j === min) min++; 183 | break; 184 | } 185 | child = idiff(child, vchild, context, mountAll); 186 | f = originalChildren[i]; 187 | if (child && child !== dom && child !== f) if (null == f) dom.appendChild(child); else if (child === f.nextSibling) removeNode(f); else dom.insertBefore(child, f); 188 | } 189 | if (keyedLen) for (var i in keyed) if (void 0 !== keyed[i]) recollectNodeTree(keyed[i], !1); 190 | while (min <= childrenLen) if (void 0 !== (child = children[childrenLen--])) recollectNodeTree(child, !1); 191 | } 192 | function recollectNodeTree(node, unmountOnly) { 193 | var component = node._component; 194 | if (component) unmountComponent(component); else { 195 | if (null != node.__preactattr_ && node.__preactattr_.ref) node.__preactattr_.ref(null); 196 | if (!1 === unmountOnly || null == node.__preactattr_) removeNode(node); 197 | removeChildren(node); 198 | } 199 | } 200 | function removeChildren(node) { 201 | node = node.lastChild; 202 | while (node) { 203 | var next = node.previousSibling; 204 | recollectNodeTree(node, !0); 205 | node = next; 206 | } 207 | } 208 | function diffAttributes(dom, attrs, old) { 209 | var name; 210 | for (name in old) if ((!attrs || null == attrs[name]) && null != old[name]) setAccessor(dom, name, old[name], old[name] = void 0, isSvgMode); 211 | for (name in attrs) if (!('children' === name || 'innerHTML' === name || name in old && attrs[name] === ('value' === name || 'checked' === name ? dom[name] : old[name]))) setAccessor(dom, name, old[name], old[name] = attrs[name], isSvgMode); 212 | } 213 | function collectComponent(component) { 214 | var name = component.constructor.name; 215 | (components[name] || (components[name] = [])).push(component); 216 | } 217 | function createComponent(Ctor, props, context) { 218 | var inst, list = components[Ctor.name]; 219 | if (Ctor.prototype && Ctor.prototype.render) { 220 | inst = new Ctor(props, context); 221 | Component.call(inst, props, context); 222 | } else { 223 | inst = new Component(props, context); 224 | inst.constructor = Ctor; 225 | inst.render = doRender; 226 | } 227 | if (list) for (var i = list.length; i--; ) if (list[i].constructor === Ctor) { 228 | inst.__b = list[i].__b; 229 | list.splice(i, 1); 230 | break; 231 | } 232 | return inst; 233 | } 234 | function doRender(props, state, context) { 235 | return this.constructor(props, context); 236 | } 237 | function setComponentProps(component, props, opts, context, mountAll) { 238 | if (!component.__x) { 239 | component.__x = !0; 240 | if (component.__r = props.ref) delete props.ref; 241 | if (component.__k = props.key) delete props.key; 242 | if (!component.base || mountAll) { 243 | if (component.componentWillMount) component.componentWillMount(); 244 | } else if (component.componentWillReceiveProps) component.componentWillReceiveProps(props, context); 245 | if (context && context !== component.context) { 246 | if (!component.__c) component.__c = component.context; 247 | component.context = context; 248 | } 249 | if (!component.__p) component.__p = component.props; 250 | component.props = props; 251 | component.__x = !1; 252 | if (0 !== opts) if (1 === opts || !1 !== options.syncComponentUpdates || !component.base) renderComponent(component, 1, mountAll); else enqueueRender(component); 253 | if (component.__r) component.__r(component); 254 | } 255 | } 256 | function renderComponent(component, opts, mountAll, isChild) { 257 | if (!component.__x) { 258 | var rendered, inst, cbase, props = component.props, state = component.state, context = component.context, previousProps = component.__p || props, previousState = component.__s || state, previousContext = component.__c || context, isUpdate = component.base, nextBase = component.__b, initialBase = isUpdate || nextBase, initialChildComponent = component._component, skip = !1; 259 | if (isUpdate) { 260 | component.props = previousProps; 261 | component.state = previousState; 262 | component.context = previousContext; 263 | if (2 !== opts && component.shouldComponentUpdate && !1 === component.shouldComponentUpdate(props, state, context)) skip = !0; else if (component.componentWillUpdate) component.componentWillUpdate(props, state, context); 264 | component.props = props; 265 | component.state = state; 266 | component.context = context; 267 | } 268 | component.__p = component.__s = component.__c = component.__b = null; 269 | component.__d = !1; 270 | if (!skip) { 271 | rendered = component.render(props, state, context); 272 | if (component.getChildContext) context = extend(extend({}, context), component.getChildContext()); 273 | var toUnmount, base, childComponent = rendered && rendered.nodeName; 274 | if ('function' == typeof childComponent) { 275 | var childProps = getNodeProps(rendered); 276 | inst = initialChildComponent; 277 | if (inst && inst.constructor === childComponent && childProps.key == inst.__k) setComponentProps(inst, childProps, 1, context, !1); else { 278 | toUnmount = inst; 279 | component._component = inst = createComponent(childComponent, childProps, context); 280 | inst.__b = inst.__b || nextBase; 281 | inst.__u = component; 282 | setComponentProps(inst, childProps, 0, context, !1); 283 | renderComponent(inst, 1, mountAll, !0); 284 | } 285 | base = inst.base; 286 | } else { 287 | cbase = initialBase; 288 | toUnmount = initialChildComponent; 289 | if (toUnmount) cbase = component._component = null; 290 | if (initialBase || 1 === opts) { 291 | if (cbase) cbase._component = null; 292 | base = diff(cbase, rendered, context, mountAll || !isUpdate, initialBase && initialBase.parentNode, !0); 293 | } 294 | } 295 | if (initialBase && base !== initialBase && inst !== initialChildComponent) { 296 | var baseParent = initialBase.parentNode; 297 | if (baseParent && base !== baseParent) { 298 | baseParent.replaceChild(base, initialBase); 299 | if (!toUnmount) { 300 | initialBase._component = null; 301 | recollectNodeTree(initialBase, !1); 302 | } 303 | } 304 | } 305 | if (toUnmount) unmountComponent(toUnmount); 306 | component.base = base; 307 | if (base && !isChild) { 308 | var componentRef = component, t = component; 309 | while (t = t.__u) (componentRef = t).base = base; 310 | base._component = componentRef; 311 | base._componentConstructor = componentRef.constructor; 312 | } 313 | } 314 | if (!isUpdate || mountAll) mounts.unshift(component); else if (!skip) { 315 | if (component.componentDidUpdate) component.componentDidUpdate(previousProps, previousState, previousContext); 316 | if (options.afterUpdate) options.afterUpdate(component); 317 | } 318 | if (null != component.__h) while (component.__h.length) component.__h.pop().call(component); 319 | if (!diffLevel && !isChild) flushMounts(); 320 | } 321 | } 322 | function buildComponentFromVNode(dom, vnode, context, mountAll) { 323 | var c = dom && dom._component, originalComponent = c, oldDom = dom, isDirectOwner = c && dom._componentConstructor === vnode.nodeName, isOwner = isDirectOwner, props = getNodeProps(vnode); 324 | while (c && !isOwner && (c = c.__u)) isOwner = c.constructor === vnode.nodeName; 325 | if (c && isOwner && (!mountAll || c._component)) { 326 | setComponentProps(c, props, 3, context, mountAll); 327 | dom = c.base; 328 | } else { 329 | if (originalComponent && !isDirectOwner) { 330 | unmountComponent(originalComponent); 331 | dom = oldDom = null; 332 | } 333 | c = createComponent(vnode.nodeName, props, context); 334 | if (dom && !c.__b) { 335 | c.__b = dom; 336 | oldDom = null; 337 | } 338 | setComponentProps(c, props, 1, context, mountAll); 339 | dom = c.base; 340 | if (oldDom && dom !== oldDom) { 341 | oldDom._component = null; 342 | recollectNodeTree(oldDom, !1); 343 | } 344 | } 345 | return dom; 346 | } 347 | function unmountComponent(component) { 348 | if (options.beforeUnmount) options.beforeUnmount(component); 349 | var base = component.base; 350 | component.__x = !0; 351 | if (component.componentWillUnmount) component.componentWillUnmount(); 352 | component.base = null; 353 | var inner = component._component; 354 | if (inner) unmountComponent(inner); else if (base) { 355 | if (base.__preactattr_ && base.__preactattr_.ref) base.__preactattr_.ref(null); 356 | component.__b = base; 357 | removeNode(base); 358 | collectComponent(component); 359 | removeChildren(base); 360 | } 361 | if (component.__r) component.__r(null); 362 | } 363 | function Component(props, context) { 364 | this.__d = !0; 365 | this.context = context; 366 | this.props = props; 367 | this.state = this.state || {}; 368 | } 369 | function render(vnode, parent, merge) { 370 | return diff(merge, vnode, {}, !1, parent, !1); 371 | } 372 | var options = {}; 373 | var stack = []; 374 | var EMPTY_CHILDREN = []; 375 | var defer = 'function' == typeof Promise ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout; 376 | var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i; 377 | var items = []; 378 | var mounts = []; 379 | var diffLevel = 0; 380 | var isSvgMode = !1; 381 | var hydrating = !1; 382 | var components = {}; 383 | extend(Component.prototype, { 384 | setState: function(state, callback) { 385 | var s = this.state; 386 | if (!this.__s) this.__s = extend({}, s); 387 | extend(s, 'function' == typeof state ? state(s, this.props) : state); 388 | if (callback) (this.__h = this.__h || []).push(callback); 389 | enqueueRender(this); 390 | }, 391 | forceUpdate: function(callback) { 392 | if (callback) (this.__h = this.__h || []).push(callback); 393 | renderComponent(this, 2); 394 | }, 395 | render: function() {} 396 | }); 397 | var preact = { 398 | h: h, 399 | createElement: h, 400 | cloneElement: cloneElement, 401 | Component: Component, 402 | render: render, 403 | rerender: rerender, 404 | options: options 405 | }; 406 | if ('undefined' != typeof module) module.exports = preact; else self.preact = preact; 407 | }(); 408 | //# sourceMappingURL=preact.js.map -------------------------------------------------------------------------------- /third_party/preact-8.2.5.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/vnode.js","../src/h.js","../src/util.js","../src/clone-element.js","../src/constants.js","../src/render-queue.js","../src/vdom/index.js","../src/dom/index.js","../src/vdom/diff.js","../src/vdom/component-recycler.js","../src/vdom/component.js","../src/options.js","../src/component.js","../src/render.js","../src/preact.js"],"names":["VNode","nodeName","attributes","children","lastSimple","child","simple","i","EMPTY_CHILDREN","arguments","length","stack","undefined","push","String","p","key","options","vnode","extend","obj","props","cloneElement","h","slice","call","ATTR_KEY","component","items","_dirty","pop","debounceRendering","rerender","renderComponent","hydrating","node","_componentConstructor","defaultProps","isSvg","document","createElementNS","createElement","createNode","normalizedNodeName","parentNode","removeChild","setAccessor","name","value","style","cssText","old","IS_NON_DIMENSIONAL","test","innerHTML","__html","useCapture","replace","toLowerCase","substring","removeAttribute","addEventListener","eventProxy","removeEventListener","_listeners","ns","setAttribute","setProperty","this","e","type","event","diffLevel","isSvgMode","afterMount","c","parent","ownerSVGElement","appendChild","ret","dom","idiff","context","mountAll","componentRoot","flushMounts","prevSvgMode","_component","nodeValue","splitText","out","createTextNode","vnodeName","isNamedNode","buildComponentFromVNode","firstChild","replaceChild","fc","vchildren","innerDiffNode","originalChildren","keyed","keyedLen","childrenLen","_child","vlen","__key","vchild","min","j","isSameNodeType","isHydrating","insertBefore","recollectNodeTree","unmountOnly","removeNode","removeChildren","diffAttributes","attrs","components","Ctor","constructor","render","createComponent","prototype","inst","nextBase","list","Component","splice","state","opts","setComponentProps","_disable","prevContext","componentWillReceiveProps","syncComponentUpdates","base","prevProps","isChild","previousProps","previousState","initialBase","isUpdate","initialChildComponent","previousContext","rendered","shouldComponentUpdate","componentWillUpdate","prevState","toUnmount","childComponent","childProps","getNodeProps","cbase","SYNC_RENDER","componentRef","t","_parentComponent","componentDidUpdate","skip","afterUpdate","originalComponent","oldDom","isDirectOwner","isOwner","ASYNC_RENDER","unmountComponent","inner","componentWillUnmount","ref","defer","Promise","resolve","then","bind","setTimeout","mounts","callback","_renderCallbacks","merge","module","exports","preact","self"],"mappings":"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","file":"preact.js","sourcesContent":["/** Virtual DOM Node */\nexport function VNode() {}\n","import { VNode } from './vnode';\nimport options from './options';\n\n\nconst stack = [];\n\nconst EMPTY_CHILDREN = [];\n\n/** JSX/hyperscript reviver\n*\tBenchmarks: https://esbench.com/bench/57ee8f8e330ab09900a1a1a0\n *\t@see http://jasonformat.com/wtf-is-jsx\n *\t@public\n */\nexport function h(nodeName, attributes) {\n\tlet children=EMPTY_CHILDREN, lastSimple, child, simple, i;\n\tfor (i=arguments.length; i-- > 2; ) {\n\t\tstack.push(arguments[i]);\n\t}\n\tif (attributes && attributes.children!=null) {\n\t\tif (!stack.length) stack.push(attributes.children);\n\t\tdelete attributes.children;\n\t}\n\twhile (stack.length) {\n\t\tif ((child = stack.pop()) && child.pop!==undefined) {\n\t\t\tfor (i=child.length; i--; ) stack.push(child[i]);\n\t\t}\n\t\telse {\n\t\t\tif (typeof child==='boolean') child = null;\n\n\t\t\tif ((simple = typeof nodeName!=='function')) {\n\t\t\t\tif (child==null) child = '';\n\t\t\t\telse if (typeof child==='number') child = String(child);\n\t\t\t\telse if (typeof child!=='string') simple = false;\n\t\t\t}\n\n\t\t\tif (simple && lastSimple) {\n\t\t\t\tchildren[children.length-1] += child;\n\t\t\t}\n\t\t\telse if (children===EMPTY_CHILDREN) {\n\t\t\t\tchildren = [child];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tchildren.push(child);\n\t\t\t}\n\n\t\t\tlastSimple = simple;\n\t\t}\n\t}\n\n\tlet p = new VNode();\n\tp.nodeName = nodeName;\n\tp.children = children;\n\tp.attributes = attributes==null ? undefined : attributes;\n\tp.key = attributes==null ? undefined : attributes.key;\n\n\t// if a \"vnode hook\" is defined, pass every created VNode to it\n\tif (options.vnode!==undefined) options.vnode(p);\n\n\treturn p;\n}\n","/** Copy own-properties from `props` onto `obj`.\n *\t@returns obj\n *\t@private\n */\nexport function extend(obj, props) {\n\tfor (let i in props) obj[i] = props[i];\n\treturn obj;\n}\n\n/** Call a function asynchronously, as soon as possible.\n *\t@param {Function} callback\n */\nexport const defer = typeof Promise=='function' ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout;\n","import { extend } from './util';\nimport { h } from './h';\n\nexport function cloneElement(vnode, props) {\n\treturn h(\n\t\tvnode.nodeName,\n\t\textend(extend({}, vnode.attributes), props),\n\t\targuments.length>2 ? [].slice.call(arguments, 2) : vnode.children\n\t);\n}\n","// render modes\n\nexport const NO_RENDER = 0;\nexport const SYNC_RENDER = 1;\nexport const FORCE_RENDER = 2;\nexport const ASYNC_RENDER = 3;\n\n\nexport const ATTR_KEY = '__preactattr_';\n\n// DOM properties that should NOT have \"px\" added when numeric\nexport const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i;\n\n","import options from './options';\nimport { defer } from './util';\nimport { renderComponent } from './vdom/component';\n\n/** Managed queue of dirty components to be re-rendered */\n\nlet items = [];\n\nexport function enqueueRender(component) {\n\tif (!component._dirty && (component._dirty = true) && items.push(component)==1) {\n\t\t(options.debounceRendering || defer)(rerender);\n\t}\n}\n\nexport function rerender() {\n\tlet p, list = items;\n\titems = [];\n\twhile ( (p = list.pop()) ) {\n\t\tif (p._dirty) renderComponent(p);\n\t}\n}\n","import { extend } from '../util';\n\n\n/** Check if two nodes are equivalent.\n *\t@param {Element} node\n *\t@param {VNode} vnode\n *\t@private\n */\nexport function isSameNodeType(node, vnode, hydrating) {\n\tif (typeof vnode==='string' || typeof vnode==='number') {\n\t\treturn node.splitText!==undefined;\n\t}\n\tif (typeof vnode.nodeName==='string') {\n\t\treturn !node._componentConstructor && isNamedNode(node, vnode.nodeName);\n\t}\n\treturn hydrating || node._componentConstructor===vnode.nodeName;\n}\n\n\n/** Check if an Element has a given normalized name.\n*\t@param {Element} node\n*\t@param {String} nodeName\n */\nexport function isNamedNode(node, nodeName) {\n\treturn node.normalizedNodeName===nodeName || node.nodeName.toLowerCase()===nodeName.toLowerCase();\n}\n\n\n/**\n * Reconstruct Component-style `props` from a VNode.\n * Ensures default/fallback values from `defaultProps`:\n * Own-properties of `defaultProps` not present in `vnode.attributes` are added.\n * @param {VNode} vnode\n * @returns {Object} props\n */\nexport function getNodeProps(vnode) {\n\tlet props = extend({}, vnode.attributes);\n\tprops.children = vnode.children;\n\n\tlet defaultProps = vnode.nodeName.defaultProps;\n\tif (defaultProps!==undefined) {\n\t\tfor (let i in defaultProps) {\n\t\t\tif (props[i]===undefined) {\n\t\t\t\tprops[i] = defaultProps[i];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn props;\n}\n","import { IS_NON_DIMENSIONAL } from '../constants';\nimport options from '../options';\n\n\n/** Create an element with the given nodeName.\n *\t@param {String} nodeName\n *\t@param {Boolean} [isSvg=false]\tIf `true`, creates an element within the SVG namespace.\n *\t@returns {Element} node\n */\nexport function createNode(nodeName, isSvg) {\n\tlet node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName);\n\tnode.normalizedNodeName = nodeName;\n\treturn node;\n}\n\n\n/** Remove a child node from its parent if attached.\n *\t@param {Element} node\t\tThe node to remove\n */\nexport function removeNode(node) {\n\tlet parentNode = node.parentNode;\n\tif (parentNode) parentNode.removeChild(node);\n}\n\n\n/** Set a named attribute on the given Node, with special behavior for some names and event handlers.\n *\tIf `value` is `null`, the attribute/handler will be removed.\n *\t@param {Element} node\tAn element to mutate\n *\t@param {string} name\tThe name/key to set, such as an event or attribute name\n *\t@param {any} old\tThe last value that was set for this name/node pair\n *\t@param {any} value\tAn attribute value, such as a function to be used as an event handler\n *\t@param {Boolean} isSvg\tAre we currently diffing inside an svg?\n *\t@private\n */\nexport function setAccessor(node, name, old, value, isSvg) {\n\tif (name==='className') name = 'class';\n\n\n\tif (name==='key') {\n\t\t// ignore\n\t}\n\telse if (name==='ref') {\n\t\tif (old) old(null);\n\t\tif (value) value(node);\n\t}\n\telse if (name==='class' && !isSvg) {\n\t\tnode.className = value || '';\n\t}\n\telse if (name==='style') {\n\t\tif (!value || typeof value==='string' || typeof old==='string') {\n\t\t\tnode.style.cssText = value || '';\n\t\t}\n\t\tif (value && typeof value==='object') {\n\t\t\tif (typeof old!=='string') {\n\t\t\t\tfor (let i in old) if (!(i in value)) node.style[i] = '';\n\t\t\t}\n\t\t\tfor (let i in value) {\n\t\t\t\tnode.style[i] = typeof value[i]==='number' && IS_NON_DIMENSIONAL.test(i)===false ? (value[i]+'px') : value[i];\n\t\t\t}\n\t\t}\n\t}\n\telse if (name==='dangerouslySetInnerHTML') {\n\t\tif (value) node.innerHTML = value.__html || '';\n\t}\n\telse if (name[0]=='o' && name[1]=='n') {\n\t\tlet useCapture = name !== (name=name.replace(/Capture$/, ''));\n\t\tname = name.toLowerCase().substring(2);\n\t\tif (value) {\n\t\t\tif (!old) node.addEventListener(name, eventProxy, useCapture);\n\t\t}\n\t\telse {\n\t\t\tnode.removeEventListener(name, eventProxy, useCapture);\n\t\t}\n\t\t(node._listeners || (node._listeners = {}))[name] = value;\n\t}\n\telse if (name!=='list' && name!=='type' && !isSvg && name in node) {\n\t\tsetProperty(node, name, value==null ? '' : value);\n\t\tif (value==null || value===false) node.removeAttribute(name);\n\t}\n\telse {\n\t\tlet ns = isSvg && (name !== (name = name.replace(/^xlink\\:?/, '')));\n\t\tif (value==null || value===false) {\n\t\t\tif (ns) node.removeAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase());\n\t\t\telse node.removeAttribute(name);\n\t\t}\n\t\telse if (typeof value!=='function') {\n\t\t\tif (ns) node.setAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase(), value);\n\t\t\telse node.setAttribute(name, value);\n\t\t}\n\t}\n}\n\n\n/** Attempt to set a DOM property to the given value.\n *\tIE & FF throw for certain property-value combinations.\n */\nfunction setProperty(node, name, value) {\n\ttry {\n\t\tnode[name] = value;\n\t} catch (e) { }\n}\n\n\n/** Proxy an event to hooked event handlers\n *\t@private\n */\nfunction eventProxy(e) {\n\treturn this._listeners[e.type](options.event && options.event(e) || e);\n}\n","import { ATTR_KEY } from '../constants';\nimport { isSameNodeType, isNamedNode } from './index';\nimport { buildComponentFromVNode } from './component';\nimport { createNode, setAccessor } from '../dom/index';\nimport { unmountComponent } from './component';\nimport options from '../options';\nimport { removeNode } from '../dom/index';\n\n/** Queue of components that have been mounted and are awaiting componentDidMount */\nexport const mounts = [];\n\n/** Diff recursion count, used to track the end of the diff cycle. */\nexport let diffLevel = 0;\n\n/** Global flag indicating if the diff is currently within an SVG */\nlet isSvgMode = false;\n\n/** Global flag indicating if the diff is performing hydration */\nlet hydrating = false;\n\n/** Invoke queued componentDidMount lifecycle methods */\nexport function flushMounts() {\n\tlet c;\n\twhile ((c=mounts.pop())) {\n\t\tif (options.afterMount) options.afterMount(c);\n\t\tif (c.componentDidMount) c.componentDidMount();\n\t}\n}\n\n\n/** Apply differences in a given vnode (and it's deep children) to a real DOM Node.\n *\t@param {Element} [dom=null]\t\tA DOM node to mutate into the shape of the `vnode`\n *\t@param {VNode} vnode\t\t\tA VNode (with descendants forming a tree) representing the desired DOM structure\n *\t@returns {Element} dom\t\t\tThe created/mutated element\n *\t@private\n */\nexport function diff(dom, vnode, context, mountAll, parent, componentRoot) {\n\t// diffLevel having been 0 here indicates initial entry into the diff (not a subdiff)\n\tif (!diffLevel++) {\n\t\t// when first starting the diff, check if we're diffing an SVG or within an SVG\n\t\tisSvgMode = parent!=null && parent.ownerSVGElement!==undefined;\n\n\t\t// hydration is indicated by the existing element to be diffed not having a prop cache\n\t\thydrating = dom!=null && !(ATTR_KEY in dom);\n\t}\n\n\tlet ret = idiff(dom, vnode, context, mountAll, componentRoot);\n\n\t// append the element if its a new parent\n\tif (parent && ret.parentNode!==parent) parent.appendChild(ret);\n\n\t// diffLevel being reduced to 0 means we're exiting the diff\n\tif (!--diffLevel) {\n\t\thydrating = false;\n\t\t// invoke queued componentDidMount lifecycle methods\n\t\tif (!componentRoot) flushMounts();\n\t}\n\n\treturn ret;\n}\n\n\n/** Internals of `diff()`, separated to allow bypassing diffLevel / mount flushing. */\nfunction idiff(dom, vnode, context, mountAll, componentRoot) {\n\tlet out = dom,\n\t\tprevSvgMode = isSvgMode;\n\n\t// empty values (null, undefined, booleans) render as empty Text nodes\n\tif (vnode==null || typeof vnode==='boolean') vnode = '';\n\n\n\t// Fast case: Strings & Numbers create/update Text nodes.\n\tif (typeof vnode==='string' || typeof vnode==='number') {\n\n\t\t// update if it's already a Text node:\n\t\tif (dom && dom.splitText!==undefined && dom.parentNode && (!dom._component || componentRoot)) {\n\t\t\t/* istanbul ignore if */ /* Browser quirk that can't be covered: https://github.com/developit/preact/commit/fd4f21f5c45dfd75151bd27b4c217d8003aa5eb9 */\n\t\t\tif (dom.nodeValue!=vnode) {\n\t\t\t\tdom.nodeValue = vnode;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// it wasn't a Text node: replace it with one and recycle the old Element\n\t\t\tout = document.createTextNode(vnode);\n\t\t\tif (dom) {\n\t\t\t\tif (dom.parentNode) dom.parentNode.replaceChild(out, dom);\n\t\t\t\trecollectNodeTree(dom, true);\n\t\t\t}\n\t\t}\n\n\t\tout[ATTR_KEY] = true;\n\n\t\treturn out;\n\t}\n\n\n\t// If the VNode represents a Component, perform a component diff:\n\tlet vnodeName = vnode.nodeName;\n\tif (typeof vnodeName==='function') {\n\t\treturn buildComponentFromVNode(dom, vnode, context, mountAll);\n\t}\n\n\n\t// Tracks entering and exiting SVG namespace when descending through the tree.\n\tisSvgMode = vnodeName==='svg' ? true : vnodeName==='foreignObject' ? false : isSvgMode;\n\n\n\t// If there's no existing element or it's the wrong type, create a new one:\n\tvnodeName = String(vnodeName);\n\tif (!dom || !isNamedNode(dom, vnodeName)) {\n\t\tout = createNode(vnodeName, isSvgMode);\n\n\t\tif (dom) {\n\t\t\t// move children into the replacement node\n\t\t\twhile (dom.firstChild) out.appendChild(dom.firstChild);\n\n\t\t\t// if the previous Element was mounted into the DOM, replace it inline\n\t\t\tif (dom.parentNode) dom.parentNode.replaceChild(out, dom);\n\n\t\t\t// recycle the old element (skips non-Element node types)\n\t\t\trecollectNodeTree(dom, true);\n\t\t}\n\t}\n\n\n\tlet fc = out.firstChild,\n\t\tprops = out[ATTR_KEY],\n\t\tvchildren = vnode.children;\n\n\tif (props==null) {\n\t\tprops = out[ATTR_KEY] = {};\n\t\tfor (let a=out.attributes, i=a.length; i--; ) props[a[i].name] = a[i].value;\n\t}\n\n\t// Optimization: fast-path for elements containing a single TextNode:\n\tif (!hydrating && vchildren && vchildren.length===1 && typeof vchildren[0]==='string' && fc!=null && fc.splitText!==undefined && fc.nextSibling==null) {\n\t\tif (fc.nodeValue!=vchildren[0]) {\n\t\t\tfc.nodeValue = vchildren[0];\n\t\t}\n\t}\n\t// otherwise, if there are existing or new children, diff them:\n\telse if (vchildren && vchildren.length || fc!=null) {\n\t\tinnerDiffNode(out, vchildren, context, mountAll, hydrating || props.dangerouslySetInnerHTML!=null);\n\t}\n\n\n\t// Apply attributes/props from VNode to the DOM Element:\n\tdiffAttributes(out, vnode.attributes, props);\n\n\n\t// restore previous SVG mode: (in case we're exiting an SVG namespace)\n\tisSvgMode = prevSvgMode;\n\n\treturn out;\n}\n\n\n/** Apply child and attribute changes between a VNode and a DOM Node to the DOM.\n *\t@param {Element} dom\t\t\tElement whose children should be compared & mutated\n *\t@param {Array} vchildren\t\tArray of VNodes to compare to `dom.childNodes`\n *\t@param {Object} context\t\t\tImplicitly descendant context object (from most recent `getChildContext()`)\n *\t@param {Boolean} mountAll\n *\t@param {Boolean} isHydrating\tIf `true`, consumes externally created elements similar to hydration\n */\nfunction innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {\n\tlet originalChildren = dom.childNodes,\n\t\tchildren = [],\n\t\tkeyed = {},\n\t\tkeyedLen = 0,\n\t\tmin = 0,\n\t\tlen = originalChildren.length,\n\t\tchildrenLen = 0,\n\t\tvlen = vchildren ? vchildren.length : 0,\n\t\tj, c, f, vchild, child;\n\n\t// Build up a map of keyed children and an Array of unkeyed children:\n\tif (len!==0) {\n\t\tfor (let i=0; i;\n *\t\t}\n *\t}\n */\nexport function Component(props, context) {\n\tthis._dirty = true;\n\n\t/** @public\n\t *\t@type {object}\n\t */\n\tthis.context = context;\n\n\t/** @public\n\t *\t@type {object}\n\t */\n\tthis.props = props;\n\n\t/** @public\n\t *\t@type {object}\n\t */\n\tthis.state = this.state || {};\n}\n\n\nextend(Component.prototype, {\n\n\t/** Returns a `boolean` indicating if the component should re-render when receiving the given `props` and `state`.\n\t *\t@param {object} nextProps\n\t *\t@param {object} nextState\n\t *\t@param {object} nextContext\n\t *\t@returns {Boolean} should the component re-render\n\t *\t@name shouldComponentUpdate\n\t *\t@function\n\t */\n\n\n\t/** Update component state by copying properties from `state` to `this.state`.\n\t *\t@param {object} state\t\tA hash of state properties to update with new values\n\t *\t@param {function} callback\tA function to be called once component state is updated\n\t */\n\tsetState(state, callback) {\n\t\tlet s = this.state;\n\t\tif (!this.prevState) this.prevState = extend({}, s);\n\t\textend(s, typeof state==='function' ? state(s, this.props) : state);\n\t\tif (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback);\n\t\tenqueueRender(this);\n\t},\n\n\n\t/** Immediately perform a synchronous re-render of the component.\n\t *\t@param {function} callback\t\tA function to be called after component is re-rendered.\n\t *\t@private\n\t */\n\tforceUpdate(callback) {\n\t\tif (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback);\n\t\trenderComponent(this, FORCE_RENDER);\n\t},\n\n\n\t/** Accepts `props` and `state`, and returns a new Virtual DOM tree to build.\n\t *\tVirtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).\n\t *\t@param {object} props\t\tProps (eg: JSX attributes) received from parent element/component\n\t *\t@param {object} state\t\tThe component's current state\n\t *\t@param {object} context\t\tContext object (if a parent component has provided context)\n\t *\t@returns VNode\n\t */\n\trender() {}\n\n});\n","import { diff } from './vdom/diff';\n\n/** Render JSX into a `parent` Element.\n *\t@param {VNode} vnode\t\tA (JSX) VNode to render\n *\t@param {Element} parent\t\tDOM element to render into\n *\t@param {Element} [merge]\tAttempt to re-use an existing DOM tree rooted at `merge`\n *\t@public\n *\n *\t@example\n *\t// render a div into :\n *\trender(
hello!
, document.body);\n *\n *\t@example\n *\t// render a \"Thing\" component into #foo:\n *\tconst Thing = ({ name }) => { name };\n *\trender(, document.querySelector('#foo'));\n */\nexport function render(vnode, parent, merge) {\n\treturn diff(merge, vnode, {}, false, parent, false);\n}\n","import { h, h as createElement } from './h';\nimport { cloneElement } from './clone-element';\nimport { Component } from './component';\nimport { render } from './render';\nimport { rerender } from './render-queue';\nimport options from './options';\n\nexport default {\n\th,\n\tcreateElement,\n\tcloneElement,\n\tComponent,\n\trender,\n\trerender,\n\toptions\n};\n\nexport {\n\th,\n\tcreateElement,\n\tcloneElement,\n\tComponent,\n\trender,\n\trerender,\n\toptions\n};\n"]} -------------------------------------------------------------------------------- /third_party/redux.min-3.7.2.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.Redux={})}(this,function(t){"use strict";function e(t){var e=h.call(t,g),n=t[g];try{t[g]=void 0;var r=!0}catch(t){}var o=v.call(t);return r&&(e?t[g]=n:delete t[g]),o}function n(t){return j.call(t)}function r(t){return null==t?void 0===t?m:w:O&&O in Object(t)?e(t):n(t)}function o(t){return null!=t&&"object"==typeof t}function i(t){if(!o(t)||r(t)!=E)return!1;var e=x(t);if(null===e)return!0;var n=N.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&S.call(n)==A}function u(t,e,n){function r(){p===s&&(p=s.slice())}function o(){return l}function c(t){if("function"!=typeof t)throw Error("Expected listener to be a function.");var e=!0;return r(),p.push(t),function(){if(e){e=!1,r();var n=p.indexOf(t);p.splice(n,1)}}}function a(t){if(!i(t))throw Error("Actions must be plain objects. Use custom middleware for async actions.");if(void 0===t.type)throw Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(y)throw Error("Reducers may not dispatch actions.");try{y=!0,l=d(l,t)}finally{y=!1}for(var e=s=p,n=0;e.length>n;n++)(0,e[n])();return t}var f;if("function"==typeof e&&void 0===n&&(n=e,e=void 0),void 0!==n){if("function"!=typeof n)throw Error("Expected the enhancer to be a function.");return n(u)(t,e)}if("function"!=typeof t)throw Error("Expected the reducer to be a function.");var d=t,l=e,s=[],p=s,y=!1;return a({type:P.INIT}),f={dispatch:a,subscribe:c,getState:o,replaceReducer:function(t){if("function"!=typeof t)throw Error("Expected the nextReducer to be a function.");d=t,a({type:P.INIT})}},f[R]=function(){var t,e=c;return t={subscribe:function(t){function n(){t.next&&t.next(o())}if("object"!=typeof t)throw new TypeError("Expected the observer to be an object.");return n(),{unsubscribe:e(n)}}},t[R]=function(){return this},t},f}function c(t,e){var n=e&&e.type;return"Given "+(n&&'action "'+n+'"'||"an action")+', reducer "'+t+'" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.'}function a(t){Object.keys(t).forEach(function(e){var n=t[e];if(void 0===n(void 0,{type:P.INIT}))throw Error('Reducer "'+e+"\" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined. If you don't want to set a value for this reducer, you can use null instead of undefined.");if(void 0===n(void 0,{type:"@@redux/PROBE_UNKNOWN_ACTION_"+Math.random().toString(36).substring(7).split("").join(".")}))throw Error('Reducer "'+e+"\" returned undefined when probed with a random type. Don't try to handle "+P.INIT+' or other actions in "redux/*" namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined, but can be null.')})}function f(t,e){return function(){return e(t.apply(this,arguments))}}function d(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];return 0===e.length?function(t){return t}:1===e.length?e[0]:e.reduce(function(t,e){return function(){return t(e.apply(void 0,arguments))}})}var l,s="object"==typeof global&&global&&global.Object===Object&&global,p="object"==typeof self&&self&&self.Object===Object&&self,y=(s||p||Function("return this")()).Symbol,b=Object.prototype,h=b.hasOwnProperty,v=b.toString,g=y?y.toStringTag:void 0,j=Object.prototype.toString,w="[object Null]",m="[object Undefined]",O=y?y.toStringTag:void 0,x=function(t,e){return function(n){return t(e(n))}}(Object.getPrototypeOf,Object),E="[object Object]",I=Function.prototype,T=Object.prototype,S=I.toString,N=T.hasOwnProperty,A=S.call(Object),R=function(t){var e,n=t.Symbol;return"function"==typeof n?n.observable?e=n.observable:(e=n("observable"),n.observable=e):e="@@observable",e}(l="undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof module?module:Function("return this")()),P={INIT:"@@redux/INIT"},k=Object.assign||function(t){for(var e=1;arguments.length>e;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t};t.createStore=u,t.combineReducers=function(t){for(var e=Object.keys(t),n={},r=0;e.length>r;r++){var o=e[r];"function"==typeof t[o]&&(n[o]=t[o])}var i=Object.keys(n),u=void 0;try{a(n)}catch(t){u=t}return function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments[1];if(u)throw u;for(var r=!1,o={},a=0;i.length>a;a++){var f=i[a],d=n[f],l=t[f],s=d(l,e);if(void 0===s){var p=c(f,e);throw Error(p)}o[f]=s,r=r||s!==l}return r?o:t}},t.bindActionCreators=function(t,e){if("function"==typeof t)return f(t,e);if("object"!=typeof t||null===t)throw Error("bindActionCreators expected an object or a function, instead received "+(null===t?"null":typeof t)+'. Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?');for(var n=Object.keys(t),r={},o=0;n.length>o;o++){var i=n[o],u=t[i];"function"==typeof u&&(r[i]=f(u,e))}return r},t.applyMiddleware=function(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];return function(t){return function(){for(var n=arguments.length,r=Array(n),o=0;n>o;o++)r[o]=arguments[o];var i=t.apply(void 0,r),u=i.dispatch,c=[],a={getState:i.getState,dispatch:function(){return u.apply(void 0,arguments)}};return c=e.map(function(t){return t(a)}),u=d.apply(void 0,c)(i.dispatch),k({},i,{dispatch:u})}}},t.compose=d,Object.defineProperty(t,"__esModule",{value:!0})}); 2 | -------------------------------------------------------------------------------- /third_party/speedometer-es2015-test-2.0.js: -------------------------------------------------------------------------------- 1 | // src/controller.js 2 | 'use strict'; 3 | 4 | class Controller { 5 | /** 6 | * Take a model & view, then act as controller between them 7 | * @param {object} model The model instance 8 | * @param {object} view The view instance 9 | */ 10 | constructor(model, view) { 11 | this.model = model; 12 | this.view = view; 13 | 14 | this.view.bind('newTodo', title => this.addItem(title)); 15 | this.view.bind('itemEdit', item => this.editItem(item.id)); 16 | this.view.bind('itemEditDone', item => this.editItemSave(item.id, item.title)); 17 | this.view.bind('itemEditCancel', item => this.editItemCancel(item.id)); 18 | this.view.bind('itemRemove', item => this.removeItem(item.id)); 19 | this.view.bind('itemToggle', item => this.toggleComplete(item.id, item.completed)); 20 | this.view.bind('removeCompleted', () => this.removeCompletedItems()); 21 | this.view.bind('toggleAll', status => this.toggleAll(status.completed)); 22 | } 23 | 24 | /** 25 | * Load & Initialize the view 26 | * @param {string} '' | 'active' | 'completed' 27 | */ 28 | setView(hash){ 29 | let route = hash.split('/')[1]; 30 | let page = route || ''; 31 | this._updateFilter(page); 32 | } 33 | 34 | /** 35 | * Event fires on load. Gets all items & displays them 36 | */ 37 | showAll(){ 38 | this.model.read(data => this.view.render('showEntries', data)); 39 | } 40 | 41 | /** 42 | * Renders all active tasks 43 | */ 44 | showActive(){ 45 | this.model.read({completed: false}, data => this.view.render('showEntries', data)); 46 | } 47 | 48 | /** 49 | * Renders all completed tasks 50 | */ 51 | showCompleted(){ 52 | this.model.read({completed: true}, data => this.view.render('showEntries', data)); 53 | } 54 | 55 | /** 56 | * An event to fire whenever you want to add an item. Simply pass in the event 57 | * object and it'll handle the DOM insertion and saving of the new item. 58 | */ 59 | addItem(title){ 60 | if (title.trim() === '') { 61 | return; 62 | } 63 | 64 | this.model.create(title, () => { 65 | this.view.render('clearNewTodo'); 66 | this._filter(true); 67 | }); 68 | } 69 | 70 | /* 71 | * Triggers the item editing mode. 72 | */ 73 | editItem(id){ 74 | this.model.read(id, data => { 75 | let title = data[0].title; 76 | this.view.render('editItem', {id, title}); 77 | }); 78 | } 79 | 80 | /* 81 | * Finishes the item editing mode successfully. 82 | */ 83 | editItemSave(id, title){ 84 | title = title.trim(); 85 | 86 | if (title.length !== 0) { 87 | this.model.update(id, {title}, () => { 88 | this.view.render('editItemDone', {id, title}); 89 | }); 90 | } else { 91 | this.removeItem(id); 92 | } 93 | } 94 | 95 | /* 96 | * Cancels the item editing mode. 97 | */ 98 | editItemCancel(id){ 99 | this.model.read(id, data => { 100 | let title = data[0].title; 101 | this.view.render('editItemDone', {id, title}); 102 | }); 103 | } 104 | 105 | /** 106 | * Find the DOM element with given ID, 107 | * Then remove it from DOM & Storage 108 | */ 109 | removeItem(id){ 110 | this.model.remove(id, () => this.view.render('removeItem', id)); 111 | this._filter(); 112 | } 113 | 114 | /** 115 | * Will remove all completed items from the DOM and storage. 116 | */ 117 | removeCompletedItems(){ 118 | this.model.read({completed: true}, data => { 119 | for (let item of data) { 120 | this.removeItem(item.id); 121 | } 122 | }); 123 | 124 | this._filter(); 125 | } 126 | 127 | /** 128 | * Give it an ID of a model and a checkbox and it will update the item 129 | * in storage based on the checkbox's state. 130 | * 131 | * @param {number} id The ID of the element to complete or uncomplete 132 | * @param {object} checkbox The checkbox to check the state of complete 133 | * or not 134 | * @param {boolean|undefined} silent Prevent re-filtering the todo items 135 | */ 136 | toggleComplete(id, completed, silent){ 137 | this.model.update(id, {completed}, () => { 138 | this.view.render('elementComplete', {id, completed}); 139 | }); 140 | 141 | if (!silent) { 142 | this._filter(); 143 | } 144 | } 145 | 146 | /** 147 | * Will toggle ALL checkboxes' on/off state and completeness of models. 148 | * Just pass in the event object. 149 | */ 150 | toggleAll(completed){ 151 | this.model.read({completed: !completed}, data => { 152 | for (let item of data) { 153 | this.toggleComplete(item.id, completed, true); 154 | } 155 | }); 156 | 157 | this._filter(); 158 | } 159 | 160 | /** 161 | * Updates the pieces of the page which change depending on the remaining 162 | * number of todos. 163 | */ 164 | _updateCount(){ 165 | this.model.getCount(todos => { 166 | const completed = todos.completed; 167 | const visible = completed > 0; 168 | const checked = completed === todos.total; 169 | 170 | this.view.render('updateElementCount', todos.active); 171 | this.view.render('clearCompletedButton', {completed, visible}); 172 | 173 | this.view.render('toggleAll', {checked}); 174 | this.view.render('contentBlockVisibility', {visible: todos.total > 0}); 175 | }); 176 | } 177 | 178 | /** 179 | * Re-filters the todo items, based on the active route. 180 | * @param {boolean|undefined} force forces a re-painting of todo items. 181 | */ 182 | _filter(force){ 183 | let active = this._activeRoute; 184 | const activeRoute = active.charAt(0).toUpperCase() + active.substr(1); 185 | 186 | // Update the elements on the page, which change with each completed todo 187 | this._updateCount(); 188 | 189 | // If the last active route isn't "All", or we're switching routes, we 190 | // re-create the todo item elements, calling: 191 | // this.show[All|Active|Completed]() 192 | if (force || this._lastActiveRoute !== 'All' || this._lastActiveRoute !== activeRoute) { 193 | this['show' + activeRoute](); 194 | } 195 | 196 | this._lastActiveRoute = activeRoute; 197 | } 198 | 199 | /** 200 | * Simply updates the filter nav's selected states 201 | */ 202 | _updateFilter(currentPage){ 203 | // Store a reference to the active route, allowing us to re-filter todo 204 | // items as they are marked complete or incomplete. 205 | this._activeRoute = currentPage; 206 | 207 | if (currentPage === '') { 208 | this._activeRoute = 'All'; 209 | } 210 | 211 | this._filter(); 212 | 213 | this.view.render('setFilter', currentPage); 214 | } 215 | } 216 | // src/helpers.js 217 | 'use strict'; 218 | 219 | 220 | // Allow for looping on nodes by chaining: 221 | // qsa('.foo').forEach(function () {}) 222 | NodeList.prototype.forEach = Array.prototype.forEach; 223 | 224 | // Get element(s) by CSS selector: 225 | function qs(selector, scope) { 226 | return (scope || document).querySelector(selector); 227 | } 228 | 229 | function qsa(selector, scope) { 230 | return (scope || document).querySelectorAll(selector); 231 | } 232 | 233 | // addEventListener wrapper: 234 | function $on(target, type, callback, useCapture) { 235 | target.addEventListener(type, callback, !!useCapture); 236 | } 237 | 238 | // Attach a handler to event for all elements that match the selector, 239 | // now or in the future, based on a root element 240 | function $delegate(target, selector, type, handler) { 241 | let dispatchEvent = event => { 242 | const targetElement = event.target; 243 | const potentialElements = qsa(selector, target); 244 | const hasMatch = Array.prototype.indexOf.call(potentialElements, targetElement) >= 0; 245 | 246 | if (hasMatch) { 247 | handler.call(targetElement, event); 248 | } 249 | }; 250 | 251 | // https://developer.mozilla.org/en-US/docs/Web/Events/blur 252 | const useCapture = type === 'blur' || type === 'focus'; 253 | 254 | $on(target, type, dispatchEvent, useCapture); 255 | } 256 | 257 | // Find the element's parent with the given tag name: 258 | // $parent(qs('a'), 'div') 259 | function $parent(element, tagName) { 260 | if (!element.parentNode) { 261 | return; 262 | } 263 | 264 | if (element.parentNode.tagName.toLowerCase() === tagName.toLowerCase()) { 265 | return element.parentNode; 266 | } 267 | 268 | return $parent(element.parentNode, tagName); 269 | } 270 | // src/template.js 271 | 'use strict'; 272 | 273 | 274 | const htmlEscapes = { 275 | '&': '&', 276 | '<': '<', 277 | '>': '>', 278 | '"': '"', 279 | '\'': ''', 280 | '`': '`' 281 | }; 282 | 283 | const reUnescapedHtml = /[&<>"'`]/g; 284 | const reHasUnescapedHtml = new RegExp(reUnescapedHtml.source); 285 | 286 | let escape = str => (str && reHasUnescapedHtml.test(str)) ? str.replace(reUnescapedHtml, escapeHtmlChar) : str; 287 | let escapeHtmlChar = chr => htmlEscapes[chr]; 288 | 289 | class Template { 290 | constructor() { 291 | this.defaultTemplate = ` 292 |
  • 293 |
    294 | 295 | 296 | 297 |
    298 |
  • 299 | `; 300 | } 301 | 302 | /** 303 | * Creates an
  • HTML string and returns it for placement in your app. 304 | * 305 | * NOTE: In real life you should be using a templating engine such as Mustache 306 | * or Handlebars, however, this is a vanilla JS example. 307 | * 308 | * @param {object} data The object containing keys you want to find in the 309 | * template to replace. 310 | * @returns {string} HTML String of an
  • element 311 | * 312 | * @example 313 | * view.show({ 314 | * id: 1, 315 | * title: "Hello World", 316 | * completed: 0, 317 | * }) 318 | */ 319 | show(data){ 320 | let i = 0; 321 | let view = ''; 322 | const len = data.length; 323 | 324 | for (i; i < len; i++) { 325 | let completed = ''; 326 | let checked = ''; 327 | let template = this.defaultTemplate; 328 | 329 | if (data[i].completed) { 330 | completed = 'completed'; 331 | checked = 'checked'; 332 | } 333 | 334 | template = template.replace('{{id}}', data[i].id); 335 | template = template.replace('{{title}}', escape(data[i].title)); 336 | template = template.replace('{{completed}}', completed); 337 | template = template.replace('{{checked}}', checked); 338 | 339 | view += template; 340 | } 341 | 342 | return view; 343 | } 344 | 345 | /** 346 | * Displays a counter of how many to dos are left to complete 347 | * 348 | * @param {number} activeTodos The number of active todos. 349 | * @returns {string} String containing the count 350 | */ 351 | itemCounter(activeTodos){ 352 | let plural = activeTodos === 1 ? '' : 's'; 353 | return `${activeTodos} item${plural} left`; 354 | } 355 | 356 | /** 357 | * Updates the text within the "Clear completed" button 358 | * 359 | * @param {[type]} completedTodos The number of completed todos. 360 | * @returns {string} String containing the count 361 | */ 362 | clearCompletedButton(completedTodos){ 363 | return (completedTodos > 0) ? 'Clear completed' : ''; 364 | } 365 | } 366 | // src/store.js 367 | /*jshint eqeqeq:false */ 368 | 'use strict'; 369 | 370 | /** 371 | * Creates a new client side storage object and will create an empty 372 | * collection if no collection already exists. 373 | * 374 | * @param {string} name The name of our DB we want to use 375 | * @param {function} callback Our fake DB uses callbacks because in 376 | * real life you probably would be making AJAX calls 377 | */ 378 | class Store { 379 | constructor(name, callback) { 380 | this._dbName = name; 381 | this.memoryStorage = this.memoryStorage || {}; 382 | 383 | if (!this.memoryStorage[name]) { 384 | let data = { 385 | todos: [] 386 | }; 387 | 388 | this.memoryStorage[name] = JSON.stringify(data); 389 | } 390 | 391 | if (callback) { 392 | callback.call(this, JSON.parse(this.memoryStorage[name])); 393 | } 394 | } 395 | 396 | /** 397 | * Finds items based on a query given as a JS object 398 | * 399 | * @param {object} query The query to match against (i.e. {foo: 'bar'}) 400 | * @param {function} callback The callback to fire when the query has 401 | * completed running 402 | * 403 | * @example 404 | * db.find({foo: 'bar', hello: 'world'}, function (data) { 405 | * // data will return any items that have foo: bar and 406 | * // hello: world in their properties 407 | * }) 408 | */ 409 | find(query, callback){ 410 | if (!callback) { 411 | return; 412 | } 413 | 414 | let todos = JSON.parse(this.memoryStorage[this._dbName]).todos; 415 | 416 | callback.call(this, todos.filter(todo => { 417 | for (let q in query) { 418 | if (query[q] !== todo[q]) { 419 | return false; 420 | } 421 | } 422 | return true; 423 | })); 424 | } 425 | 426 | /** 427 | * Will retrieve all data from the collection 428 | * 429 | * @param {function} callback The callback to fire upon retrieving data 430 | */ 431 | findAll(callback){ 432 | if (callback) { 433 | callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); 434 | } 435 | } 436 | 437 | /** 438 | * Will save the given data to the DB. If no item exists it will create a new 439 | * item, otherwise it'll simply update an existing item's properties 440 | * 441 | * @param {object} updateData The data to save back into the DB 442 | * @param {function} callback The callback to fire after saving 443 | * @param {number} id An optional param to enter an ID of an item to update 444 | */ 445 | save(updateData, callback, id){ 446 | const data = JSON.parse(this.memoryStorage[this._dbName]); 447 | let todos = data.todos; 448 | const len = todos.length; 449 | 450 | // If an ID was actually given, find the item and update each property 451 | if (id) { 452 | for (let i = 0; i < len; i++) { 453 | if (todos[i].id === id) { 454 | for (let key in updateData) { 455 | todos[i][key] = updateData[key]; 456 | } 457 | break; 458 | } 459 | } 460 | 461 | this.memoryStorage[this._dbName] = JSON.stringify(data); 462 | 463 | if (callback) { 464 | callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); 465 | } 466 | } else { 467 | // Generate an ID 468 | updateData.id = new Date().getTime(); 469 | 470 | todos.push(updateData); 471 | this.memoryStorage[this._dbName] = JSON.stringify(data); 472 | 473 | if (callback) { 474 | callback.call(this, [updateData]); 475 | } 476 | } 477 | } 478 | 479 | /** 480 | * Will remove an item from the Store based on its ID 481 | * 482 | * @param {number} id The ID of the item you want to remove 483 | * @param {function} callback The callback to fire after saving 484 | */ 485 | remove(id, callback){ 486 | const data = JSON.parse(this.memoryStorage[this._dbName]); 487 | let todos = data.todos; 488 | const len = todos.length; 489 | 490 | for (let i = 0; i < todos.length; i++) { 491 | if (todos[i].id == id) { 492 | todos.splice(i, 1); 493 | break; 494 | } 495 | } 496 | 497 | this.memoryStorage[this._dbName] = JSON.stringify(data); 498 | 499 | if (callback) { 500 | callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); 501 | } 502 | } 503 | 504 | /** 505 | * Will drop all storage and start fresh 506 | * 507 | * @param {function} callback The callback to fire after dropping the data 508 | */ 509 | drop(callback){ 510 | this.memoryStorage[this._dbName] = JSON.stringify({todos: []}); 511 | 512 | if (callback) { 513 | callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); 514 | } 515 | } 516 | } 517 | // src/model.js 518 | 'use strict'; 519 | 520 | 521 | /** 522 | * Creates a new Model instance and hooks up the storage. 523 | * @constructor 524 | * @param {object} storage A reference to the client side storage class 525 | */ 526 | class Model { 527 | constructor(storage) { 528 | this.storage = storage; 529 | } 530 | 531 | /** 532 | * Creates a new todo model 533 | * 534 | * @param {string} [title] The title of the task 535 | * @param {function} [callback] The callback to fire after the model is created 536 | */ 537 | create(title, callback){ 538 | title = title || ''; 539 | 540 | let newItem = { 541 | title: title.trim(), 542 | completed: false 543 | }; 544 | 545 | this.storage.save(newItem, callback); 546 | } 547 | 548 | /** 549 | * Finds and returns a model in storage. If no query is given it'll simply 550 | * return everything. If you pass in a string or number it'll look that up as 551 | * the ID of the model to find. Lastly, you can pass it an object to match 552 | * against. 553 | * 554 | * @param {string|number|object} [query] A query to match models against 555 | * @param {function} [callback] The callback to fire after the model is found 556 | * 557 | * @example 558 | * model.read(1, func) // Will find the model with an ID of 1 559 | * model.read('1') // Same as above 560 | * //Below will find a model with foo equalling bar and hello equalling world. 561 | * model.read({ foo: 'bar', hello: 'world' }) 562 | */ 563 | read(query, callback){ 564 | const queryType = typeof query; 565 | 566 | if (queryType === 'function') { 567 | callback = query; 568 | this.storage.findAll(callback); 569 | } else if (queryType === 'string' || queryType === 'number') { 570 | query = parseInt(query, 10); 571 | this.storage.find({id: query}, callback); 572 | } else { 573 | this.storage.find(query, callback); 574 | } 575 | } 576 | 577 | /** 578 | * Updates a model by giving it an ID, data to update, and a callback to fire when 579 | * the update is complete. 580 | * 581 | * @param {number} id The id of the model to update 582 | * @param {object} data The properties to update and their new value 583 | * @param {function} callback The callback to fire when the update is complete. 584 | */ 585 | update(id, data, callback){ 586 | this.storage.save(data, callback, id); 587 | } 588 | 589 | /** 590 | * Removes a model from storage 591 | * 592 | * @param {number} id The ID of the model to remove 593 | * @param {function} callback The callback to fire when the removal is complete. 594 | */ 595 | remove(id, callback){ 596 | this.storage.remove(id, callback); 597 | } 598 | 599 | /** 600 | * WARNING: Will remove ALL data from storage. 601 | * 602 | * @param {function} callback The callback to fire when the storage is wiped. 603 | */ 604 | removeAll(callback){ 605 | this.storage.drop(callback); 606 | } 607 | 608 | /** 609 | * Returns a count of all todos 610 | */ 611 | getCount(callback){ 612 | let todos = { 613 | active: 0, 614 | completed: 0, 615 | total: 0 616 | }; 617 | 618 | this.storage.findAll(data => { 619 | for (let todo of data) { 620 | if (todo.completed) { 621 | todos.completed++; 622 | } else { 623 | todos.active++; 624 | } 625 | 626 | todos.total++; 627 | } 628 | 629 | if (callback) { 630 | callback(todos); 631 | } 632 | }); 633 | } 634 | } 635 | // src/view.js 636 | 'use strict'; 637 | 638 | 639 | // import {qs, qsa, $on, $parent, $delegate} from './helpers'; 640 | 641 | let _itemId = element => parseInt($parent(element, 'li').dataset.id, 10); 642 | 643 | let _setFilter = currentPage => { 644 | qs('.filters .selected').className = ''; 645 | qs(`.filters [href="#/${currentPage}"]`).className = 'selected'; 646 | }; 647 | 648 | let _elementComplete = (id, completed) => { 649 | let listItem = qs(`[data-id="${id}"]`); 650 | 651 | if (!listItem) { 652 | return; 653 | } 654 | 655 | listItem.className = completed ? 'completed' : ''; 656 | 657 | // In case it was toggled from an event and not by clicking the checkbox 658 | qs('input', listItem).checked = completed; 659 | }; 660 | 661 | let _editItem = (id, title) => { 662 | let listItem = qs(`[data-id="${id}"]`); 663 | 664 | if (!listItem) { 665 | return; 666 | } 667 | 668 | listItem.className += ' editing'; 669 | 670 | let input = document.createElement('input'); 671 | input.className = 'edit'; 672 | 673 | listItem.appendChild(input); 674 | input.focus(); 675 | input.value = title; 676 | }; 677 | 678 | /** 679 | * View that abstracts away the browser's DOM completely. 680 | * It has two simple entry points: 681 | * 682 | * - bind(eventName, handler) 683 | * Takes a todo application event and registers the handler 684 | * - render(command, parameterObject) 685 | * Renders the given command with the options 686 | */ 687 | class View { 688 | constructor(template) { 689 | this.template = template; 690 | 691 | this.ENTER_KEY = 13; 692 | this.ESCAPE_KEY = 27; 693 | 694 | this.$todoList = qs('.todo-list'); 695 | this.$todoItemCounter = qs('.todo-count'); 696 | this.$clearCompleted = qs('.clear-completed'); 697 | this.$main = qs('.main'); 698 | this.$footer = qs('.footer'); 699 | this.$toggleAll = qs('.toggle-all'); 700 | this.$newTodo = qs('.new-todo'); 701 | 702 | this.viewCommands = { 703 | showEntries: parameter => this.$todoList.innerHTML = this.template.show(parameter), 704 | removeItem: parameter => this._removeItem(parameter), 705 | updateElementCount: parameter => this.$todoItemCounter.innerHTML = this.template.itemCounter(parameter), 706 | clearCompletedButton: parameter => this._clearCompletedButton(parameter.completed, parameter.visible), 707 | contentBlockVisibility: parameter => this.$main.style.display = this.$footer.style.display = parameter.visible ? 'block' : 'none', 708 | toggleAll: parameter => this.$toggleAll.checked = parameter.checked, 709 | setFilter: parameter => _setFilter(parameter), 710 | clearNewTodo: parameter => this.$newTodo.value = '', 711 | elementComplete: parameter => _elementComplete(parameter.id, parameter.completed), 712 | editItem: parameter => _editItem(parameter.id, parameter.title), 713 | editItemDone: parameter => this._editItemDone(parameter.id, parameter.title), 714 | }; 715 | } 716 | 717 | _removeItem(id) { 718 | let elem = qs(`[data-id="${id}"]`); 719 | 720 | if (elem) { 721 | this.$todoList.removeChild(elem); 722 | } 723 | } 724 | 725 | _clearCompletedButton(completedCount, visible) { 726 | this.$clearCompleted.innerHTML = this.template.clearCompletedButton(completedCount); 727 | this.$clearCompleted.style.display = visible ? 'block' : 'none'; 728 | } 729 | 730 | _editItemDone(id, title) { 731 | let listItem = qs(`[data-id="${id}"]`); 732 | 733 | if (!listItem) { 734 | return; 735 | } 736 | 737 | let input = qs('input.edit', listItem); 738 | listItem.removeChild(input); 739 | 740 | listItem.className = listItem.className.replace(' editing', ''); 741 | 742 | qsa('label', listItem).forEach(label => label.textContent = title); 743 | } 744 | 745 | render(viewCmd, parameter) { 746 | this.viewCommands[viewCmd](parameter); 747 | } 748 | 749 | _bindItemEditDone(handler) { 750 | let self = this; 751 | 752 | $delegate(self.$todoList, 'li .edit', 'blur', function () { 753 | if (!this.dataset.iscanceled) { 754 | handler({ 755 | id: _itemId(this), 756 | title: this.value 757 | }); 758 | } 759 | }); 760 | 761 | // Remove the cursor from the input when you hit enter just like if it were a real form 762 | $delegate(self.$todoList, 'li .edit', 'keypress', function (event) { 763 | if (event.keyCode === self.ENTER_KEY) { 764 | this.blur(); 765 | } 766 | }); 767 | } 768 | 769 | _bindItemEditCancel(handler) { 770 | let self = this; 771 | 772 | $delegate(self.$todoList, 'li .edit', 'keyup', function (event) { 773 | if (event.keyCode === self.ESCAPE_KEY) { 774 | let id = _itemId(this); 775 | this.dataset.iscanceled = true; 776 | this.blur(); 777 | 778 | handler({ id }); 779 | } 780 | }); 781 | } 782 | 783 | bind(event, handler) { 784 | if (event === 'newTodo') { 785 | $on(this.$newTodo, 'change', () => handler(this.$newTodo.value)); 786 | } else if (event === 'removeCompleted') { 787 | $on(this.$clearCompleted, 'click', handler); 788 | } else if (event === 'toggleAll') { 789 | $on(this.$toggleAll, 'click', function(){ 790 | handler({completed: this.checked}); 791 | }); 792 | } else if (event === 'itemEdit') { 793 | $delegate(this.$todoList, 'li label', 'dblclick', function(){ 794 | handler({id: _itemId(this)}); 795 | }); 796 | } else if (event === 'itemRemove') { 797 | $delegate(this.$todoList, '.destroy', 'click', function(){ 798 | handler({id: _itemId(this)}); 799 | }); 800 | } else if (event === 'itemToggle') { 801 | $delegate(this.$todoList, '.toggle', 'click', function(){ 802 | handler({ 803 | id: _itemId(this), 804 | completed: this.checked 805 | }); 806 | }); 807 | } else if (event === 'itemEditDone') { 808 | this._bindItemEditDone(handler); 809 | } else if (event === 'itemEditCancel') { 810 | this._bindItemEditCancel(handler); 811 | } 812 | } 813 | } 814 | // src/app.js 815 | 'use strict'; 816 | 817 | let todo; 818 | const setView = () => todo.controller.setView(document.location.hash); 819 | 820 | class Todo { 821 | /** 822 | * Init new Todo List 823 | * @param {string} The name of your list 824 | */ 825 | constructor(name) { 826 | this.storage = new Store(name); 827 | this.model = new Model(this.storage); 828 | 829 | this.template = new Template(); 830 | this.view = new View(this.template); 831 | 832 | this.controller = new Controller(this.model, this.view); 833 | } 834 | } 835 | 836 | $on(window, 'load', () => { 837 | todo = new Todo('todos-vanillajs'); 838 | setView(); 839 | }); 840 | 841 | $on(window, 'hashchange', setView); 842 | -------------------------------------------------------------------------------- /third_party/todomvc/react/app.jsx: -------------------------------------------------------------------------------- 1 | /*jshint quotmark:false */ 2 | /*jshint white:false */ 3 | /*jshint trailing:false */ 4 | /*jshint newcap:false */ 5 | /*global React, Router*/ 6 | var app = app || {}; 7 | 8 | (function () { 9 | 'use strict'; 10 | 11 | app.ALL_TODOS = 'all'; 12 | app.ACTIVE_TODOS = 'active'; 13 | app.COMPLETED_TODOS = 'completed'; 14 | var TodoFooter = app.TodoFooter; 15 | var TodoItem = app.TodoItem; 16 | 17 | var ENTER_KEY = 13; 18 | 19 | var TodoApp = React.createClass({ 20 | getInitialState: function () { 21 | return { 22 | nowShowing: app.ALL_TODOS, 23 | editing: null, 24 | newTodo: '' 25 | }; 26 | }, 27 | 28 | componentDidMount: function () { 29 | var setState = this.setState; 30 | var router = Router({ 31 | '/': setState.bind(this, {nowShowing: app.ALL_TODOS}), 32 | '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}), 33 | '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS}) 34 | }); 35 | router.init('/'); 36 | }, 37 | 38 | handleChange: function (event) { 39 | this.setState({newTodo: event.target.value}); 40 | }, 41 | 42 | handleNewTodoKeyDown: function (event) { 43 | if (event.keyCode !== ENTER_KEY) { 44 | return; 45 | } 46 | 47 | event.preventDefault(); 48 | 49 | var val = this.state.newTodo.trim(); 50 | 51 | if (val) { 52 | this.props.model.addTodo(val); 53 | this.setState({newTodo: ''}); 54 | } 55 | }, 56 | 57 | toggleAll: function (event) { 58 | var checked = event.target.checked; 59 | this.props.model.toggleAll(checked); 60 | }, 61 | 62 | toggle: function (todoToToggle) { 63 | this.props.model.toggle(todoToToggle); 64 | }, 65 | 66 | destroy: function (todo) { 67 | this.props.model.destroy(todo); 68 | }, 69 | 70 | edit: function (todo) { 71 | this.setState({editing: todo.id}); 72 | }, 73 | 74 | save: function (todoToSave, text) { 75 | this.props.model.save(todoToSave, text); 76 | this.setState({editing: null}); 77 | }, 78 | 79 | cancel: function () { 80 | this.setState({editing: null}); 81 | }, 82 | 83 | clearCompleted: function () { 84 | this.props.model.clearCompleted(); 85 | }, 86 | 87 | render: function () { 88 | var footer; 89 | var main; 90 | var todos = this.props.model.todos; 91 | 92 | var shownTodos = todos.filter(function (todo) { 93 | switch (this.state.nowShowing) { 94 | case app.ACTIVE_TODOS: 95 | return !todo.completed; 96 | case app.COMPLETED_TODOS: 97 | return todo.completed; 98 | default: 99 | return true; 100 | } 101 | }, this); 102 | 103 | var todoItems = shownTodos.map(function (todo) { 104 | return ( 105 | 115 | ); 116 | }, this); 117 | 118 | var activeTodoCount = todos.reduce(function (accum, todo) { 119 | return todo.completed ? accum : accum + 1; 120 | }, 0); 121 | 122 | var completedCount = todos.length - activeTodoCount; 123 | 124 | if (activeTodoCount || completedCount) { 125 | footer = 126 | ; 132 | } 133 | 134 | if (todos.length) { 135 | main = ( 136 |
    137 | 143 |
      144 | {todoItems} 145 |
    146 |
    147 | ); 148 | } 149 | 150 | return ( 151 |
    152 |
    153 |

    todos

    154 | 162 |
    163 | {main} 164 | {footer} 165 |
    166 | ); 167 | } 168 | }); 169 | 170 | var model = new app.TodoModel('react-todos'); 171 | 172 | function render() { 173 | React.render( 174 | , 175 | document.getElementsByClassName('todoapp')[0] 176 | ); 177 | } 178 | 179 | model.subscribe(render); 180 | render(); 181 | })(); 182 | -------------------------------------------------------------------------------- /third_party/todomvc/react/footer.jsx: -------------------------------------------------------------------------------- 1 | /*jshint quotmark:false */ 2 | /*jshint white:false */ 3 | /*jshint trailing:false */ 4 | /*jshint newcap:false */ 5 | /*global React */ 6 | var app = app || {}; 7 | 8 | (function () { 9 | 'use strict'; 10 | 11 | app.TodoFooter = React.createClass({ 12 | render: function () { 13 | var activeTodoWord = app.Utils.pluralize(this.props.count, 'item'); 14 | var clearButton = null; 15 | 16 | if (this.props.completedCount > 0) { 17 | clearButton = ( 18 | 23 | ); 24 | } 25 | 26 | var nowShowing = this.props.nowShowing; 27 | return ( 28 | 59 | ); 60 | } 61 | }); 62 | })(); 63 | -------------------------------------------------------------------------------- /third_party/todomvc/react/todoItem.jsx: -------------------------------------------------------------------------------- 1 | /*jshint quotmark: false */ 2 | /*jshint white: false */ 3 | /*jshint trailing: false */ 4 | /*jshint newcap: false */ 5 | /*global React */ 6 | var app = app || {}; 7 | 8 | (function () { 9 | 'use strict'; 10 | 11 | var ESCAPE_KEY = 27; 12 | var ENTER_KEY = 13; 13 | 14 | app.TodoItem = React.createClass({ 15 | handleSubmit: function (event) { 16 | var val = this.state.editText.trim(); 17 | if (val) { 18 | this.props.onSave(val); 19 | this.setState({editText: val}); 20 | } else { 21 | this.props.onDestroy(); 22 | } 23 | }, 24 | 25 | handleEdit: function () { 26 | this.props.onEdit(); 27 | this.setState({editText: this.props.todo.title}); 28 | }, 29 | 30 | handleKeyDown: function (event) { 31 | if (event.which === ESCAPE_KEY) { 32 | this.setState({editText: this.props.todo.title}); 33 | this.props.onCancel(event); 34 | } else if (event.which === ENTER_KEY) { 35 | this.handleSubmit(event); 36 | } 37 | }, 38 | 39 | handleChange: function (event) { 40 | if (this.props.editing) { 41 | this.setState({editText: event.target.value}); 42 | } 43 | }, 44 | 45 | getInitialState: function () { 46 | return {editText: this.props.todo.title}; 47 | }, 48 | 49 | /** 50 | * This is a completely optional performance enhancement that you can 51 | * implement on any React component. If you were to delete this method 52 | * the app would still work correctly (and still be very performant!), we 53 | * just use it as an example of how little code it takes to get an order 54 | * of magnitude performance improvement. 55 | */ 56 | shouldComponentUpdate: function (nextProps, nextState) { 57 | return ( 58 | nextProps.todo !== this.props.todo || 59 | nextProps.editing !== this.props.editing || 60 | nextState.editText !== this.state.editText 61 | ); 62 | }, 63 | 64 | /** 65 | * Safely manipulate the DOM after updating the state when invoking 66 | * `this.props.onEdit()` in the `handleEdit` method above. 67 | * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate 68 | * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate 69 | */ 70 | componentDidUpdate: function (prevProps) { 71 | if (!prevProps.editing && this.props.editing) { 72 | var node = React.findDOMNode(this.refs.editField); 73 | node.focus(); 74 | node.setSelectionRange(node.value.length, node.value.length); 75 | } 76 | }, 77 | 78 | render: function () { 79 | return ( 80 |
  • 84 |
    85 | 91 | 94 |
    96 | 104 |
  • 105 | ); 106 | } 107 | }); 108 | })(); 109 | -------------------------------------------------------------------------------- /third_party/underscore.min-1.8.3.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"underscore-min.js","sources":["underscore.js"],"names":["createReduce","dir","iterator","obj","iteratee","memo","keys","index","length","currentKey","context","optimizeCb","isArrayLike","_","arguments","createPredicateIndexFinder","array","predicate","cb","getLength","createIndexFinder","predicateFind","sortedIndex","item","idx","i","Math","max","min","slice","call","isNaN","collectNonEnumProps","nonEnumIdx","nonEnumerableProps","constructor","proto","isFunction","prototype","ObjProto","prop","has","contains","push","root","this","previousUnderscore","ArrayProto","Array","Object","FuncProto","Function","toString","hasOwnProperty","nativeIsArray","isArray","nativeKeys","nativeBind","bind","nativeCreate","create","Ctor","_wrapped","exports","module","VERSION","func","argCount","value","other","collection","accumulator","apply","identity","isObject","matcher","property","Infinity","createAssigner","keysFunc","undefinedOnly","source","l","key","baseCreate","result","MAX_ARRAY_INDEX","pow","each","forEach","map","collect","results","reduce","foldl","inject","reduceRight","foldr","find","detect","findIndex","findKey","filter","select","list","reject","negate","every","all","some","any","includes","include","fromIndex","guard","values","indexOf","invoke","method","args","isFunc","pluck","where","attrs","findWhere","computed","lastComputed","shuffle","rand","set","shuffled","random","sample","n","sortBy","criteria","sort","left","right","a","b","group","behavior","groupBy","indexBy","countBy","toArray","size","partition","pass","fail","first","head","take","initial","last","rest","tail","drop","compact","flatten","input","shallow","strict","startIndex","output","isArguments","j","len","without","difference","uniq","unique","isSorted","isBoolean","seen","union","intersection","argsLength","zip","unzip","object","findLastIndex","low","high","mid","floor","lastIndexOf","range","start","stop","step","ceil","executeBound","sourceFunc","boundFunc","callingContext","self","TypeError","bound","concat","partial","boundArgs","position","bindAll","Error","memoize","hasher","cache","address","delay","wait","setTimeout","defer","throttle","options","timeout","previous","later","leading","now","remaining","clearTimeout","trailing","debounce","immediate","timestamp","callNow","wrap","wrapper","compose","after","times","before","once","hasEnumBug","propertyIsEnumerable","allKeys","mapObject","pairs","invert","functions","methods","names","extend","extendOwn","assign","pick","oiteratee","omit","String","defaults","props","clone","tap","interceptor","isMatch","eq","aStack","bStack","className","areArrays","aCtor","bCtor","pop","isEqual","isEmpty","isString","isElement","nodeType","type","name","Int8Array","isFinite","parseFloat","isNumber","isNull","isUndefined","noConflict","constant","noop","propertyOf","matches","accum","Date","getTime","escapeMap","&","<",">","\"","'","`","unescapeMap","createEscaper","escaper","match","join","testRegexp","RegExp","replaceRegexp","string","test","replace","escape","unescape","fallback","idCounter","uniqueId","prefix","id","templateSettings","evaluate","interpolate","noMatch","escapes","\\","\r","\n","
","
","escapeChar","template","text","settings","oldSettings","offset","variable","render","e","data","argument","chain","instance","_chain","mixin","valueOf","toJSON","define","amd"],"mappings":"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"} -------------------------------------------------------------------------------- /tools/hooks/pre-commit.js: -------------------------------------------------------------------------------- 1 | // Check if benchmark dependencies have explicit versions 2 | const semver = require("semver"); 3 | const { EOL } = require("os"); 4 | 5 | const { dependencies } = require("../../package.json"); 6 | const { targetList } = require("../../src/cli-flags-helper"); 7 | 8 | // babel -> @babel/standalone 9 | targetList.delete("babel"); 10 | targetList.add("@babel/standalone"); 11 | 12 | // postcss requires autoprefixer and postcss-nested 13 | targetList.add("autoprefixer"); 14 | targetList.add("postcss-nested"); 15 | 16 | const invalid = [...targetList].reduce((list, dependency) => { 17 | const version = dependencies[dependency]; 18 | if (!semver.valid(version)) { 19 | list.push({ dependency, version }); 20 | } 21 | return list; 22 | }, []); 23 | 24 | 25 | if (invalid.length > 0) { 26 | console.error( 27 | `ERROR: Benchmark dependencies must have explicit versions.${EOL}` 28 | ); 29 | console.error(`Invalid dependencies:`); 30 | invalid.forEach(({ dependency, version }) => { 31 | console.error(`- ${dependency}: ${version}`); 32 | }); 33 | 34 | process.exit(1); 35 | } 36 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 6 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 7 | const path = require("path"); 8 | const webpack = require("webpack"); 9 | const targetList = require("./src/cli-flags-helper").targetList; 10 | 11 | function getTarget(env) { 12 | return env && targetList.has(env.only) && env.only; 13 | } 14 | 15 | module.exports = env => [ 16 | { 17 | context: path.resolve("src"), 18 | entry: "./cli.js", 19 | output: { 20 | filename: "cli.js", 21 | path: path.resolve("dist") 22 | }, 23 | bail: true, 24 | resolve: { 25 | alias: { 26 | fs: require.resolve("./src/vfs"), 27 | module: require.resolve("./src/mocks/dummy") 28 | } 29 | }, 30 | plugins: [ 31 | new webpack.BannerPlugin({ 32 | banner: 33 | "// Required for JavaScript engine shells.\n" + 34 | "var global = this;\n" + 35 | "if (typeof console === 'undefined') {\n" + 36 | " console = {log: print};\n" + 37 | "}", 38 | raw: true 39 | }), 40 | new webpack.DefinePlugin({ 41 | ONLY: JSON.stringify(getTarget(env)) 42 | }) 43 | ] 44 | }, 45 | { 46 | context: path.resolve("src"), 47 | entry: "./bootstrap.js", 48 | output: { 49 | filename: "browser.js", 50 | path: path.resolve("dist") 51 | }, 52 | bail: true, 53 | resolve: { 54 | alias: { 55 | define: require.resolve("./src/mocks/dummy"), 56 | fs: require.resolve("./src/vfs"), 57 | module: require.resolve("./src/mocks/dummy") 58 | } 59 | }, 60 | plugins: [ 61 | new CopyWebpackPlugin([{ from: "style.css" }, { from: "Logo.png" }]), 62 | new webpack.BannerPlugin({ 63 | banner: 64 | "// Work-around for the weird JaegerMonkey\n" + 65 | "// work-around inside benchmark.js.\n" + 66 | "const define = { amd: {} };\n", 67 | raw: true 68 | }), 69 | new HtmlWebpackPlugin({ 70 | template: "./index.html", 71 | inject: "head" 72 | }), 73 | new webpack.DefinePlugin({ 74 | ONLY: JSON.stringify(getTarget(env)) 75 | }) 76 | ] 77 | } 78 | ]; 79 | --------------------------------------------------------------------------------