Next.js: Dependencies specified in _app are duplicated in other pages.

Created on 19 Dec 2018  路  11Comments  路  Source: vercel/next.js

Bug report

Describe the bug

Dependencies not properly shared across pages and _app.js

To Reproduce

Create a number of pages. Add a module to _app.js.
Increase the number of times a module is included from once to N times, track progress

Takes at least 2 pages for a dep included in _app.js to be factored out.

Expected behavior

Once a module has been included in _app, it should never be packed again.

Screenshots

In a 4 page + _app + _document app

// _app only (_app.js includes Auth)
screen shot 2018-12-19 at 1 29 25 pm

// 1 page (_app.js + submit.js include Auth)
screen shot 2018-12-19 at 1 30 22 pm

// 2 pages (_app.js + submit.js + scorecard.js include Auth)
screen shot 2018-12-19 at 1 31 00 pm

System information

  • OS: Mac OS X
  • Version of Next.js: canary, 7.0.2

Additional context

Related to: #3818 (though in this case import isn't being exported as in HOC)
Related to: #118 and #253

Potential solutions: expose or document modifying the threshold for placing a dependency in the common bundle.

However, it seems there should be a more intelligent procedure, in which unnecessary data is not bundled for any descendants of _app.js.

bug p1

Most helpful comment

@dav-is is working on fixing this.

All 11 comments

Fixed by

if (!options.isServer) {
  config.optimization.splitChunks.cacheGroups.commons.minChunks = 2;
}

This is a simple fix, effectively just needs documentation of default of 3. This may be somewhat confusing, as Webpack's default is 1, and "shared" implies 2.

@akotlar that snippet seems out of date when investigating the cacheGroups object returned by the most recent version of webpack bundled with Next:

After console.logging(config.optimizations.splitChunks.cacheGroups) on startup (with zeit/next-css generating the "styles" prop):

{ cacheGroups:
   { default: false,
     vendors: false,
     styles:
      { name: 'styles',
        test: /\.+(css)$/,
        chunks: 'all',
        enforce: true }
 } 
}

Looking at the documentation for the SplitChunksPlugin it seems you can set up the commons object as you are suggesting; I am wondering if that or either of these lines would do the trick on newer versions:

if (!isServer) {  
    const chunkingDefaults = { minChunks: 2, reuseExistingChunk: true };
    config.optimization.splitChunks.cacheGroups.default = chunkingDefaults;
    config.optimization.splitChunks.minChunks = 2;  
}

I can confirm this is happening with our app bundles too.

@dav-is is working on fixing this.

Cheering for fixing this as well.. Our app is 2x more heavy than necessary because of this bug

Currently I have best results when using following:

    if (!isServer) {
      const cacheGroups = config.optimization.splitChunks.cacheGroups

      delete cacheGroups.react

      cacheGroups.default = false

      cacheGroups.vendors = {
        name: 'vendors',
        test: /[\\/](node_modules|packages)[\\/]/,
        enforce: true,
        priority: 20
      }

      cacheGroups.commons = {
        name: 'commons',
        minChunks: 2,
        priority: 10
      }
    }

This forces all dependencies from node_modules to vendor chunk (nice, because yarn.lock ensures this chunk won't change very often), then it forces all common non-vendor application code to commons chunk (nice because pages are loading faster when browsing on client side).

The only issue I have currently is that _app.js is separate page while I'd like it to be a part of commons chunk... Also runtime chunk that I'd like also to be a part of commons chunk. Any help appreciated..

Any updates regarding this issue?

This should be fixed in https://github.com/zeit/next.js/pull/7696

module.exports = {
  experimental: {
    granularChunks: true
  }
}

Closing this as it should be solved by #7696

I'm still seeing an overlapping @apollo/client in _app.js, even with granularChunks enabled:

double apollo

And if I manually split the chunks, it still overlaps a decent amount of code (should be ~30kb gzipped total, but is more like 50kb gzipped combined):

        const regexWithApollo = /(?<!node_modules.*)[\\/]node_modules[\\/](react|react-dom|scheduler|prop-types|use-subscription|@apollo\/client)[\\/]/;

        config.optimization.splitChunks.cacheGroups.framework.test = regexWithApollo;

image

Any ideas?

@switz it might not be what is causing your specific issue, but note that @apollo/client publishes code duplicated in separate ESM (faux ESM, not Node.js compatible) and CJS files:

https://unpkg.com/browse/@apollo/client@3.1.4/

Depending how multiple modules require or import from the various files, you could end up encountering the dual package hazard.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jesselee34 picture jesselee34  路  3Comments

knipferrc picture knipferrc  路  3Comments

YarivGilad picture YarivGilad  路  3Comments

swrdfish picture swrdfish  路  3Comments

rauchg picture rauchg  路  3Comments