microsoft / ApplicationInsights-JS

Microsoft Application Insights SDK for JavaScript
MIT License
650 stars 240 forks source link

[BUG] Server Side Rendering fails when using Gatsby #1094

Open aaronpowell opened 5 years ago

aaronpowell commented 5 years ago

Description/Screenshot

I'm using Gatsby to create a static website but when I attempted to generate the static HTML files from the React components the Server Side Rendering (SSR) fails in AppInsights:

"window" is not available during server side rendering.
[14/1691]
See our docs page for more info on this error: https://gatsby.dev/debug-html

   ReferenceError: window is not defined

   - render-page.js:8451 new AjaxMonitor
 /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:8451:34

- render-page.js:10514 new Initialization
 /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:10514:29

   - render-page.js:50798 Module../src/AppInsights.js
/home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:50798:306

  - render-page.js:30 __webpack_require__
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:30:30

  - render-page.js:51172 Module../src/components/ProductSummary/index.js
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:51172:70

   - render-page.js:30 __webpack_require__
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:30:30

  - render-page.js:51433 Module../src/templates/ProductPage.js
  /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:51433:84

   - render-page.js:30 __webpack_require__
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:30:30

  - render-page.js:667 Object../.cache/sync-requires.js
 /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:667:364

- render-page.js:30 __webpack_require__
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:30:30

  - render-page.js:617 Module../.cache/static-entry.js
  /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:617:1526

   - render-page.js:30 __webpack_require__
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:30:30

  - render-page.js:94
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:94:18

  - render-page.js:97
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:97:10

  - render-page.js:3 webpackUniversalModuleDefinition
   /home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:3:20

   - render-page.js:10 Object.<anonymous>
/home/aaron/code/github/react-app-insights/AppInsights-Part2/public/render-page.js:10:3 

Steps to Reproduce

  1. Create a new Gatsby website (using the default starter kit, or any others)
  2. Add AppInsights from npm + the React extension
  3. Run npm run build to generate the static output

    • OS/Browser: WSL2 (but confirmed failing on Windows)
    • SDK Version [e.g. 22]:
      "@microsoft/applicationinsights-react-js": "^2.3.0",
      "@microsoft/applicationinsights-web": "^2.3.0",
    • How you initialized the SDK: Following Basic Usage from the sample README.

Expected behavior

Gatsby is able to generate a set of static files.

Additional context

You'll find a demo that the errors can be repo'ed in on my GitHub. Gatsby works fine when run using the development webserver.

aaronpowell commented 5 years ago

Doing my own digging into the problem, the issue is with the way the AjaxMonitor dependency works, specifically the following lines:

Line 98 which fails because the line does a test of window && ..., which will fail during SSR since window isn't defined

Line 325 which fails because it expects XMLHttpRequest to be globally defined, but isn't during SSR.

Line 584 which fails because it expects window to be a global.

aaronpowell commented 5 years ago

Workaround

The workaround for this would be to use the DefinePlugin plugin for webpack. This is doable with Gastby, by updating the gastby-node.js file like so:

exports.onCreateWebpackConfig = ({stage, plugins, actions}) => {
  if (stage === 'build-html') {
    actions.setWebpackConfig({
      plugins: [
        plugins.define({
          window: undefined,
          XMLHttpRequest: undefined
        }),
      ],
    })
  }
}

This will define window and XMLHttpRequest but define them as undefined so that the tests will pass and anywhere that's doing a typeof window === 'object' test will still fail since typeof undefined === 'undefined'.

MSNev commented 4 years ago

@aaronpowell Hi Aaron, is this issue still relevant based on the changes introduced in #1167 to support a generic getGlobal() lookup method?

aaronpowell commented 4 years ago

@MSNev I'll have to have a test and see if I can still repo (assuming that #1167 is in a released npm package).

MSNev commented 4 years ago

It's been included since v2.4.1

jasonnutter commented 4 years ago

This appears to still be an issue in 2.5.5. I believe this is because the library is using a helper function to check whether or not something is undefined, instead of checking typeof at the call sites (example). This results in the code throwing an exception (due to referencing an undefined value) before the helper code can run.

@MSNev I have put together a sample Gatsby app demonstrating these errors: https://github.com/jasonnutter/appinsights-gatsby

For other Gatsby users encountering this bug, I was able to workaround this by using the workaround from @aaronpowell above along with putting the invocation of loadAppInsights() in my app behind a typeof window !== "undefined" check.

MSNev commented 4 years ago

It should indeed be using typeof to avoid the JS strict mode checking, just as is done in the dependencies @ https://github.com/microsoft/ApplicationInsights-JS/blob/master/extensions/applicationinsights-dependencies-js/src/ajax.ts#L54

t0ff3r commented 3 years ago

@jasonnutter came across this issue. If you loadAppInsights() in gatsby-browser.js you avoid that window-problem aswell 😄