Skip to content

Commit

Permalink
feat: split into nuxt module
Browse files Browse the repository at this point in the history
  • Loading branch information
pimlie committed Feb 28, 2019
0 parents commit c78d6b2
Show file tree
Hide file tree
Showing 11 changed files with 9,062 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .eslintrc
@@ -0,0 +1,10 @@
{
"root": true,
"parserOptions": {
"parser": "babel-eslint",
"sourceType": "module"
},
"extends": [
"@nuxtjs"
]
}
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
node_modules
coverage
.nuxt
yarn-error.log
21 changes: 21 additions & 0 deletions LICENSE
@@ -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.
97 changes: 97 additions & 0 deletions README.md
@@ -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()
}
}
}
...
```
Binary file added assets/demo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/demo.mp4
Binary file not shown.
40 changes: 40 additions & 0 deletions example/nuxt.config.js
@@ -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)
}
}
}
3 changes: 3 additions & 0 deletions example/pages/index.vue
@@ -0,0 +1,3 @@
<template>
<h1>Page</h1>
</template>
74 changes: 74 additions & 0 deletions lib/module.js
@@ -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)
})
}
53 changes: 53 additions & 0 deletions package.json
@@ -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"
}
}

0 comments on commit c78d6b2

Please sign in to comment.