Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- .eslintrc.js +14 -0
- .github/workflows/main.yml +27 -0
- .github/workflows/publish.yml +28 -0
- .gitignore +4 -0
- .prettierignore +2 -0
- CHANGELOG.md +15 -0
- LICENSE +21 -0
- README.md +30 -10
- index.html +24 -0
- package.json +54 -0
- prettier.config.js +5 -0
- src/index.js +1 -0
- src/style.scss +120 -0
- src/template.hbs +68 -0
- src/timing.js +236 -0
- src/util.js +16 -0
- webpack.config.js +73 -0
.eslintrc.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
module.exports = {
|
| 2 |
+
env: {
|
| 3 |
+
browser: true,
|
| 4 |
+
es6: true,
|
| 5 |
+
commonjs: true
|
| 6 |
+
},
|
| 7 |
+
extends: 'eslint:recommended',
|
| 8 |
+
rules: {
|
| 9 |
+
quotes: ['error', 'single']
|
| 10 |
+
},
|
| 11 |
+
parserOptions: {
|
| 12 |
+
sourceType: 'module'
|
| 13 |
+
}
|
| 14 |
+
}
|
.github/workflows/main.yml
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: CI
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- 'master'
|
| 7 |
+
paths:
|
| 8 |
+
- 'src/**/*'
|
| 9 |
+
|
| 10 |
+
jobs:
|
| 11 |
+
ci:
|
| 12 |
+
|
| 13 |
+
runs-on: ubuntu-latest
|
| 14 |
+
|
| 15 |
+
strategy:
|
| 16 |
+
matrix:
|
| 17 |
+
node-version: [12.x]
|
| 18 |
+
|
| 19 |
+
steps:
|
| 20 |
+
- uses: actions/checkout@v2
|
| 21 |
+
- name: Use Node.js ${{ matrix.node-version }}
|
| 22 |
+
uses: actions/setup-node@v2
|
| 23 |
+
with:
|
| 24 |
+
node-version: ${{ matrix.node-version }}
|
| 25 |
+
- run: |
|
| 26 |
+
npm i
|
| 27 |
+
npm run ci
|
.github/workflows/publish.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Publish to NPM
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
release:
|
| 6 |
+
types: [created]
|
| 7 |
+
|
| 8 |
+
jobs:
|
| 9 |
+
publish:
|
| 10 |
+
|
| 11 |
+
runs-on: ubuntu-latest
|
| 12 |
+
|
| 13 |
+
steps:
|
| 14 |
+
- name: Checkout
|
| 15 |
+
uses: actions/checkout@v2
|
| 16 |
+
- name: Setup Node
|
| 17 |
+
uses: actions/setup-node@v2
|
| 18 |
+
with:
|
| 19 |
+
node-version: '14.x'
|
| 20 |
+
registry-url: 'https://registry.npmjs.org'
|
| 21 |
+
- name: Build eruda timing
|
| 22 |
+
run: |
|
| 23 |
+
npm i
|
| 24 |
+
npm run build
|
| 25 |
+
- name: Publish package on NPM
|
| 26 |
+
run: npm publish
|
| 27 |
+
env:
|
| 28 |
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/node_modules/
|
| 2 |
+
eruda-timing.js
|
| 3 |
+
eruda-timing.js.map
|
| 4 |
+
package-lock.json
|
.prettierignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
eruda-timing.js
|
| 2 |
+
eruda-timing.min.js
|
CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## v2.0.1 (26 Nov 2022)
|
| 2 |
+
|
| 3 |
+
* fix: unable to load in eruda 2.5.0
|
| 4 |
+
|
| 5 |
+
## v2.0.0 (6 Jan 2019)
|
| 6 |
+
|
| 7 |
+
* feat: theme support
|
| 8 |
+
|
| 9 |
+
## v1.1.3 (8 Nov 2019)
|
| 10 |
+
|
| 11 |
+
* chore: update refresh icon style
|
| 12 |
+
|
| 13 |
+
## v1.1.2 (22 Aug 2018)
|
| 14 |
+
|
| 15 |
+
* Fix refresh icon missing
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The MIT License (MIT)
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2017 liriliri
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,10 +1,30 @@
|
|
| 1 |
-
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
--
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# eruda-timing
|
| 2 |
+
|
| 3 |
+
[![NPM version][npm-image]][npm-url]
|
| 4 |
+
[![Build status][ci-image]][ci-url]
|
| 5 |
+
[![License][license-image]][npm-url]
|
| 6 |
+
|
| 7 |
+
[npm-image]: https://img.shields.io/npm/v/eruda-timing.svg
|
| 8 |
+
[npm-url]: https://npmjs.org/package/eruda-timing
|
| 9 |
+
[ci-image]: https://img.shields.io/github/workflow/status/liriliri/eruda-timing/CI?style=flat-square
|
| 10 |
+
[ci-url]: https://github.com/liriliri/eruda-timing/actions/workflows/main.yml
|
| 11 |
+
[license-image]: https://img.shields.io/npm/l/eruda-timing.svg
|
| 12 |
+
|
| 13 |
+
Eruda plugin for performance and resource timing.
|
| 14 |
+
|
| 15 |
+
## Demo
|
| 16 |
+
|
| 17 |
+
Browse it on your phone:
|
| 18 |
+
[http://eruda.liriliri.io/?plugin=timing](http://eruda.liriliri.io/?plugin=timing)
|
| 19 |
+
|
| 20 |
+
## Install
|
| 21 |
+
|
| 22 |
+
```bash
|
| 23 |
+
npm install eruda-timing --save
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
```javascript
|
| 27 |
+
eruda.add(erudaTiming);
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
Make sure Eruda is loaded before this plugin, otherwise won't work.
|
index.html
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8" />
|
| 5 |
+
<meta
|
| 6 |
+
name="viewport"
|
| 7 |
+
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
|
| 8 |
+
/>
|
| 9 |
+
<title>Eruda-timing</title>
|
| 10 |
+
</head>
|
| 11 |
+
<body>
|
| 12 |
+
<script src="node_modules/eruda/eruda.js"></script>
|
| 13 |
+
<script>
|
| 14 |
+
eruda.init({ tool: ['sources'] })
|
| 15 |
+
</script>
|
| 16 |
+
<script src="assets/eruda-timing.js"></script>
|
| 17 |
+
<script>
|
| 18 |
+
eruda
|
| 19 |
+
.add(erudaTiming)
|
| 20 |
+
.show('timing')
|
| 21 |
+
.show()
|
| 22 |
+
</script>
|
| 23 |
+
</body>
|
| 24 |
+
</html>
|
package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "eruda-timing",
|
| 3 |
+
"version": "2.0.1",
|
| 4 |
+
"main": "eruda-timing.js",
|
| 5 |
+
"description": "Eruda plugin for performance and resource timing",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "webpack-dev-server --host 0.0.0.0",
|
| 8 |
+
"build": "webpack -p",
|
| 9 |
+
"format": "prettier 'src/*.js' 'src/style.scss' '*.js' 'index.html' --write",
|
| 10 |
+
"ci": "npm run lint && npm run build",
|
| 11 |
+
"lint": "eslint src/**/*.js"
|
| 12 |
+
},
|
| 13 |
+
"files": [
|
| 14 |
+
"eruda-timing*"
|
| 15 |
+
],
|
| 16 |
+
"repository": {
|
| 17 |
+
"type": "git",
|
| 18 |
+
"url": "git+https://github.com/liriliri/eruda-timing.git"
|
| 19 |
+
},
|
| 20 |
+
"keywords": [
|
| 21 |
+
"eruda",
|
| 22 |
+
"plugin",
|
| 23 |
+
"timing"
|
| 24 |
+
],
|
| 25 |
+
"author": "redhoodsu",
|
| 26 |
+
"license": "MIT",
|
| 27 |
+
"bugs": {
|
| 28 |
+
"url": "https://github.com/liriliri/eruda-timing/issues"
|
| 29 |
+
},
|
| 30 |
+
"homepage": "https://github.com/liriliri/eruda-timing#readme",
|
| 31 |
+
"devDependencies": {
|
| 32 |
+
"@babel/core": "^7.7.2",
|
| 33 |
+
"@babel/plugin-transform-runtime": "^7.6.2",
|
| 34 |
+
"@babel/preset-env": "^7.7.1",
|
| 35 |
+
"@babel/runtime": "^7.7.2",
|
| 36 |
+
"autoprefixer": "^9.7.1",
|
| 37 |
+
"babel-loader": "^8.0.6",
|
| 38 |
+
"css-loader": "^3.2.0",
|
| 39 |
+
"eruda": "^2.6.0",
|
| 40 |
+
"eslint": "^6.6.0",
|
| 41 |
+
"handlebars": "^4.5.1",
|
| 42 |
+
"handlebars-loader": "^1.7.1",
|
| 43 |
+
"licia": "^1.37.0",
|
| 44 |
+
"node-sass": "^4.13.0",
|
| 45 |
+
"postcss": "^7.0.21",
|
| 46 |
+
"postcss-class-prefix": "^0.3.0",
|
| 47 |
+
"postcss-loader": "^3.0.0",
|
| 48 |
+
"prettier": "^1.18.2",
|
| 49 |
+
"sass-loader": "^8.0.0",
|
| 50 |
+
"webpack": "^4.41.2",
|
| 51 |
+
"webpack-cli": "^3.3.10",
|
| 52 |
+
"webpack-dev-server": "^3.9.0"
|
| 53 |
+
}
|
| 54 |
+
}
|
prettier.config.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
module.exports = {
|
| 2 |
+
singleQuote: true,
|
| 3 |
+
tabWidth: 2,
|
| 4 |
+
semi: false
|
| 5 |
+
}
|
src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
module.exports = require('./timing').default
|
src/style.scss
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@mixin overflow-auto($direction: 'both') {
|
| 2 |
+
@if $direction == 'both' {
|
| 3 |
+
overflow: auto;
|
| 4 |
+
} @else {
|
| 5 |
+
overflow-#{$direction}: auto;
|
| 6 |
+
}
|
| 7 |
+
-webkit-overflow-scrolling: touch;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
$padding: 10px;
|
| 11 |
+
$font-size-s: 12px;
|
| 12 |
+
$font-size-l: 16px;
|
| 13 |
+
$font-size: 14px;
|
| 14 |
+
$anim-duration: 0.3s;
|
| 15 |
+
|
| 16 |
+
.timing {
|
| 17 |
+
@include overflow-auto(y);
|
| 18 |
+
.performance-timing {
|
| 19 |
+
padding: $padding 0;
|
| 20 |
+
.inner-wrapper {
|
| 21 |
+
background: var(--darker-background);
|
| 22 |
+
.bar {
|
| 23 |
+
@include overflow-auto(x);
|
| 24 |
+
border-bottom: 1px solid var(--border);
|
| 25 |
+
span {
|
| 26 |
+
font-size: $font-size-s;
|
| 27 |
+
white-space: nowrap;
|
| 28 |
+
padding: 5px 0;
|
| 29 |
+
background: var(--highlight);
|
| 30 |
+
display: inline-block;
|
| 31 |
+
}
|
| 32 |
+
&:last-child {
|
| 33 |
+
border-bottom: none;
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
.performance-timing-data {
|
| 39 |
+
padding-bottom: $padding;
|
| 40 |
+
text-align: center;
|
| 41 |
+
table {
|
| 42 |
+
width: 100%;
|
| 43 |
+
border-collapse: collapse;
|
| 44 |
+
text-align: left;
|
| 45 |
+
th {
|
| 46 |
+
background: var(--darker-background);
|
| 47 |
+
text-align: left;
|
| 48 |
+
font-size: $font-size;
|
| 49 |
+
}
|
| 50 |
+
td {
|
| 51 |
+
font-size: $font-size-s;
|
| 52 |
+
}
|
| 53 |
+
th,
|
| 54 |
+
td {
|
| 55 |
+
padding: 10px;
|
| 56 |
+
border: 1px solid var(--border);
|
| 57 |
+
}
|
| 58 |
+
tr:nth-child(even) {
|
| 59 |
+
background: var(--contrast);
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
.title {
|
| 64 |
+
border-top: 1px solid var(--border);
|
| 65 |
+
background: var(--darker-background);
|
| 66 |
+
padding: $padding;
|
| 67 |
+
.btn {
|
| 68 |
+
display: flex;
|
| 69 |
+
margin-left: 5px;
|
| 70 |
+
float: right;
|
| 71 |
+
width: 18px;
|
| 72 |
+
height: 18px;
|
| 73 |
+
justify-content: center;
|
| 74 |
+
align-items: center;
|
| 75 |
+
font-size: $font-size-l;
|
| 76 |
+
cursor: pointer;
|
| 77 |
+
transition: color $anim-duration;
|
| 78 |
+
&:active {
|
| 79 |
+
color: var(--select-foreground);
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
.entries {
|
| 84 |
+
border-bottom: 1px solid var(--border);
|
| 85 |
+
margin-bottom: 10px;
|
| 86 |
+
@include overflow-auto(x);
|
| 87 |
+
table {
|
| 88 |
+
min-width: 100%;
|
| 89 |
+
cursor: pointer;
|
| 90 |
+
tr:nth-child(4n-1) {
|
| 91 |
+
background: var(--contrast);
|
| 92 |
+
}
|
| 93 |
+
td.timeline {
|
| 94 |
+
padding: 0;
|
| 95 |
+
height: 4px;
|
| 96 |
+
font-size: 0;
|
| 97 |
+
span {
|
| 98 |
+
display: inline-block;
|
| 99 |
+
height: 100%;
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
td {
|
| 103 |
+
border: 1px solid var(--border);
|
| 104 |
+
padding: 10px;
|
| 105 |
+
white-space: nowrap;
|
| 106 |
+
}
|
| 107 |
+
.right {
|
| 108 |
+
text-align: right;
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
.not-supported {
|
| 113 |
+
background: var(--console-error-background);
|
| 114 |
+
border: 1px solid var(--console-error-border);
|
| 115 |
+
color: var(--console-error-foreground);
|
| 116 |
+
margin: 10px;
|
| 117 |
+
padding: $padding;
|
| 118 |
+
text-align: center;
|
| 119 |
+
}
|
| 120 |
+
}
|
src/template.hbs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{#if timing}}
|
| 2 |
+
<div class="eruda-performance-timing">
|
| 3 |
+
<div class="eruda-inner-wrapper">
|
| 4 |
+
{{#each data}}
|
| 5 |
+
<div class="eruda-bar">
|
| 6 |
+
<span style="position:relative;left:{{start}}%;width:{{len}}%">{{name}}({{duration}}ms)</span>
|
| 7 |
+
</div>
|
| 8 |
+
{{/each}}
|
| 9 |
+
</div>
|
| 10 |
+
</div>
|
| 11 |
+
|
| 12 |
+
{{#if showPerformanceDetail}}
|
| 13 |
+
<div class="eruda-performance-timing-data">
|
| 14 |
+
<table>
|
| 15 |
+
<thead>
|
| 16 |
+
<tr>
|
| 17 |
+
<th>Name</th>
|
| 18 |
+
<th>Time(ms)</th>
|
| 19 |
+
</tr>
|
| 20 |
+
</thead>
|
| 21 |
+
<tbody>
|
| 22 |
+
{{#each timing}}
|
| 23 |
+
<tr>
|
| 24 |
+
<td>{{@key}}</td>
|
| 25 |
+
<td>{{this}}</td>
|
| 26 |
+
</tr>
|
| 27 |
+
{{/each}}
|
| 28 |
+
</tbody>
|
| 29 |
+
</table>
|
| 30 |
+
</div>
|
| 31 |
+
{{/if}}
|
| 32 |
+
{{/if}}
|
| 33 |
+
|
| 34 |
+
{{#if entries}}
|
| 35 |
+
<div class="eruda-title">
|
| 36 |
+
ResourceTiming
|
| 37 |
+
<div class="eruda-btn eruda-refresh-resource-timing">
|
| 38 |
+
<span class="eruda-icon-refresh"></span>
|
| 39 |
+
</div>
|
| 40 |
+
</div>
|
| 41 |
+
<div class="eruda-entries">
|
| 42 |
+
<table>
|
| 43 |
+
<tbody>
|
| 44 |
+
{{#each entries}}
|
| 45 |
+
<tr class="eruda-entry" data-idx="{{@key}}">
|
| 46 |
+
<td>{{name}}</td>
|
| 47 |
+
<td>{{#if initiatorType}}<span>{{initiatorType}}</span>{{/if}}</td>
|
| 48 |
+
<td class="eruda-right">{{displayTime}}</td>
|
| 49 |
+
<td class="eruda-blue">{{url}}</td>
|
| 50 |
+
</tr>
|
| 51 |
+
<tr>
|
| 52 |
+
<td class="eruda-timeline" colspan="4">
|
| 53 |
+
<span style="border-left: 1px solid #707d8b; background: #707d8b; margin-left: {{timeline.left}}%; width: {{timeline.connection}}%;"></span>
|
| 54 |
+
<span style="background: #009688; width: {{timeline.ttfb}}%"></span>
|
| 55 |
+
<span style="background: #2196f3; width: {{timeline.response}}%"></span>
|
| 56 |
+
</td>
|
| 57 |
+
</tr>
|
| 58 |
+
{{/each}}
|
| 59 |
+
</tbody>
|
| 60 |
+
</table>
|
| 61 |
+
</div>
|
| 62 |
+
{{/if}}
|
| 63 |
+
|
| 64 |
+
{{#if notSupported}}
|
| 65 |
+
<div class="eruda-not-supported">
|
| 66 |
+
Not supported for this browser!
|
| 67 |
+
</div>
|
| 68 |
+
{{/if}}
|
src/timing.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ready from 'licia/ready'
|
| 2 |
+
import isFn from 'licia/isFn'
|
| 3 |
+
import $ from 'licia/$'
|
| 4 |
+
import { getFileName } from './util'
|
| 5 |
+
|
| 6 |
+
export default function(eruda) {
|
| 7 |
+
let { evalCss } = eruda.util
|
| 8 |
+
|
| 9 |
+
class Timing extends eruda.Tool {
|
| 10 |
+
constructor() {
|
| 11 |
+
super()
|
| 12 |
+
this.name = 'timing'
|
| 13 |
+
this._style = evalCss(require('./style.scss'))
|
| 14 |
+
this._performanceTimingData = []
|
| 15 |
+
this._performanceTiming = {}
|
| 16 |
+
this._showPerformanceDetail = false
|
| 17 |
+
this._resourceTimingData = []
|
| 18 |
+
this._tpl = require('./template.hbs')
|
| 19 |
+
|
| 20 |
+
let performance = (this._performance =
|
| 21 |
+
window.webkitPerformance || window.performance)
|
| 22 |
+
this._hasResourceTiming = performance && isFn(performance.getEntries)
|
| 23 |
+
}
|
| 24 |
+
init($el, container) {
|
| 25 |
+
super.init($el, container)
|
| 26 |
+
|
| 27 |
+
this._container = container
|
| 28 |
+
this._bindEvent()
|
| 29 |
+
}
|
| 30 |
+
show() {
|
| 31 |
+
super.show()
|
| 32 |
+
|
| 33 |
+
this._render()
|
| 34 |
+
}
|
| 35 |
+
hide() {
|
| 36 |
+
super.hide()
|
| 37 |
+
}
|
| 38 |
+
destroy() {
|
| 39 |
+
super.destroy()
|
| 40 |
+
evalCss.remove(this._style)
|
| 41 |
+
}
|
| 42 |
+
_bindEvent() {
|
| 43 |
+
let $el = this._$el,
|
| 44 |
+
container = this._container
|
| 45 |
+
|
| 46 |
+
let self = this
|
| 47 |
+
|
| 48 |
+
$el
|
| 49 |
+
.on('click', '.eruda-performance-timing', function() {
|
| 50 |
+
self._showPerformanceDetail = !self._showPerformanceDetail
|
| 51 |
+
self._render()
|
| 52 |
+
})
|
| 53 |
+
.on('click', '.eruda-entry', function() {
|
| 54 |
+
let idx = $(this).data('idx'),
|
| 55 |
+
data = self._resourceTimingData[Number(idx)]
|
| 56 |
+
|
| 57 |
+
if (data.initiatorType === 'img') {
|
| 58 |
+
showSources('img', data.url)
|
| 59 |
+
}
|
| 60 |
+
})
|
| 61 |
+
.on('click', '.eruda-refresh-resource-timing', () => {
|
| 62 |
+
this._render()
|
| 63 |
+
})
|
| 64 |
+
|
| 65 |
+
function showSources(type, data) {
|
| 66 |
+
let sources = container.get('sources')
|
| 67 |
+
if (!sources) return
|
| 68 |
+
|
| 69 |
+
sources.set(type, data)
|
| 70 |
+
|
| 71 |
+
container.showTool('sources')
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
+
_getPerformanceTimingData() {
|
| 75 |
+
let performance = this._performance
|
| 76 |
+
if (!performance) return
|
| 77 |
+
|
| 78 |
+
let timing = performance.timing
|
| 79 |
+
if (!timing) return
|
| 80 |
+
|
| 81 |
+
let data = []
|
| 82 |
+
|
| 83 |
+
/* eslint-disable no-unused-vars */
|
| 84 |
+
let {
|
| 85 |
+
navigationStart,
|
| 86 |
+
unloadEventStart,
|
| 87 |
+
unloadEventEnd,
|
| 88 |
+
redirectStart,
|
| 89 |
+
redirectEnd,
|
| 90 |
+
fetchStart,
|
| 91 |
+
domainLookupStart,
|
| 92 |
+
domainLookupEnd,
|
| 93 |
+
connectStart,
|
| 94 |
+
connectEnd,
|
| 95 |
+
secureConnectionStart,
|
| 96 |
+
requestStart,
|
| 97 |
+
responseStart,
|
| 98 |
+
responseEnd,
|
| 99 |
+
domLoading,
|
| 100 |
+
domInteractive,
|
| 101 |
+
domContentLoadedEventStart,
|
| 102 |
+
domContentLoadedEventEnd,
|
| 103 |
+
domComplete,
|
| 104 |
+
loadEventStart,
|
| 105 |
+
loadEventEnd
|
| 106 |
+
} = timing
|
| 107 |
+
|
| 108 |
+
let start = navigationStart,
|
| 109 |
+
end = loadEventEnd,
|
| 110 |
+
ready = true,
|
| 111 |
+
total = end - start
|
| 112 |
+
|
| 113 |
+
function getData(name, startTime, endTime) {
|
| 114 |
+
let duration = endTime - startTime
|
| 115 |
+
if (duration < 0) ready = false
|
| 116 |
+
|
| 117 |
+
return {
|
| 118 |
+
name: name,
|
| 119 |
+
start: ((startTime - start) / total) * 100,
|
| 120 |
+
duration: duration,
|
| 121 |
+
len: (duration / total) * 100
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
data.push(getData('Total', navigationStart, loadEventEnd))
|
| 126 |
+
data.push(getData('Network/Server', navigationStart, responseStart))
|
| 127 |
+
data.push(getData('App Cache', fetchStart, domainLookupStart))
|
| 128 |
+
data.push(getData('DNS', domainLookupStart, domainLookupEnd))
|
| 129 |
+
data.push(getData('TCP', connectStart, connectEnd))
|
| 130 |
+
data.push(getData('Time to First Byte', requestStart, responseStart))
|
| 131 |
+
data.push(getData('Response', responseStart, responseEnd))
|
| 132 |
+
data.push(getData('Unload', unloadEventStart, unloadEventEnd))
|
| 133 |
+
data.push(getData('DOM Processing', domLoading, domComplete))
|
| 134 |
+
data.push(getData('DOM Construction', domLoading, domInteractive))
|
| 135 |
+
|
| 136 |
+
if (!ready) return
|
| 137 |
+
|
| 138 |
+
this._performanceTimingData = data
|
| 139 |
+
|
| 140 |
+
let performanceTiming = {}
|
| 141 |
+
;[
|
| 142 |
+
'navigationStart',
|
| 143 |
+
'unloadEventStart',
|
| 144 |
+
'unloadEventEnd',
|
| 145 |
+
'redirectStart',
|
| 146 |
+
'redirectEnd',
|
| 147 |
+
'fetchStart',
|
| 148 |
+
'domainLookupStart',
|
| 149 |
+
'domainLookupEnd',
|
| 150 |
+
'connectStart',
|
| 151 |
+
'connectEnd',
|
| 152 |
+
'secureConnectionStart',
|
| 153 |
+
'requestStart',
|
| 154 |
+
'responseStart',
|
| 155 |
+
'responseEnd',
|
| 156 |
+
'domLoading',
|
| 157 |
+
'domInteractive',
|
| 158 |
+
'domContentLoadedEventStart',
|
| 159 |
+
'domContentLoadedEventEnd',
|
| 160 |
+
'domComplete',
|
| 161 |
+
'loadEventStart',
|
| 162 |
+
'loadEventEnd'
|
| 163 |
+
].forEach(val => {
|
| 164 |
+
performanceTiming[val] = timing[val] === 0 ? 0 : timing[val] - start
|
| 165 |
+
})
|
| 166 |
+
this._performanceTiming = performanceTiming
|
| 167 |
+
}
|
| 168 |
+
_getResourceTimingData() {
|
| 169 |
+
if (!this._hasResourceTiming) return
|
| 170 |
+
|
| 171 |
+
let entries = this._performance.getEntries(),
|
| 172 |
+
data = []
|
| 173 |
+
|
| 174 |
+
let totalTime = 0
|
| 175 |
+
entries.forEach(entry => {
|
| 176 |
+
if (entry.entryType !== 'resource') return
|
| 177 |
+
if (entry.responseEnd > totalTime) totalTime = entry.responseEnd
|
| 178 |
+
})
|
| 179 |
+
|
| 180 |
+
entries.forEach(entry => {
|
| 181 |
+
if (entry.entryType !== 'resource') return
|
| 182 |
+
|
| 183 |
+
let timeline = {
|
| 184 |
+
left: (entry.startTime / totalTime) * 100,
|
| 185 |
+
connection:
|
| 186 |
+
((entry.requestStart - entry.startTime) / totalTime) * 100,
|
| 187 |
+
ttfb: ((entry.responseStart - entry.requestStart) / totalTime) * 100,
|
| 188 |
+
response:
|
| 189 |
+
((entry.responseEnd - entry.responseStart) / totalTime) * 100
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
data.push({
|
| 193 |
+
name: getFileName(entry.name),
|
| 194 |
+
displayTime: Math.round(entry.duration) + 'ms',
|
| 195 |
+
url: entry.name,
|
| 196 |
+
timeline,
|
| 197 |
+
initiatorType: entry.initiatorType
|
| 198 |
+
})
|
| 199 |
+
})
|
| 200 |
+
|
| 201 |
+
this._resourceTimingData = data
|
| 202 |
+
}
|
| 203 |
+
_render() {
|
| 204 |
+
if (!this.active) return
|
| 205 |
+
|
| 206 |
+
this._getResourceTimingData()
|
| 207 |
+
|
| 208 |
+
let renderData = { entries: this._resourceTimingData }
|
| 209 |
+
|
| 210 |
+
if (this._performanceTimingData.length === 0) {
|
| 211 |
+
ready(() => {
|
| 212 |
+
this._getPerformanceTimingData()
|
| 213 |
+
this._render()
|
| 214 |
+
})
|
| 215 |
+
} else {
|
| 216 |
+
this._getPerformanceTimingData()
|
| 217 |
+
}
|
| 218 |
+
renderData.data = this._performanceTimingData
|
| 219 |
+
renderData.timing = this._performanceTiming
|
| 220 |
+
renderData.showPerformanceDetail = this._showPerformanceDetail
|
| 221 |
+
|
| 222 |
+
if (!renderData.timing && !renderData.entries) {
|
| 223 |
+
renderData.notSupported = true
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
this._renderHtml(this._tpl(renderData))
|
| 227 |
+
}
|
| 228 |
+
_renderHtml(html) {
|
| 229 |
+
if (html === this._lastHtml) return
|
| 230 |
+
this._lastHtml = html
|
| 231 |
+
this._$el.html(html)
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
return new Timing()
|
| 236 |
+
}
|
src/util.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import last from 'licia/last'
|
| 2 |
+
import trim from 'licia/trim'
|
| 3 |
+
import Url from 'licia/Url'
|
| 4 |
+
|
| 5 |
+
export function getFileName(url) {
|
| 6 |
+
let ret = last(url.split('/'))
|
| 7 |
+
|
| 8 |
+
if (ret.indexOf('?') > -1) ret = trim(ret.split('?')[0])
|
| 9 |
+
|
| 10 |
+
if (ret === '') {
|
| 11 |
+
url = new Url(url)
|
| 12 |
+
ret = url.hostname
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
return ret
|
| 16 |
+
}
|
webpack.config.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const autoprefixer = require('autoprefixer')
|
| 2 |
+
const postcss = require('postcss')
|
| 3 |
+
const webpack = require('webpack')
|
| 4 |
+
const pkg = require('./package.json')
|
| 5 |
+
const classPrefix = require('postcss-class-prefix')
|
| 6 |
+
|
| 7 |
+
const banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage
|
| 8 |
+
|
| 9 |
+
module.exports = {
|
| 10 |
+
devtool: 'source-map',
|
| 11 |
+
entry: './src/index.js',
|
| 12 |
+
devServer: {
|
| 13 |
+
contentBase: './',
|
| 14 |
+
port: 3000
|
| 15 |
+
},
|
| 16 |
+
output: {
|
| 17 |
+
path: __dirname,
|
| 18 |
+
filename: 'eruda-timing.js',
|
| 19 |
+
publicPath: '/assets/',
|
| 20 |
+
library: ['erudaTiming'],
|
| 21 |
+
libraryTarget: 'umd'
|
| 22 |
+
},
|
| 23 |
+
module: {
|
| 24 |
+
rules: [
|
| 25 |
+
{
|
| 26 |
+
test: /\.js$/,
|
| 27 |
+
exclude: /node_modules|index\.js/,
|
| 28 |
+
use: {
|
| 29 |
+
loader: 'babel-loader',
|
| 30 |
+
options: {
|
| 31 |
+
presets: ['@babel/preset-env'],
|
| 32 |
+
plugins: ['@babel/plugin-transform-runtime']
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
test: /\.scss$/,
|
| 38 |
+
loaders: [
|
| 39 |
+
'css-loader',
|
| 40 |
+
{
|
| 41 |
+
loader: 'postcss-loader',
|
| 42 |
+
options: {
|
| 43 |
+
plugins: function() {
|
| 44 |
+
return [
|
| 45 |
+
postcss.plugin('postcss-namespace', function() {
|
| 46 |
+
// Add '.dev-tools .tools ' to every selector.
|
| 47 |
+
return function(root) {
|
| 48 |
+
root.walkRules(function(rule) {
|
| 49 |
+
if (!rule.selectors) return rule
|
| 50 |
+
|
| 51 |
+
rule.selectors = rule.selectors.map(function(selector) {
|
| 52 |
+
return '.dev-tools .tools ' + selector
|
| 53 |
+
})
|
| 54 |
+
})
|
| 55 |
+
}
|
| 56 |
+
}),
|
| 57 |
+
classPrefix('eruda-'),
|
| 58 |
+
autoprefixer
|
| 59 |
+
]
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
'sass-loader'
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
test: /\.hbs$/,
|
| 68 |
+
loader: 'handlebars-loader'
|
| 69 |
+
}
|
| 70 |
+
]
|
| 71 |
+
},
|
| 72 |
+
plugins: [new webpack.BannerPlugin(banner)]
|
| 73 |
+
}
|