Skip to content

Unwanted tailwindcss full refresh #9512

Open
@fabio-ivona

Description

Describe the bug

After PR #3929 has ben released in V3,

In Laravel+tailwind+livewire stacks we are experiencing unwanted full refreshes triggered by changes on files registered as dependencies by tailwind

background

during Livewire components development, often with nested interactions, it is generally unwanted to full refresh the page until all template+css changes are completed, as it compels the developer to recreate again the same state of the component in order to show the part under development

Additionally a vite plugin has been released in order to trigger livewire components hot reloads when template files are changed (see here the plugin). The plugin uses

 ctx.server.ws.send({
        type: 'custom',
        event: 'livewire-update',
        data: {
            blade_updated: ctx.file.endsWith('.blade.php'),
        }
    });

to trigger a client-side script that starts the update routine for all livewire components in the page.

the problem

Both using and not using the vite livewire plugin, it is generally detrimental to have a full refresh when a .blade file changes

also, full page refreshes for .blade file changes is a feature already covered by laravel vite plugin (see here the plugin) with an opt-in feature in its config

the cause

PR #3929 fixes other issues by adding this code d97b33a to trigger a full refresh when a change happens in a .blade file registered as dependency by tailwind preprocessing

reproduction

the issue can be reproduced in any plain laravel+tailwind installation, seeing that the page is full refreshed at every .blade file change.

a ready to use repository is available at the reproduction link, it works with docker+docker-compose in order to setup an nginx+php+mysql environment, but can also be set up manually

see the repository readme for detailed steps

desired behaviour

in V2 the behaviour was the desired one:

when a .blade file was changes, tailwind recompiled app.css file, then Vite:

  • hot reloads the app.css file (as it is changed)
  • (optionally) livewire a custom update or full refresh message payloads are sent by laravel/livewire plugins

the solution

is there the possibility to make this part of code conditional? maybe with a vite config setting to disable it where needed?

I've set up a small Laravel/livewire project to reproduce the issue

Reproduction

https://github.com/fabio-ivona/livewire-refresh

System Info

tested both on

System:
    OS: Linux 5.13 Ubuntu 22.04.1 LTS 22.04.1 LTS (Jammy Jellyfish)
    CPU: (16) x64 AMD Ryzen 7 5700G with Radeon Graphics
    Memory: 17.04 GB / 31.14 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 16.16.0 - /usr/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 8.15.1 - /usr/bin/npm
  npmPackages:
    vite: ^3.0.0 => 3.0.4


and

System:
    OS: Linux 5.13 Ubuntu 21.10 21.10 (Impish Indri)
    CPU: (16) x64 AMD Ryzen 7 5700G with Radeon Graphics
    Memory: 17.10 GB / 31.14 GB
    Container: Yes
    Shell: 5.8 - /usr/bin/zsh
  Binaries:
    Node: 16.15.0 - /usr/local/bin/node
    npm: 8.5.5 - /usr/local/bin/npm
  Browsers:
    Chrome: 103.0.5060.134
    Firefox: 103.0.1
  npmPackages:
    vite: ^3.0.0 => 3.0.4

Used Package Manager

npm

Logs

