Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrating newrelic on angular universal application (nodejs)

I'm integrating newrelic on nodejs app, made with angular universal. I am using webpack for bundling

first line in main.server.aot.ts

const newrelic = require('newrelic');

and have added newrelic.js in root directory as well.

running build ejects following error :-

ERROR in ./node_modules/@newrelic/native-metrics/lib/pre-build.js
Module not found: Error: Can't resolve '../package' in 'D:\repos\ib-mobile\node_modules\@newrelic\native-metrics\lib'
 @ ./node_modules/@newrelic/native-metrics/lib/pre-build.js 40:12-33
 @ ./node_modules/@newrelic/native-metrics/index.js
 @ ./node_modules/newrelic/lib/sampler.js
 @ ./node_modules/newrelic/lib/agent.js
 @ ./node_modules/newrelic/index.js
 @ ./src/main.server.aot.ts

ERROR in ./node_modules/node-gyp/lib/node-gyp.js
Module not found: Error: Can't resolve '../package' in 'D:\repos\ib-mobile\node_modules\node-gyp\lib'
 @ ./node_modules/node-gyp/lib/node-gyp.js 67:16-37
 @ ./node_modules/@newrelic/native-metrics/lib/pre-build.js
 @ ./node_modules/@newrelic/native-metrics/index.js
 @ ./node_modules/newrelic/lib/sampler.js
 @ ./node_modules/newrelic/lib/agent.js
 @ ./node_modules/newrelic/index.js
 @ ./src/main.server.aot.ts

ERROR in ./node_modules/newrelic/index.js
Module not found: Error: Can't resolve './package' in 'D:\repos\ib-mobile\node_modules\newrelic'
 @ ./node_modules/newrelic/index.js 13:19-39
 @ ./src/main.server.aot.ts

and if I add newrelic as externals in webpack config

module.exports = {
  entry: root('./src/main.server.aot.ts'),
  output: {
    path: root('dist_server'),
    filename: 'server.js'
  },
  target: 'node',
  externals: {
    newrelic: true
  }
};

then I get another error as

/home/ubuntu/ib-mobile/dist_server/server.js:79752

module.exports = newrelic;
                 ^

ReferenceError: newrelic is not defined
    at Object.<anonymous> (/home/ubuntu/ib-mobile/dist_server/server.js:79752:18)
    at __webpack_require__ (/home/ubuntu/ib-mobile/dist_server/server.js:26:30)
    at Object.module.exports (/home/ubuntu/ib-mobile/dist_server/server.js:79667:16)
    at __webpack_require__ (/home/ubuntu/ib-mobile/dist_server/server.js:26:30)
    at /home/ubuntu/ib-mobile/dist_server/server.js:91:18
    at Object.<anonymous> (/home/ubuntu/ib-mobile/dist_server/server.js:94:10)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)

Angular Version (ng -v)

Angular CLI: 1.6.3
Node: 6.11.0
OS: win32 x64
Angular: 4.4.6
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router
... tsc-wrapped

@angular/cli: 1.6.3
@angular-devkit/build-optimizer: 0.0.36
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.42
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.3
@schematics/angular: 0.1.11
@schematics/schematics: 0.0.11
typescript: 2.3.4
webpack: 3.10.0
like image 529
Ubaid Azad Avatar asked Dec 28 '17 08:12

Ubaid Azad


People also ask

Is it possible to integrate newrelic on NodeJS app?

I'm integrating newrelic on nodejs app, made with angular universal. I am using webpack for bundling and have added newrelic.js in root directory as well.

How to install angular on a server or node application?

Furthermore, since Angular is a front end framework, installing it requires the inclusion of JavaScript files in server or node application. This can be done in various ways and the easiest one, run ng build and copy the code of dist folder of angular and store them in the public folder. First, install all the dependency.

How do I install the New Relic Node JS agent?

Our Node.js agent is publicly available on the Node Package Manager (npm) repositoryas well as on GitHub. Install the Node.js agent Important If you're using the agent in a Docker container, install the agent in each container. To install the Node.js agent: Create a New Relic account. Don't have one? Sign up for free! No credit card required.

What is New Relic node pinpoint?

Introduction to New Relic for Node.js Pinpoint and solve issues down to the line of code with Node.js monitoring from New Relic. With features like service maps, errors inbox, logs in context, and more, our Node.js agent helps you get the full picture of your app environment. Why it matters Many Node application requests are based on raw URLs.


2 Answers

There is more elegant solution to described problem. You can set webpack externals field like function:

(context, request, callback) => {
    var regex = new RegExp(`^newrelic$`);

    if (regex.test(request)) {
        return callback(null, `commonjs ${request}`);
    }
    callback();
 }

This will tell webpack to leave const newrelic = require('newrelic'); as is in bundled file. All you need is to place node_modules with newrelic near your running server. The second solution is to set libraryType property of outputto commonjs then the following externals syntax will work:

externals : {
    newrelic : {
        commonjs: 'newrelic'
    }
}
like image 128
Timon Thelure Avatar answered Sep 20 '22 14:09

Timon Thelure


Found a hacky way to get around this issuse!

TLDR

Essentially all this does is configure webpack to add the import at the top of the server.js file, and BAM it works.

Problem

So everything that you have done is correct, however by telling webpack that you want newrelic module to be external, you are telling it that the newrelic instance will be available in memory when running the application. We obviously have not done this and that is why we are getting the error you mentioned above. I think the use case for this functionality is for the browser, where you are including scripts with the <script src="{http://example.com/script.js}" /> and so you dont want webpack to concern itself with trying to resolve the dependency from node_modules.

Solution

Instead of using the "externals" property, we are going to simply add our standard nodejs import var newrelic = require('newrelic'); into the file that runs the expressjs node application (exactly like the new relic people are expecting).

In order to do this, we need the following:

  • BannerWebpackPlugin
  • Knowledge of which output chunk/file our nodejs express application is running.

In order to install BannerWebpackPlugin simply do the following: npm install --save-dev banner-webpack-plugin

As for the chunk/file you can either have a look at the error log (you can see from this error snippet that its the server.js chunk/file):

ReferenceError: newrelic is not defined at Object.<anonymous> (/home/ubuntu/ib-mobile/dist_server/server.js:79752:18)

Or you could look the webpack files "entry" property and find the chunk that is being generated by webpack (In my case this is also a "sever" which outputs to server.js.)

Now that we have this information we simply need to add a banner configuration to our chunk through the webpack config plugins section.

This is what my one looked like:

plugins: [
...,
    new BannerPlugin({
        chunks: {
            server:{
                beforeContent: 'var newrelic = require("newrelic");'
            }
       }
    }),
...]

At this point you should be able to run your webpack build and have your new relic stuff working!

If you had previously been including a require in your application code you can now remove it and the webpack import should be enough to get the newrelic agent running.

like image 21
sansomguy Avatar answered Sep 16 '22 14:09

sansomguy