Jump to content

Tutorial: Browser sync or Live reload (small footprint)


ukyo
 Share

Recommended Posts

This hook is used to monitor file changes and page updates in your ProcessWire project. It operates when debug mode is active and returns file changes and latest page update information in JSON format.

The script hook is automatically injected before the </body> tag in your HTML. It periodically checks for any file or page updates in your system at the interval you specify. If the previous check time is older than the new check time (indicating changes), the page automatically refreshes.

~/site/ready.php

if ($wire->config->debug) {

    $wire->addHookAfter('Page::render', function (HookEvent $event) {
        $script = <<<HTML
        <script>
        const browserSync = {
            mtime: 0,
            init() {
                this.sync();
            },
            sync() {
                fetch('/browser-sync')
                .then(response => response.json())
                .then(data => {
                    if (!this.mtime) {
                        this.mtime = data.max;
                    } else {
                        if (data.max > this.mtime) {
                            location.reload();
                            }
                        }
                    });
                }
            };
            browserSync.init();
            setInterval(() => browserSync.sync(), 2500);
        </script>
        HTML;

        $event->return = str_replace('</body>', "{$script}</body>", $event->return);
    });

    $wire->addHook('/browser-sync', function (HookEvent $event) {

        $wire = $event->wire();
        $root = $wire->config->paths->root;
        $siteRoot = $wire->config->paths->site;
        $extensions = '*.{php,js,css}';

        $paths = [
            "{$root}src/{$extensions}", // custom composer package
            "{$root}src/src/{$extensions}", // custom composer package
            "{$siteRoot}{$extensions}", // ready.php, init.php, finished.php
            "{$siteRoot}classes/{$extensions}", // page classes
            "{$siteRoot}templates/{$extensions}",
            "{$siteRoot}templates/*/{$extensions}",
            "{$siteRoot}templates/*/*/{$extensions}",
            "{$siteRoot}templates/*/*/*/{$extensions}",
            "{$siteRoot}templates/*/*/*/*/{$extensions}",
        ];

        $files = [];
        foreach ($paths as $pattern) {
            // Try with GLOB_BRACE first
            $result = glob($pattern, GLOB_NOSORT | GLOB_BRACE);
            // If no results with GLOB_BRACE, try without it
            if (!$result) {
                $result = glob($pattern, GLOB_NOSORT) ?: [];
            }
            $files = array_merge($files, $result);
        }

        $filemtime = 0;
        foreach ($files as $file) {
            if (!is_file($file)) {
                continue;
            }
            try {
                $mtime = @filemtime($file);
                if ($mtime && $mtime > $filemtime) {
                    $filemtime = $mtime;
                }
            } catch (\Exception $e) {
                continue;
            }
        }

        $latest = $wire->pages->get('sort=-created|-modified');
        $latestTime = $latest->modified > $latest->created ? $latest->modified : $latest->created;
        
        header('Content-Type: application/javascript');
        echo json_encode([
            'max' => max($filemtime, $latestTime),
            'mtime' => $filemtime,
            'modified' => $latest->modified,
            'created' => $latest->created
        ]);
        exit;
    });
}

This development tool helps streamline your workflow by automatically refreshing the browser when you make changes to your files or content, eliminating the need for manual page refreshes during development.

  • Like 12
Link to comment
Share on other sites

@bernhard

Yes, I know about it. However, I prefer not to use modules for these kinds of things, as my work approach would need to adapt to each module used.

I am using Vite for these purposes instead.

Before developing this script, I was using the AllInOneMinify module for ProcessWire. Later, I switched to JavaScript-based compilation solutions:

  1. First moved to Gulp with Browser Sync
  2. Then migrated to Webpack
  3. Currently using Vite

Among these tools, Vite has proven to be the lightest solution, and I'm getting exactly the results I want with my Vite configuration. While using Vite, I wondered "Why don't I implement my own browser sync solution?" This led me to write this lightweight script, which works remarkably well.

And I'm happy with this setup!

  • Like 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...