Skip to content

Application with multiple iframes performances problems on hot reload #2969

Open

Description

@paztis
  • Operating System: MacOS BigSur
  • Node Version: 14.15
  • NPM Version: 6.14.8
  • webpack Version: 4.44.2
  • webpack-dev-server Version: 3.11.1
  • Browser: chrome 88.0.4324.87
  • This is a bug
  • This is a modification request

Code

// webpack.config.js
{
    output: {
        library: 'viewDesignerApp',
        path: 'dist',
        publicPath: '/my-app/',
        libraryTarget: 'umd'
    },
    entry: {
        'index': 'src/index',
        'index-frame1': 'src/index-frame1',
        'index-frame2': 'src/index-frame2'
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            chunks: ['index']
        }),
        new HtmlWebpackPlugin({
            filename: 'index-frame1.html',
            chunks: ['index-frame1']
        }),
        new HtmlWebpackPlugin({
            filename: 'index-frame2.html',
            chunks: ['index-frame2']
        }),
    ],
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    },
    devServer: {
        contentBase: ['dist'],
        contentBasePublicPath: '/my-app/',
        compress: true,
        publicPath: '/my-app/',
        port: 3001
    }
}

src/index.js

import {render} from 'react-dom';

const rootNode = document.getElementById('root');
render(
    <div>
        <iframe src="./index-frame1.html" />
        <iframe src="./index-frame2.html" />
    </div>,
    rootNode
);

src/index-frame1.js

import {render} from 'react-dom';

const rootNode = document.getElementById('root');
render(
    <div>SUB FRAME 1</div>,
    rootNode
);

src/index-frame2.js

import {render} from 'react-dom';

const rootNode = document.getElementById('root');
render(
    <div>SUB FRAME 2</div>,
    rootNode
);

Expected Behavior

I've an application that contains 2 sub iframes
Webpack generates 3 html files for the application
In dev mode, in case of code change, only the top level window might listne the events / try to refresh the page
or the main window need a way to advert the subframes to avoid listening

Actual Behavior

in dev mode, all the frames + root window are listening the hot reload changes.
In case of code change, the frames + root window tries to reload the page in same time
Chrome devTools frequently crashes because of to many logs (3x the progress logs) + interrupted sourcemaps decoding

For Bugs; How can we reproduce the behavior?

create an app with an iframe, both pointing to html pages managed by webpack

For Features; What is the motivation and/or use-case for the feature?

Activity

  1. alexander-akait commented on Jan 19, 2021

    @alexander-akait
    Member

    Do not ignore section how we can reproduce it, i.e. core and configuration, otherwise we can't help

    In dev mode, in case of code change, only the top level window might listne the events / try to refresh the page
    or the main window need a way to advert the subframes to avoid listening

    Expected, why do you avoid changes here?

  2. paztis commented on Jan 19, 2021

    @paztis
    Author

    You want me to produce a full application to explain you the problem ?

    Expected, why do you avoid changes here?

    In case of liveReload (page reload), the subframe is destroyed during the top window unload
    Then a new subframe is created.
    Devtools encounter problems because it starts to decode sourcemap then destroy and load a new frame

    I search a way to inform the subframes not to listen to socket events or at least to not refresh code.
    But if I disable hot or liveReload, I do it also for top level window.

    There's no way to provide different configs for each page produced by the same webpack build

  3. alexander-akait commented on Jan 19, 2021

    @alexander-akait
    Member

    You want me to produce a full application to explain you the problem ?

    Minimum or configuration

  4. paztis commented on Jan 19, 2021

    @paztis
    Author

    original comment updated with webpack config and index files

  5. alexander-akait commented on Jan 20, 2021

    @alexander-akait
    Member

    You need to use injectHot as function and return false for index-frame1 and index-frame2

  6. paztis commented on Jan 20, 2021

    @paztis
    Author
  7. paztis commented on Jan 26, 2021

    @paztis
    Author

    any other idea @alexander-akait ?

  8. alexander-akait commented on Jan 26, 2021

    @alexander-akait
    Member

    We need improve injectClient and injectHot and pass entry to callback

  9. paztis commented on Jan 26, 2021

    @paztis
    Author

    Great that was my idea.

  10. alexander-akait commented on Jan 26, 2021

    @alexander-akait
    Member

    Feel free to send a PR

  11. paztis commented on Jan 28, 2021

    @paztis
    Author

    I've take a look at it
    I correctly see how to do it for webpack 4 (in lib/utils/devServerPlugin.js) in prependEntry, as I control all the chunks

    const prependEntry = (originalEntry, additionalEntries) => {
          if (typeof originalEntry === 'function') {
            return () =>
              Promise.resolve(originalEntry()).then((entry) =>
                prependEntry(entry, additionalEntries)
              );
          }
    
          if (typeof originalEntry === 'object' && !Array.isArray(originalEntry)) {
            /** @type {Object<string,string>} */
            const clone = {};
    
            Object.keys(originalEntry).forEach((key) => {
              // entry[key] should be a string here
              const entryDescription = originalEntry[key];
            // ===========> job to do to decide to inject or not, depending of 'key' chunk
              clone[key] = prependEntry(entryDescription, additionalEntries);
            });
    
            return clone;
          }
    
          // in this case, entry is a string or an array.
          // make sure that we do not add duplicates.
          /** @type {Entry} */
          const entriesClone = additionalEntries.slice(0);
          [].concat(originalEntry).forEach((newEntry) => {
            if (!entriesClone.includes(newEntry)) {
              entriesClone.push(newEntry);
            }
          });
          return entriesClone;
        };
    

    But in webpack 5 mode, I don't see how to do it

    compiler.hooks.make.tapPromise('DevServerPlugin', (compilation) =>
            Promise.all(
              additionalEntries.map(
                (entry) =>
                  new Promise((resolve, reject) => {
                    compilation.addEntry(
                      compiler.context,
                      EntryPlugin.createDependency(entry, {}),
                      {}, // global entry
                      (err) => {
                        if (err) return reject(err);
                        resolve();
                      }
                    );
                  })
              )
            )
          );
    

    Any idea of it ?

  12. alexander-akait commented on Jan 29, 2021

    @alexander-akait
    Member

    We should improve our check, yes, it is not implemented

  13. paztis commented on Feb 2, 2021

    @paztis
    Author

    until this is developed, is there's any way to do it through custom plugin I can wrote or something else ? I'm using webpac-dev-server@3.11.2 and webpack@4.

    I know how to do it inside your code for webpack 4, but useless to create a PR that didn't cover the webpack 5 case, or it is ?

  14. alexander-akait commented on Feb 2, 2021

    @alexander-akait
    Member

    I don't think it is possible to solve on plugin level without extra hacks

  15. paztis commented on Feb 2, 2021

    @paztis
    Author

    Will you accept PR for version 3.11, or you stop enhancement on it an onli work on v4 ?

  16. alexander-akait commented on Feb 2, 2021

    @alexander-akait
    Member

    If this does not require global changes, we can accept it, but you need send two PRs for v3 and v4

  17. paztis commented on Feb 2, 2021

    @paztis
    Author

    what it will require I think is a modification / enhancement of the injectClient init param signature, or another init param.
    Is it considered as global ?

  18. alexander-akait commented on Feb 2, 2021

    @alexander-akait
    Member

    I think yes, for me it is not global changes

  19. paztis commented on Feb 6, 2021

    @paztis
    Author

    PR created in v3: #2995
    Tell me if it is ok before I start master report

  20. paztis commented on Feb 7, 2021

    @paztis
    Author

    Here is the PR for master: #2998

  21. alexander-akait commented on Feb 8, 2021

    @alexander-akait
    Member

    I will look at this in this week

  22. paztis commented on Feb 14, 2021

    @paztis
    Author

    Have you found time to look at it ?

  23. alexander-akait commented on Feb 14, 2021

    @alexander-akait
    Member

    On the next week I am working on dev server, so I will look at near future

  24. paztis commented on Mar 2, 2021

    @paztis
    Author

    any news for the review ?

  25. alexander-akait commented on Mar 2, 2021

    @alexander-akait
    Member

    Still on my roadmap (near future)

  26. paztis commented on Mar 10, 2023

    @paztis
    Author

    any updated ? I open it 2 years ago now

  27. alexander-akait commented on Mar 10, 2023

    @alexander-akait
    Member

    @paztis Yeah, sorry for that, let's do rebase of you PR, I want to do a new release soon, so let's incude this in a new release

  28. alexander-akait commented on Mar 10, 2023

    @alexander-akait
    Member

    Anyway why don't use Function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions