Webpack-encore: Dynamic imports don't work with --watch and versioning

Created on 9 Jul 2019  Â·  6Comments  Â·  Source: symfony/webpack-encore

Hello there,

Following a Slack conversation with @Lyrkan, I have detected an unexpected behaviour with the following scenario:

  • Code with the yarn watch daemon running in background
  • Use dynamic imports
  • Versioning is enabled

What's wrong:
Although changes in dynamic imports are properly detected by yarn watch (a compile task is triggered), it's still the old chunk that gets called during the Ajax request related to the import() function.

Steps to reproduce:

  • Create module ./assets/app/dynamic.js and console.log('foo') inside it
  • Create ./assets/app/app.js and write import('./dynamic.js')
  • Encore.enableVersioning(true)
  • Encore.addEntry('app', './assets/app/app.js')
  • Run yarn watch and check your console log in the browser, it should display foo
  • Edit your console log to console.log('bar'): yarn watch will detect changes and compile
  • Go back to your browser again and refresh: it still displays foo.
  • Stop yarn watch, launch it back again, and refresh your browser: it should now display bar.

Visible cause:

  • Even if chunks are regenerated, the new runtime.js still references the old import chunk.

Example:

yarn watch

Files generated:

vendors~app.e4eaffae.js
app.43ccc91a.js
0.c686782a.js
1.47b280f0.js (file that will be called by an ajax request)
runtime.23bc6e15.js (referencing 1.47b280f0.js)

_* Edit dynamically imported file *_

Files generated:

vendors~app.e4eaffae.js (unchanged)
app.43ccc91a.js (unchanged)
0.c686782a.js (unchanged)
1.58820a65.js (changed)
runtime.021c84f2.js (changed, but still referencing 1.47b280f0.js)

Additionnal Notes:

  • This issue doesn't occur with static imports nor with versioning disabled.
HasPR bug

Most helpful comment

Good job @Lyrkan! I confirm removing this plugin actually solves the problem.

All 6 comments

I suspect this is rather a bug in webpack than in Encore. I don't think we customize the building of the runtime file.

@stof Yep, that's @Lyrkan's opinion as well. But even if this can be solved let's keep it for the records, in case someone having the same troubles is looking for support, or if we want to document this.

Yeah, it looks like a bug in Webpack but I'm not 100% certain about it...

I tried reproducing the issue with a really basic setup (without Encore) and it seems to work fine.

// webpack.config.js
module.exports = {
  mode: 'development',
  output: {
    filename: '[name].[contenthash:8].js',
  },
  optimization: {
    runtimeChunk: 'single',
  },
};
// src/index.js
import('./dynamic.js');
// src/dynamic.js
console.log('Foo');
$./node_modules/.bin/webpack --watch

webpack is watching the files…

Hash: 831fd1ed75b526570d79
Version: webpack 4.35.3
Time: 111ms
Built at: 07/09/2019 3:46:00 PM
              Asset       Size   Chunks             Chunk Names
      0.64984b7e.js  343 bytes        0  [emitted]  
   main.fb4816a9.js  496 bytes     main  [emitted]  main
runtime.bb95a825.js    8.9 KiB  runtime  [emitted]  runtime
Entrypoint main = runtime.bb95a825.js main.fb4816a9.js
[./src/dynamic.js] 20 bytes {0} [built]
[./src/index.js] 24 bytes {main} [built]
$ grep 64984b7e dist/runtime.bb95a825.js
/******/        return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + "." + {"0":"64984b7e"}[chunkId] + ".js"

After replacing console.log('Foo') by console.log('Bar'):

Hash: d88f849a462184fad5dc
Version: webpack 4.35.3
Time: 15ms
Built at: 07/09/2019 3:46:30 PM
              Asset       Size   Chunks             Chunk Names
      0.dd16fd12.js  343 bytes        0  [emitted]  
runtime.1f052d70.js    8.9 KiB  runtime  [emitted]  runtime
 + 1 hidden asset
Entrypoint main = runtime.1f052d70.js main.fb4816a9.js
[./src/dynamic.js] 20 bytes {0} [built]
    + 1 hidden module
$ grep 64984b7e dist/runtime.1f052d70.js
$ grep dd16fd12 dist/runtime.1f052d70.js
/******/        return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + "." + {"0":"dd16fd12"}[chunkId] + ".js"

I can however reproduce it with the following webpack.config.js file and Encore:

const Encore = require('@symfony/webpack-encore');

Encore
  .enableSingleRuntimeChunk()
  .setOutputPath('dist/')
  .setPublicPath('/')
  .addEntry('main', './src/index.js')
  .enableVersioning()
;

module.exports = Encore.getWebpackConfig();
$ ./node_modules/.bin/encore dev --watch
Running webpack ...


webpack is watching the files…

 DONE  Compiled successfully in 697ms                                                                                                                                                                     4:05:01 PM

 I  3 files written to dist
Entrypoint main = runtime.0293b661.js main.26cadb5f.js
$ grep 3cc0512d dist/runtime.0293b661.js
/******/        return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + "." + {"0":"3cc0512d"}[chunkId] + ".js"

After replacing console.log('Foo') by console.log('Bar'):

 WAIT  Compiling...

 DONE  Compiled successfully in 19ms

 I  3 files written to dist
Entrypoint main = runtime.fbcb1962.js main.26cadb5f.js
$ grep 3cc0512d dist/runtime.fbcb1962.js
/******/        return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + "." + {"0":"3cc0512d"}[chunkId] + ".js"

So it looks like it's caused by WebpackChunkHash.

It is added automatically when enableVersioning() is called in order to support the [chunkhash] placeholder... but I'm not sure we need it anymore, especially since we also deprecated its use a while ago:

https://github.com/symfony/webpack-encore/blob/f9c3fc6fb047741449238d85e46622b24876f284/lib/plugins/versioning.js#L53-L59

@bpolaszek Could you check if the following code fixes the issue on your project?

// webpack.config.js
const Encore = require('@symfony/webpack-encore');
const WebpackChunkHash = require('webpack-chunk-hash');

Encore
  .enableSingleRuntimeChunk()
  // (...)
;

const config = Encore.getWebpackConfig();

config.plugins = config.plugins.filter(plugin => {
  return !(plugin instanceof WebpackChunkHash);
});

module.exports = config;

Good job @Lyrkan! I confirm removing this plugin actually solves the problem.

Works for me! Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JohnnyEvo picture JohnnyEvo  Â·  3Comments

MatthD picture MatthD  Â·  4Comments

zek0faws picture zek0faws  Â·  4Comments

kegilko picture kegilko  Â·  3Comments

wenmingtang picture wenmingtang  Â·  4Comments