Can I get the dependency tree before webpack starts to build?

Viewed 4376

Does webpack expose the dependency tree before the build is sealed? I have searched all through the compiler instance, but have found nothing about a dependency tree. It seems that there should be one hidden in that object somewhere, because webpack has to know what this tree is in order to later output the stats.json.

I've tried using the dependency-tree npm package, but it doesn't support some things I have in my webpack config, so the tree is incomplete.

2 Answers

TL;DR: Yes, you can access the dependency tree just before it's being sealed.

To do this, add the following code to your webpack.config.js:

class AccessDependenciesPlugin {
  apply (compiler) {
    compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
      compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
        /*
        |---------------------------------------------------
        | Here we go, `modules` is what we're looking for!
        |---------------------------------------------------
        */
      })
    })
  }
}


module.exports = {
  // ...
  plugins: [
    new AccessDependenciesPlugin()
  ]
}

For more details, see the explanation below.


The hook we're looking for

We can access the pre-sealed dependency tree with the finishModules compilation hook.


How do we know?

Since the webpack hook docs are very minimal (to say the least), we had to read webpack source code to be sure it's what we're looking for:

The last thing the compiler does before sealing the dependency tree is "finishing" it.

Finishing the dependency tree offers a hook on the compilation.


Code example

We create a plugin called AccessDependenciesPlugin:

// Basic webpack plugin structure
class AccessDependenciesPlugin {
  apply (compiler) {

  }
}

To use a compilation hook, we need to get access to the compilation object first. We do that with the compilation hook:

class AccessDependenciesPlugin {
  apply (compiler) {
    compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
      // We have access to the compilation now!
    })
  }
}

Now we tap the finishModules hook of the compilation:

class AccessDependenciesPlugin {
  apply (compiler) {
    compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
      compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
        // Here we go, `modules` is what we're looking for!
      })
    })
  }
}

The modules parameter of that hook is an array of webpack modules with their dependencies and basically all other data available about them.

Last but not least, we need to add the plugin to our webpack configuration:

module.exports = {
  plugins: [
    new AccessDependenciesPlugin()
  ]
}

And we're done.


Hope this helps.


Bonus Content: webpack 3

Per request in the comments: Here's the version of the AccessDependenciesPlugin for the legacy plugin system of webpack 3.

class AccessDependenciesPlugin {
  apply (compiler) {
    compiler.plugin('compilation', compilation => {
      compilation.plugin('finish-modules', modules => {
        /*
        |---------------------------------------------------
        | Here we go, `modules` is what we're looking for!
        |---------------------------------------------------
        */
      })
    })
  }
}

Perhaps the line of code from this GitHub thread will help you out:

"Compile with webpack --profile --json > stats.json

(node.js API: { profile: true } and stats.toJson())

Go to http://webpack.github.io/analyse/#modules

Load your stats file (It's not uploaded, the analyse tools is a client only tool).

Wait a bit until the graph has been stabilized."

If that's not what you need, then I'd look into @Loilo 's answer - more complicated, but probably more what you need too.

Related