Click to expand!
  vite:config bundled config file loaded in 55.85ms +0ms
  vite:config using resolved config: {
  vite:config   plugins: [
  vite:config     'vite:pre-alias',
  vite:config     'alias',
  vite:config     'vite:modulepreload-polyfill',
  vite:config     'vite:optimized-deps',
  vite:config     'vite:resolve',
  vite:config     'vite:html-inline-proxy',
  vite:config     'vite:css',
  vite:config     'vite:esbuild',
  vite:config     'vite:json',
  vite:config     'vite:wasm-helper',
  vite:config     'vite:worker',
  vite:config     'vite:asset',
  vite:config     'vite:wasm-fallback',
  vite:config     'vite:define',
  vite:config     'vite:css-post',
  vite:config     'vite:worker-import-meta-url',
  vite:config     'vite:dynamic-import-vars',
  vite:config     'vite:import-glob',
  vite:config     'laravel',
  vite:config     'vite:client-inject',
  vite:config     'vite:import-analysis'
  vite:config   ],
  vite:config   optimizeDeps: {
  vite:config     disabled: 'build',
  vite:config     force: undefined,
  vite:config     esbuildOptions: { preserveSymlinks: undefined }
  vite:config   },
  vite:config   server: {
  vite:config     preTransformRequests: true,
  vite:config     origin: '__laravel_vite_placeholder__',
  vite:config     host: '0.0.0.0',
  vite:config     port: 5173,
  vite:config     strictPort: true,
  vite:config     middlewareMode: false,
  vite:config     fs: { strict: true, allow: [Array], deny: [Array] }
  vite:config   },
  vite:config   base: '/',
  vite:config   publicDir: '',
  vite:config   build: {
  vite:config     target: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari13' ],
  vite:config     polyfillModulePreload: true,
  vite:config     outDir: 'public/build',
  vite:config     assetsDir: 'assets',
  vite:config     assetsInlineLimit: 4096,
  vite:config     cssCodeSplit: true,
  vite:config     cssTarget: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari13' ],
  vite:config     sourcemap: false,
  vite:config     rollupOptions: { input: [Array] },
  vite:config     minify: 'esbuild',
  vite:config     terserOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     manifest: true,
  vite:config     lib: false,
  vite:config     ssr: false,
  vite:config     ssrManifest: false,
  vite:config     reportCompressedSize: true,
  vite:config     chunkSizeWarningLimit: 500,
  vite:config     watch: null,
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] }
  vite:config   },
  vite:config   resolve: { alias: [ [Object], [Object], [Object] ] },
  vite:config   ssr: {
  vite:config     format: 'esm',
  vite:config     target: 'node',
  vite:config     noExternal: [ 'laravel-vite-plugin' ],
  vite:config     optimizeDeps: { disabled: true, esbuildOptions: [Object] }
  vite:config   },
  vite:config   configFile: '/var/www/html/vite.config.js',
  vite:config   configFileDependencies: [ '/var/www/html/vite.config.js' ],
  vite:config   inlineConfig: {
  vite:config     root: undefined,
  vite:config     base: undefined,
  vite:config     mode: undefined,
  vite:config     configFile: undefined,
  vite:config     logLevel: undefined,
  vite:config     clearScreen: undefined,
  vite:config     optimizeDeps: { force: undefined },
  vite:config     server: {}
  vite:config   },
  vite:config   root: '/var/www/html',
  vite:config   cacheDir: '/var/www/html/node_modules/.vite',
  vite:config   command: 'serve',
  vite:config   mode: 'development',
  vite:config   isWorker: false,
  vite:config   mainConfig: null,
  vite:config   isProduction: false,
  vite:config   preview: {
  vite:config     port: undefined,
  vite:config     strictPort: true,
  vite:config     host: '0.0.0.0',
  vite:config     https: undefined,
  vite:config     open: undefined,
  vite:config     proxy: undefined,
  vite:config     cors: undefined,
  vite:config     headers: undefined
  vite:config   },
  vite:config   env: {
  vite:config     VITE_PUSHER_APP_KEY: '',
  vite:config     VITE_PUSHER_HOST: '',
  vite:config     VITE_PUSHER_PORT: '443',
  vite:config     VITE_PUSHER_SCHEME: 'https',
  vite:config     VITE_PUSHER_APP_CLUSTER: 'mt1',
  vite:config     BASE_URL: '/',
  vite:config     MODE: 'development',
  vite:config     DEV: true,
  vite:config     PROD: false
  vite:config   },
  vite:config   assetsInclude: [Function: assetsInclude],
  vite:config   logger: {
  vite:config     hasWarned: false,
  vite:config     info: [Function: info],
  vite:config     warn: [Function: warn],
  vite:config     warnOnce: [Function: warnOnce],
  vite:config     error: [Function: error],
  vite:config     clearScreen: [Function: clearScreen],
  vite:config     hasErrorLogged: [Function: hasErrorLogged]
  vite:config   },
  vite:config   packageCache: Map(0) {},
  vite:config   createResolver: [Function: createResolver],
  vite:config   worker: {
  vite:config     format: 'iife',
  vite:config     plugins: [
  vite:config       [Object], [Object], [Object],
  vite:config       [Object], [Object], [Object],
  vite:config       [Object], [Object], [Object],
  vite:config       [Object], [Object], [Object],
  vite:config       [Object], [Object], [Object],
  vite:config       [Object], [Object], [Object],
  vite:config       [Object], [Object]
  vite:config     ],
  vite:config     rollupOptions: {}
  vite:config   },
  vite:config   appType: 'spa',
  vite:config   experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false }
  vite:config } +57ms
  vite:deps Hash is consistent. Skipping. Use --force to override. +0ms

  VITE v3.0.4  ready in 255 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: http://172.27.0.7:5173/

  LARAVEL v9.23.0  plugin v0.5.2

  ➜  APP_URL: http://livewire-refresh.test
  vite:spa-fallback Rewriting GET / to /index.html +0ms
  vite:time 2.70ms /index.html +0ms
  vite:time 5.04ms /index.html +3ms
  vite:spa-fallback Rewriting GET / to /index.html +6ms
  vite:time 0.52ms /index.html +2ms
  vite:time 0.91ms /index.html +0ms
  vite:hmr [file change] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +0ms
  vite:hmr [no modules matched] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +1ms
  vite:resolve 1.90ms /@vite/client -> /var/www/html/node_modules/vite/dist/client/client.mjs +0ms
  vite:resolve 0.39ms /resources/css/app.css?direct -> /var/www/html/resources/css/app.css?direct +4ms
  vite:load 6.02ms [fs] /@vite/client +0ms
  vite:resolve 0.33ms @vite/env -> /var/www/html/node_modules/vite/dist/client/env.mjs +12ms
  vite:resolve 0.11ms /node_modules/vite/dist/client/env.mjs -> /var/www/html/node_modules/vite/dist/client/env.mjs +1ms
  vite:import-analysis 5.20ms [1 imports rewritten] node_modules/vite/dist/client/client.mjs +0ms
  vite:transform 9.23ms /@vite/client +0ms
  vite:time 21.74ms /@vite/client +248ms
  vite:load 14.64ms [fs] /resources/css/app.css?direct +13ms
  vite:cache [304] /@vite/client +0ms
  vite:time 0.37ms /@vite/client +4ms
  vite:load 4.74ms [fs] /node_modules/vite/dist/client/env.mjs +4ms
  vite:import-analysis 0.07ms [no imports] node_modules/vite/dist/client/env.mjs +7ms
  vite:transform 0.39ms /node_modules/vite/dist/client/env.mjs +7ms
  vite:time 1.37ms /node_modules/vite/dist/client/env.mjs +2ms
  vite:cache [304] /node_modules/vite/dist/client/env.mjs +332ms
  vite:time 0.44ms /node_modules/vite/dist/client/env.mjs +331ms
  vite:resolve 0.17ms /resources/views/welcome.blade.php -> /var/www/html/resources/views/welcome.blade.php +516ms
  vite:resolve 0.21ms /resources/views/livewire/hello-world.blade.php -> /var/www/html/resources/views/livewire/hello-world.blade.php +1ms
  vite:resolve 0.18ms /resources/js/app.js -> /var/www/html/resources/js/app.js +0ms
  vite:resolve 0.18ms /resources/js/bootstrap.js -> /var/www/html/resources/js/bootstrap.js +1ms
  vite:resolve 0.16ms /tailwind.config.js -> /var/www/html/tailwind.config.js +0ms
  vite:import-analysis [skipped] resources/css/app.css?direct +511ms
  vite:transform 515.90ms /resources/css/app.css?direct +511ms
  vite:time 532.72ms /resources/css/app.css +180ms
  vite:cache [304] /resources/css/app.css?direct +182ms
  vite:time 0.65ms /resources/css/app.css +2ms
  vite:deps ✨ static imports crawl ended +2s
  vite:hmr [file change] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +5s
  vite:hmr [no modules matched] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +0ms
  vite:hmr [file change] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +279ms
  vite:hmr [no modules matched] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +0ms
  vite:hmr [file change] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +339ms
  vite:hmr [no modules matched] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +0ms
  vite:hmr [file change] resources/views/livewire/hello-world.blade.php +11s
