Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HMR with cross-domain iframe content script causes infinite reload #3861

Closed
1 of 2 tasks
ChrRubin opened this issue Sep 21, 2021 · 8 comments
Closed
1 of 2 tasks

HMR with cross-domain iframe content script causes infinite reload #3861

ChrRubin opened this issue Sep 21, 2021 · 8 comments

Comments

@ChrRubin
Copy link

  • This is a bug
  • This is a modification request

Code

An example repo can be found here.

Please paste the results of npx webpack-cli info here, and mention other relevant information

  System:
    OS: Linux 4.19 Arch Linux
    CPU: (6) x64 AMD Ryzen 5 2600 Six-Core Processor
    Memory: 2.23 GB / 7.77 GB
  Binaries:
    Node: 16.5.0 - ~/.nvm/versions/node/v16.5.0/bin/node
    Yarn: 1.22.10 - /usr/sbin/yarn
    npm: 7.19.1 - ~/.nvm/versions/node/v16.5.0/bin/npm
  Packages:
    clean-webpack-plugin: ^4.0.0 => 4.0.0
    copy-webpack-plugin: ^9.0.1 => 9.0.1
    webpack: ^5.53.0 => 5.53.0
    webpack-cli: ^4.8.0 => 4.8.0
    webpack-dev-server: ^4.2.1 => 4.2.1

Expected Behavior

Cross-domain iframe does not reload infinitely when hot reload is triggered.

Actual Behavior

When developing for chrome extensions, triggering hot reload in a page with a cross-domain iframe that has an injected content script causes the iframe to reload infinitely, even when the change is not on the injected content script.

Checking the browser console shows that HMR tries to load the *.hot-update.json file via the iframe's domain, and continues to reload and fail infinitely:

image

This bug did not occur in webpack-dev-server v3.11.2.

For Bugs; How can we reproduce the behavior?

The example repo's README.md contains details on how to reproduce this behaviour.

@alexander-akait
Copy link
Member

Weird, very

@alexander-akait
Copy link
Member

If I use<iframe src="https://example.com/" width="500" height="500"></iframe> all works fine

@alexander-akait
Copy link
Member

Even more try to add "build": "webpack build" and run it after yarn serve, extension still try to connect to dev server, but if I remove <iframe> all works fine

@alexander-akait
Copy link
Member

Solution:

const webpack = require('webpack');
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const isProduction = process.env.NODE_ENV == 'production';

const notHotReload = ['content-script', 'devtools', 'background'];
const entry =  {
  background: path.join(__dirname, 'src', 'background.js'),
  'content-script': path.join(__dirname, 'src', 'content-script.js'),
  'page-script': path.join(__dirname, 'src', 'page-script.js')
};

const host = 'localhost';
const port = 3010;

for (var entryName in entry) {
  if (!notHotReload.includes(entryName)) {
    entry[entryName] = [
      'webpack/hot/dev-server',
      `webpack-dev-server/client?hot=true&hostname=${host}&port=${port}`,
    ].concat(entry[entryName]);
  }
}

const config = {
  devtool: false,
  entry,
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
  devServer: {
    host,
    port,
    allowedHosts: 'all',
    // We disable hot, because we use manual hot setup, i.e. we are adding `webpack/hot/dev-server` and `HotModuleReplacementPlugin` manually (under the hood `hot: true` do the same, but we don't need hot for all entries)
    hot: false,
    // We disable default client in favor `webpack-dev-server/client?hot=true&hostname=${host}&port=${port}`, again because we do it manually
    client: false,
    headers: { 'Access-Control-Allow-Origin': '*' },
    static: {
      directory: path.join(__dirname, '../dist')
    },
    devMiddleware: {
      writeToDisk: true
    }
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),  
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'src/manifest.json'
        },
        {
          from: 'src/page.html'
        }
      ]
    })
  ],
};

module.exports = () => {
  if (isProduction) {
    config.mode = 'production';
  } else {
    config.mode = 'development';
  }
  return config;
};

You don't need to add hot entries for ['content-script', 'devtools', 'background']. Because they are worked in another worker, you can't hot them.

@alexander-akait
Copy link
Member

Note - you don't need CleanWebpackPlugin, because we have output.clean: true

@alexander-akait
Copy link
Member

Hot/LiveReload for extensions is bit tricky, feel free to feedback

@ChrRubin
Copy link
Author

Ah, so basically moving forward with WDS v4 we should just disable HMR for any content/background scripts when developing extensions? Or is it just for this case with cross-domain iframes?

I vaguely recall HMR not being the most reliable for reloading content scripts on v3.11.2, but at least it didn't cause infinite reloads like it does now, which is why I thought it might be a bug with v4.

On a side note, might be a nice QOL feature to have a config option to exclude entries from HMR without manually setting it up.

@alexander-akait
Copy link
Member

On a side note, might be a nice QOL feature to have a config option to exclude entries from HMR without manually setting it up.

Yes, it is in our roadmap, already tracked #2969, title is some misleading, but there is the same problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants