ukyo Posted February 10 Share Posted February 10 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. 12 Link to comment Share on other sites More sharing options...
bernhard Posted February 11 Share Posted February 11 Thx for sharing! In case you don't know or anybody is interested in alternatives: RockDevTools is free and provides asset merge/minify plus live reload: 3 Link to comment Share on other sites More sharing options...
ukyo Posted February 11 Author Share Posted February 11 @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: First moved to Gulp with Browser Sync Then migrated to Webpack 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! 3 Link to comment Share on other sites More sharing options...
abmcr Posted July 14 Share Posted July 14 For bypass the admin page i have added two lines if ($wire->config->debug) { $wire->addHookAfter('Page::render', function (HookEvent $event) { $page = $event->object; if($page->template->name == 'admin') return; (...) Thank you for the snippet 1 Link to comment Share on other sites More sharing options...
Sanyaissues Posted July 30 Share Posted July 30 (edited) Also, for those using DDEV there's a ddev-browsersync add-on, that's simple to use: ddev add-on get ddev/ddev-browsersync ddev restart And then, open .ddev/browser-sync.cjs and add the files you want to watch (the more specific, the better), e.g: files: ["/site/templates/**/*.php", "/site/templates/**/*.css"] Start browsersync, and launch the browser ddev browsersync ddev launch :3000 //Or just open https://yoursite.ddev.site:3000 Update a template and test it! You will notice a brief connected message: Edit: Adding this, in case it could be useful for someone else Here's an example of some useful settings: // #ddev-generated let docroot = process.env.DDEV_DOCROOT; let filesdir = process.env.DDEV_FILES_DIR; let url = process.env.DDEV_HOSTNAME; let nonSslUrl = process.env.DDEV_PRIMARY_URL.replace(/^https:/, 'http:'); if (filesdir === "") { filesdir = null; } module.exports = { files: [ "./site/templates/**/*.{latte,php,js,css}" // watch these file types in templates ], ignore: ["node_modules", filesdir, "vendor"], open: false, ui: false, server: false, notify: false, // disable Browsersync notification proxy: { target: nonSslUrl }, host: url, snippetOptions: { blacklist: ["/processwire/**"] // avoid refreshing admin backend }, }; Edited August 13 by Sanyaissues Adding more context 4 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now