-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c78d6b2
Showing
11 changed files
with
9,062 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"root": true, | ||
"parserOptions": { | ||
"parser": "babel-eslint", | ||
"sourceType": "module" | ||
}, | ||
"extends": [ | ||
"@nuxtjs" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
coverage | ||
.nuxt | ||
yarn-error.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
memwatchers | ||
|
||
Copyright (C) 2019, pimlie | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Quickly watch real-time memory stats of your nuxt app | ||
[![npm](https://img.shields.io/npm/dt/nuxt-memwatch.svg?style=flat-square)](https://www.npmjs.com/package/nuxt-memwatch) | ||
[![npm (scoped with tag)](https://img.shields.io/npm/v/nuxt-memwatch/latest.svg?style=flat-square)](https://www.npmjs.com/package/nuxt-memwatch) | ||
|
||
## Why and when do you use this module | ||
|
||
Other tools may provide the same or better functionality, but this module is probably the quickest way to get more insights in the memory usage of your nuxt server. Especially when using the node-memwatch peer dependency it could help you track down memory leaks. See [node-memwatcher](https://github.com/pimlie/node-memwatcher) and [node-memwatch](https://github.com/airbnb/node-memwatch) readme's for more information | ||
|
||
<p align="center"><img src="./assets/demo.gif" alt="nuxt-memwatch demo"/></p> | ||
|
||
## Setup | ||
> :information_source: Please note you dont need to re-build your project when en-/disabling this module, you only need to restart the server | ||
##### Install | ||
``` | ||
npm install --save nuxt-memwatch | ||
// or | ||
yarn add nuxt-memwatch | ||
``` | ||
|
||
##### Install the node-memwatcher peer dependency (recommended) | ||
``` | ||
npm install --save @airbnb/node-memwatch | ||
// or | ||
yarn add @airbnb/node-memwatch | ||
``` | ||
|
||
##### Add `nuxt-memwatch` to `modules` section of `nuxt.config.js` | ||
```js | ||
modules: [ | ||
['nuxt-memwatch', { graph: false }], | ||
] | ||
``` | ||
or | ||
```js | ||
modules: [ | ||
'nuxt-memwatch' | ||
], | ||
memwatch: { | ||
graphSetup(setup) { | ||
setup.metrics.malloc = { | ||
aggregator: 'avg', | ||
color: 'cyan' | ||
} | ||
}, | ||
graphAddMetric(turtleGraph, stats) { | ||
turtleGraph.metric('my metrics', 'malloc').push(stats.malloced_memory) | ||
} | ||
} | ||
``` | ||
|
||
## Example | ||
|
||
You can run the included example by cloning this repo, run `yarn install && yarn build` and finally `yarn start`. Then generate some requests by running `ab -c100 -n100000 http://127.0.0.1:3000/`, this example uses max ~1.3GB of memory which is fine-tuned for node's default heap size limit of 1.5GB | ||
|
||
## Module Options | ||
|
||
Besides the default [node-memwatcher options](https://github.com/pimlie/node-memwatcher#options), this module provides some extra options | ||
|
||
#### `gcAfterEvery` _number_ (0) | ||
|
||
If set to a number larger then 0, we will force the gc to run after this number of requests. E.g. when set to 1 the gc runs after every request | ||
|
||
> :fire: This only works when you have either installed the peerDependency or are running node with `--expose_gc` | ||
#### `nuxtHook` _string_ (listen) | ||
|
||
Normally we are interested in memory usage when nuxt is serving requests, so we start listening for stats events on the listen hook. If you are running this module in development mode, we listen for `build:done` instead if you dont change this value. You can probably leave this to the default, but if you want to debug the nuxt generate command you could do: | ||
|
||
```js | ||
// nuxt.config.js | ||
|
||
import { getMemwatch } from 'node-memwatcher' | ||
let memwatch | ||
|
||
export default { | ||
... | ||
memwatch: { | ||
graph: false, | ||
nuxtHook: 'generate:before' | ||
}, | ||
hooks: { | ||
generate: { | ||
async before() { | ||
memwatch = await getMemwatch() | ||
}, | ||
page() { | ||
// this probably wont work as you expect | ||
// as node will probably be too busy generating pages | ||
// and the gc will only run after | ||
// generate.concurrency routes have finished | ||
memwatch.gc() | ||
} | ||
} | ||
} | ||
... | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
let log = [] | ||
let dev | ||
|
||
export default { | ||
modules: [ | ||
'@/../lib/module' | ||
], | ||
hooks: { | ||
listen(server, listener) { | ||
dev = listener.dev | ||
}, | ||
render: { | ||
routeDone(url, res, context) { | ||
log.push(res) | ||
|
||
// development mode significantly increases used memory already | ||
// and it crashes around ~3k requests anyway | ||
if (log.length > (dev ? 100 : 18000)) { | ||
log = [] | ||
} | ||
} | ||
} | ||
}, | ||
memwatch: { | ||
graph: true, | ||
gcMetrics: false, | ||
gcAfterEvery: 0, | ||
autoHeapDiff: true, | ||
useMovingAverage: 5, | ||
graphSetup(graphSetup) { | ||
graphSetup.metrics.malloc = { | ||
aggregator: 'avg', | ||
color: 'cyan' | ||
} | ||
}, | ||
graphAddMetric(graph, stats) { | ||
graph.metric('my metrics', 'malloc').push(stats.malloced_memory) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<template> | ||
<h1>Page</h1> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import env from 'std-env' | ||
import consola from 'consola' | ||
import { start, setOptions, getMemwatch } from 'node-memwatcher' | ||
|
||
export default function nuxtMemwatch(options = {}) { | ||
let nuxtHook = 'listen' | ||
if (options.nuxtHook) { | ||
nuxtHook = options.nuxtHook | ||
} | ||
|
||
if (this.options.memwatch && this.options.memwatch.nuxtHook) { | ||
nuxtHook = this.options.memwatch.nuxtHook | ||
} | ||
|
||
// listen for build:done in dev mode because the server | ||
// already listens before building is finished | ||
if (this.options.dev && nuxtHook === 'listen') { | ||
nuxtHook = 'build:done' | ||
} | ||
|
||
this.nuxt.hook(nuxtHook, async () => { | ||
const logger = consola.withScope('memwatch') | ||
|
||
if (!env.tty) { | ||
logger.info('No tty found, nuxt-memwatch will not run') | ||
return | ||
} | ||
|
||
let requestCounter = 0 | ||
let gcRequestCounter = 0 | ||
|
||
options = setOptions(this.options.memwatch || options) | ||
|
||
if (options.autoHeapDiff && !this.options.dev) { | ||
logger.warn(`Creating heapDiffs is very expensive, only enable this in production if you really have to`) | ||
} | ||
|
||
options.appName = 'nuxt-memwatch' | ||
options.groupName = 'nuxt-memwatch' | ||
options.gcAfterEvery = options.gcAfterEvery || 0 | ||
|
||
options.graphSetup.push((graphSetup) => { | ||
graphSetup.metrics.requests = { | ||
min: 0, | ||
aggregator: 'avg', | ||
color: 'magenta,bold' | ||
} | ||
}) | ||
|
||
options.graphAddMetric.push((turtle, stats) => { | ||
turtle.metric(options.groupName, 'requests').push(requestCounter) | ||
requestCounter = 0 | ||
}) | ||
|
||
if (options.gcAfterEvery) { | ||
const memwatch = await getMemwatch() | ||
|
||
this.nuxt.hook('render:routeDone', () => { | ||
gcRequestCounter++ | ||
|
||
if (gcRequestCounter >= options.gcAfterEvery) { | ||
memwatch.gc() | ||
gcRequestCounter = 0 | ||
} | ||
}) | ||
} | ||
|
||
if (options.graph) { | ||
this.nuxt.hook('render:routeDone', () => (requestCounter++)) | ||
} | ||
|
||
start(options) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
{ | ||
"name": "nuxt-memwatch", | ||
"version": "0.1.0", | ||
"description": "Quickly watch real-time memory stats of your nuxt app", | ||
"main": "lib/module.js", | ||
"files": [ | ||
"lib" | ||
], | ||
"scripts": { | ||
"dev": "nuxt dev example", | ||
"build": "nuxt build example", | ||
"start": "nuxt start example", | ||
"lint": "eslint lib", | ||
"release": "yarn lint && standard-version" | ||
}, | ||
"keywords": [ | ||
"memwatch", | ||
"memory", | ||
"leak", | ||
"statistics", | ||
"heap", | ||
"dump", | ||
"nuxt", | ||
"module", | ||
"nuxt-module" | ||
], | ||
"author": "pimlie <pimlie@hotmail.com>", | ||
"license": "MIT", | ||
"dependencies": { | ||
"node-memwatcher": "^0.1.1", | ||
"std-env": "^2.2.1" | ||
}, | ||
"devDependencies": { | ||
"@airbnb/node-memwatch": "^1.0.2", | ||
"@babel/core": "^7.3.4", | ||
"@babel/plugin-syntax-dynamic-import": "^7.2.0", | ||
"@babel/preset-env": "^7.3.4", | ||
"@nuxtjs/eslint-config": "^0.0.1", | ||
"babel-eslint": "^10.0.1", | ||
"babel-jest": "^24.1.0", | ||
"babel-plugin-dynamic-import-node": "^2.2.0", | ||
"eslint": "^5.14.1", | ||
"eslint-config-standard": "^12.0.0", | ||
"eslint-plugin-import": "^2.16.0", | ||
"eslint-plugin-jest": "^22.3.0", | ||
"eslint-plugin-node": "^8.0.1", | ||
"eslint-plugin-promise": "^4.0.1", | ||
"eslint-plugin-standard": "^4.0.0", | ||
"eslint-plugin-vue": "^5.2.2", | ||
"jest": "^24.1.0", | ||
"nuxt": "^2.4.5" | ||
} | ||
} |
Oops, something went wrong.