7:37:41 AM [vite] page reload resources/views/livewire/hello-world.blade.php
  vite:hmr [file change] storage/framework/views/4e0125ea13b45623cb2cef72879f41ca2753763e.php +50ms
  vite:hmr [no modules matched] storage/framework/views/4e0125ea13b45623cb2cef72879f41ca2753763e.php +0ms
  vite:hmr [file change] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +2ms
  vite:hmr [no modules matched] storage/framework/sessions/5bVKUXpEXuUOZ0bLZZRyXLZ5WHgm4uDKplNJHS34 +1ms
  vite:cache [304] /@vite/client +16s
  vite:time 1.45ms /@vite/client +16s
  vite:load 3.14ms [fs] /resources/css/app.css?direct +17s
  vite:import-analysis [skipped] resources/css/app.css?direct +16s
  vite:transform 28.68ms /resources/css/app.css?direct +16s
  vite:time 35.04ms /resources/css/app.css +36ms
  vite:cache [304] /@vite/client +38ms
  vite:time 1.25ms /@vite/client +2ms
  vite:cache [304] /resources/css/app.css?direct +1ms
  vite:time 0.53ms /resources/css/app.css +1ms
  vite:hmr [file change] .idea/workspace.xml +80ms
  vite:hmr [no modules matched] .idea/workspace.xml +0ms
  vite:cache [304] /node_modules/vite/dist/client/env.mjs +29ms
  vite:time 0.44ms /node_modules/vite/dist/client/env.mjs +29ms
  vite:cache [304] /node_modules/vite/dist/client/env.mjs +19ms
  vite:time 0.59ms /node_modules/vite/dist/client/env.mjs +19ms

Validations

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions