Skip to content

A minimal reproduction of TDZ errors encountered using @observablehq/plot with webpack.

Notifications You must be signed in to change notification settings

parkerziegler/plot-cycle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This repo is a minimal reproduction of a Temporal Dead Zone (TDZ) error encountered when using multiple APIs from @observablehq/plot in a production Webpack build.

Seeing the Error

To encounter the TDZ error, take the following steps:

  1. Run the Next.js production build:
yarn build
  1. Serve the production build locally:
yarn start

This will start a local development server at http://localhost:3000.

  1. Navigate to either http:localhost:3000/histogram or http:localhost:3000/strip-plot. You should see a white screen with an bit of black text reading "Application error: a client-side exception has occurred (see the browser console for more information).".

  2. Open the browser console. You should see an error saying:

ReferenceError: can't access lexical declaration 'd' before initialization (Firefox) ReferenceError: Cannot access 'd' before initialization (Chrome)

Removing the Error

To get rid of the error, delete either pages/histogram.js or pages/strip-plot.js. Follow the steps above to re-run and serve the production build. If you visit the page you DID NOT delete, you should be able to see the histogram or strip plot generated by Plot.

Discussion

In what environments does the error occur?

The error is only visible in production builds (e.g. those run with NODE_ENV=production). This is part of what makes it difficult to trace!

What is the specific error reported?

The stack trace of the reported error is as follows:

ReferenceError: Cannot access 'd' before initialization
    at Object.vc (497-35515fda497bb06a.js:1:665)
    at Object.27 (facet.js:13:21)
    at r (bootstrap:21:23)
    at Object.2186 (497-35515fda497bb06a.js:1:1422)
    at r (bootstrap:21:23)
    at Object.3962 (histogram-6827f696cfad69e9.js:1:297)
    at r (bootstrap:21:23)
    at (index):5:16
    at route-loader.js:236:51

Following the stack trace is a bit difficult since the production build is minified. However, we did turn on source maps using productionBrowserSourceMaps: true in next.config.js. This is what allows us to trace that the error arose from L13 in facet.js from @observablehq/plot.

What does the stack trace suggest?

L13, C21 of facet.js pertains to the Mark class imported from mark.js. The issue is that, at the time class Facet is being initialized to extend Mark, Mark itself has not yet been declared. This is what leads to the TDZ ReferenceError. d in the minified build pertains to class Mark.

These types of TDZ ReferenceErrors in production Webpack builds tend, based on this comment from Webpack's core author Tobias Koppers, to be caused by cyclic dependencies.

Does @observablehq/plot have cyclic dependencies?

Yes. Adding the no-cycle rule from @eslint-plugin-import to @observablehq/plot resulted in 52 detected cycles. To be clear, cyclic dependencies are allowed by the ESM spec; they can just lead to these kinds of TDZ errors in Webpack. In addition, tree shaking in Webpack makes this even more tricky to track down, because, depending on which parts of the Plot API you use, the chunk Webpack generates for @observablehq/plot will resolve these cycles in different orders. This means you may use a set of APIs that result in a perfectly fine production build with no runtime errors.

What could be done to alleviate this error?

The solution with the highest probability of success would be to eliminate all cycles from the source. However, this is likely prohibitively expensive due to how many cycles currently exist and the challenges associated with such large-scale refactoring.

The specific error here appears to be the result of the following cycle:

  • facet.js imports Mark from mark.js
  • mark.js imports plot from plot.js
  • plot.js imports facets from facets.js

Resolving this cycle could help to alleviate this problem, but I'm not fully certain. It appears to be the most likely candidate based on the stack trace, but I have noticed that this error appears to be mark type dependent. For example, in another project where I use the barY and dot marks APIs in the same project, I don't encounter this error. This suggests that the troublesome cycle may be related to some of the transforms APIs (e.g. binX, normalizeX) that the histogram and strip plots use.

About

A minimal reproduction of TDZ errors encountered using @observablehq/plot with webpack.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published