Webpack/Phaser Performance Issue

Hello,

When I was developing my game using imports to connect the classes, it ran smoothly. Now that I’ve bundled my project with Webpack, it has become very choppy. Here is a 10 second video demonstrating the issue.

I have tried many solutions/manipulations of the config file to try to get it to work smoothly. I tried using terser and babel, not using them, using the optimization settings on the webpack docs, every combination I can think of. Everything makes it choppy with Webpack.

Does anyone know what I can do differently to make this work? Can someone share their webpack config file or let me know what mine might be missing?

My webpack.config.js:

const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
// const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
  entry: {
    app:'./index.js',
   'production-dependencies': ['phaser']
  },
  mode: 'production',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename:'[name].bundle.js'
  },
  // optimization: {
  //     minimize: true,
  //     minimizer: [new TerserPlugin()],
  //     splitChunks: {
  //       chunks:'all'
  //     },
  //   },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname),
        // use: {
        //   loader:'babel-loader',
        //   options: {
        //     presets: ['env']
        //   }
        // }
      }
    ]
  },

  devServer: {
    contentBase: path.resolve(__dirname, 'build'),
  },

  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        { from: path.resolve(__dirname, 'index.html'),  to: path.resolve(__dirname, 'build') },

        { from: path.resolve(__dirname, 'assets', 'apple_juice.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'balloon_blue.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'balloon_green.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'balloon_pink.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'balloon_purple.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'balloon_red.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'balloon_yellow.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'blank_screen.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'black.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'blast.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'blast2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'blast_backup.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'blast_cover.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'car_wheel.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'check_flag.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'confetti.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'controller.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'credits.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'dark_rock.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enter_key.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'fact2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'fence.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'flag.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'futureish.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'hill.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'keyboard.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'lava.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'level3_bg_cutscene.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'life_bar.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'limo.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'liquid_blue.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'liquid_green.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'liquid_purple.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'logo2.jpg'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'main_menu.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'mute.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'options.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'parking_lot.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'phone.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'phone2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'platform.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'play_game.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'red_car.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'road.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'rock.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'snow.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'starburst.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'test_title.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'thought.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'van.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'water.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'welcome_to_chicago.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'wind.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'bird.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'boss_bird.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'boss_bot.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'boss_tomato.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'bot.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'buzz_saw.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'canceled.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'demonetization.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'drill.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'egg.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'explosion.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'eye.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'gear.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'machine.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'milkshake.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'regular_tomato.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'small_bot.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'snowflake.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'spikey_ball.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'tomato.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'torch.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'trash_can.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'enemies', 'wheel.png'),  to: path.resolve(__dirname, 'build') },

        { from: path.resolve(__dirname, 'assets', 'maps', 'awesome_sunset_sky.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'bg_forest_b.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'bg_forest_c.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'cutscene_buildings.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'cutscene_buildings.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'cutscene_buildings2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'debug_level.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'debug_level.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'debug_level_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'flat_level.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1_bg1.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1_bg2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1_bg_sky.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level1_tileset_original.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level2.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level2.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level2_bg1.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level2_bg2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level2_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level2_tileset_original.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg4.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg_sky1.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg_sky2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg_sky3.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg_sky4.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg_sky5.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_bg_sky6.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level3_tileset_original.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_bg1.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_bg2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_bg3.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_bg4.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_bg_sky1.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_bg_sky2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level4_tileset_original.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level5.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level5.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level5.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level5_bg.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level5_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level5_tileset_original.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6_bg1.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6_bg2.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6_bg3.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6_tileset.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'level6_tileset_original.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'options_bg.png'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'test_level.json'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'test_level.tmx'),  to: path.resolve(__dirname, 'build') },
        { from: path.resolve(__dirname, 'assets', 'maps', 'test_level_copy.json'),  to: path.resolve(__dirname, 'build') },

      ]
    }),
    new webpack.DefinePlugin({
     'typeof CANVAS_RENDERER': JSON.stringify(false),
     'typeof WEBGL_RENDERER': JSON.stringify(true)
     }),
   new CleanWebpackPlugin({
         root: path.resolve(__dirname, '../')
    })
  ]
}

Hi,

I can’t help you with webpack, but i use it without problems, i use the config from the phaser3-project-template


Perhaps you can compare the configs…

Is it choppy the whole time? Can you compare w/ Chrome FPS meter?

Console shows same Phaser version in both?

So it turned out the version was different, the smooth one was using 3.17.0 and the choppy one was using 3.24.1. Now I’ve tried every version since 3.17.0 and they all (except this one) have the stuttery movement as seen in the video. Any idea why that might be?

I’m facing another issue in 3.17.0 but it’s the only one that doesn’t have that choppiness.

The frame rate shows as 75 fps with each version, whether smooth or choppy.

Hi @t_rev44 ,
If you are using Arcade physics, try:

// In create() function
this.physics.world.fixedStep = false;

This code syncs physics to the game render (variable physics step).

Regards.

That didn’t seem to change anything. I’ve now discovered that the stutter is happening when the frame rate goes above 60fps. And it goes up to 75 when I plug in a monitor with a higher refresh rate (my laptop hz is 60, so it runs smoothly with only the laptop).

I know this bug was reportedly fixed after 3.17.0, but it’s happening for me with every version. How can I prevent the frame rate from exceeding 60 when the monitor’s hz is above 60?

Do you see any problems in

on that monitor?

You need to use v3.24.1 to use fixedStep = false. It won’t work in v3.17.0.

You should also try increasing Arcade Physics fps (150, 300, or 450). Double-check that you’re doing it correctly; it needs to be done in the physics config or by setFPS().

Using fixedStep=false on 3.24.1 SEEMS to have fixed the issue… but I thought it was gone before when it wasn’t so I will test more and come back.