welldone-software / why-did-you-render

why-did-you-render by Welldone Software monkey patches React to notify you about potentially avoidable re-renders. (Works with React Native as well.)
https://www.npmjs.com/package/@welldone-software/why-did-you-render
MIT License
11.11k stars 196 forks source link

Integration with Next.js 13 app folder? #266

Open hems opened 1 year ago

hems commented 1 year ago

According to this comment the community still don't have a working example of how to integrate with Next.js 13.

I can see the official repository from vercel has an example using the pages folder but still no example with the app folder?

Perhaps the Next.js 13 example would be based off the beta documentation example for client side providers: Rendering third-party context providers in Server Components ?

jens-duttke commented 1 year ago

This works for me:

  1. Create a file scripts/why-did-you-render/index.js:
const path = require('path');

/** @typedef {Parameters<import('next').NextConfig['webpack']>[1]} WebpackConfigContext */

const injectionSource = path.join(__dirname, 'injection.ts');

/**
 * @param {import('webpack').Configuration} config
 * @param {WebpackConfigContext} context
 */
module.exports = (config, context) => {
    if (context.dev && !context.isServer) {
        const originalEntry = config.entry;

        config.entry = async () => {
            const entries = await originalEntry();

            if (entries['main-app'] && !entries['main-app'].includes(injectionSource)) {
                entries['main-app'].unshift(injectionSource);
            }

            return entries;
        };
    }
};

Here, instead of entries['main.js'] (which is used for the pages folder), entries['main-app'] is used (which is required for the app folder).

  1. Create a file scripts/why-did-you-render/injection.ts (you could also call it injection.js if you don't use TypeScript, and change it in the code above).
import React from 'react';

import whyDidYouRender from '@welldone-software/why-did-you-render';

// eslint-disable-next-line no-console -- Show information that `whyDidYouRender` has been applied to the website.
console.debug('Applying whyDidYouRender, to help you locate unnecessary re-renders during development. See https://github.com/welldone-software/why-did-you-render');

// See https://github.com/welldone-software/why-did-you-render#options
whyDidYouRender(React, {
    trackAllPureComponents: true,
    trackHooks: true,
    logOwnerReasons: true,
    collapseGroups: true,
    include: [/./],

    // This is for testing, remove it, if you don't want to log on different values
    logOnDifferentValues: true
});

In your next.config.js add:

const injectWhyDidYouRender = require('./scripts/why-did-you-render');

/** @type {import('next').NextConfig} */
module.exports = {
    ...
    webpack: (config, context) => {
        injectWhyDidYouRender(config, context)

        return config;
    }
};

The include: [/./] in the whyDidYouRender options is a workaround for a bug, which seems to be in https://github.com/welldone-software/why-did-you-render/blob/0f364e8451f5283e4d59054c96a9e2788f497045/src/shouldTrack.js#L39-L47