From d390d9e66cba6b1711a6107dd25bfaf27f36865f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Sep 2025 22:48:14 +0000 Subject: [PATCH 1/3] Initial plan From d6f7d1f0d0f72c8ff8f25a52c61e0eb8af22eeaf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Sep 2025 23:00:02 +0000 Subject: [PATCH 2/3] Replace browser-sync with django-browser-reload for auto-reload functionality Co-authored-by: MauGx3 <225707+MauGx3@users.noreply.github.com> --- .../developing-locally.rst | 6 +-- .../config/settings/local.py | 7 ++- {{cookiecutter.project_slug}}/config/urls.py | 6 +++ {{cookiecutter.project_slug}}/gulpfile.mjs | 43 ++----------------- {{cookiecutter.project_slug}}/package.json | 1 - .../requirements/local.txt | 1 + 6 files changed, 19 insertions(+), 45 deletions(-) diff --git a/docs/2-local-development/developing-locally.rst b/docs/2-local-development/developing-locally.rst index 278d2542d..0333135cd 100644 --- a/docs/2-local-development/developing-locally.rst +++ b/docs/2-local-development/developing-locally.rst @@ -216,7 +216,7 @@ You can also use Django admin to queue up tasks, thanks to the `django-celerybea Using Webpack or Gulp --------------------- -If you've opted for Gulp or Webpack as front-end pipeline, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change your Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page. +If you've opted for Gulp or Webpack as front-end pipeline, the project comes configured with `Sass`_ compilation. As you change your Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets. The project also uses `django-browser-reload`_ to automatically refresh your browser when changes are detected. #. Make sure that `Node.js`_ v18 is installed on your machine. #. In the project root, install the JS dependencies with:: @@ -227,7 +227,7 @@ If you've opted for Gulp or Webpack as front-end pipeline, the project comes con npm run dev - This will start 2 processes in parallel: the static assets build loop on one side, and the Django server on the other. + This will start 2 processes in parallel: the static assets build loop on one side, and the Django server on the other. `django-browser-reload`_ will detect changes to your Python, CSS, and JavaScript files and will refresh your current browser tab automatically. #. Access your application at the address of the ``node`` service in order to see your correct styles. This is http://localhost:3000 by default. @@ -236,7 +236,7 @@ If you've opted for Gulp or Webpack as front-end pipeline, the project comes con .. _Node.js: http://nodejs.org/download/ .. _Sass: https://sass-lang.com/ -.. _live reloading: https://browsersync.io +.. _django-browser-reload: https://github.com/adamchainz/django-browser-reload Summary ------- diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index c42ce59cc..186924d21 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -58,9 +58,12 @@ INSTALLED_APPS = ["whitenoise.runserver_nostatic", *INSTALLED_APPS] # django-debug-toolbar # ------------------------------------------------------------------------------ # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites -INSTALLED_APPS += ["debug_toolbar"] +INSTALLED_APPS += ["debug_toolbar", "django_browser_reload"] # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware -MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] +MIDDLEWARE += [ + "debug_toolbar.middleware.DebugToolbarMiddleware", + "django_browser_reload.middleware.BrowserReloadMiddleware", +] # https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config DEBUG_TOOLBAR_CONFIG = { "DISABLE_PANELS": [ diff --git a/{{cookiecutter.project_slug}}/config/urls.py b/{{cookiecutter.project_slug}}/config/urls.py index c69358180..f25dd259c 100644 --- a/{{cookiecutter.project_slug}}/config/urls.py +++ b/{{cookiecutter.project_slug}}/config/urls.py @@ -80,3 +80,9 @@ if settings.DEBUG: path("__debug__/", include(debug_toolbar.urls)), *urlpatterns, ] + + if "django_browser_reload" in settings.INSTALLED_APPS: + urlpatterns = [ + path("__reload__/", include("django_browser_reload.urls")), + *urlpatterns, + ] diff --git a/{{cookiecutter.project_slug}}/gulpfile.mjs b/{{cookiecutter.project_slug}}/gulpfile.mjs index 41f02b78e..45ee005bd 100644 --- a/{{cookiecutter.project_slug}}/gulpfile.mjs +++ b/{{cookiecutter.project_slug}}/gulpfile.mjs @@ -8,7 +8,6 @@ import pjson from './package.json' with {type: 'json'}; // Plugins import autoprefixer from 'autoprefixer'; -import browserSyncLib from 'browser-sync'; import concat from 'gulp-concat'; import tildeImporter from 'node-sass-tilde-importer'; import cssnano from 'cssnano'; @@ -21,8 +20,6 @@ import * as dartSass from 'sass'; import gulUglifyES from 'gulp-uglify-es'; import { spawn } from 'node:child_process'; -const browserSync = browserSyncLib.create(); -const reload = browserSync.reload; const sass = gulpSass(dartSass); const uglify = gulUglifyES.default; @@ -129,42 +126,10 @@ function runServer(cb) { } {%- endif %} -// Browser sync server for live reload -function initBrowserSync() { - browserSync.init( - [`${paths.css}/*.css`, `${paths.js}/*.js`, `${paths.templates}/*.html`], - { - {%- if cookiecutter.use_docker == 'y' %} - // https://www.browsersync.io/docs/options/#option-open - // Disable as it doesn't work from inside a container - open: false, - {%- endif %} - // https://www.browsersync.io/docs/options/#option-proxy - proxy: { - {%- if cookiecutter.use_docker == 'n' %} - target: '127.0.0.1:8000', - {%- else %} - target: 'django:8000', - {%- endif %} - proxyReq: [ - function (proxyReq, req) { - // Assign proxy 'host' header same as current request at Browsersync server - proxyReq.setHeader('Host', req.headers.host); - }, - ], - }, - }, - ); -} - // Watch function watchPaths() { watch(`${paths.sass}/*.scss`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, styles); - watch(`${paths.templates}/**/*.html`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}).on('change', reload); - watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`]{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, scripts).on( - 'change', - reload, - ); + watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`]{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, scripts); } // Generate all assets @@ -173,12 +138,12 @@ const build = parallel(styles, scripts, vendorScripts, imgCompression); // Set up dev environment {%- if cookiecutter.use_docker == 'n' %} {%- if cookiecutter.use_async == 'y' %} -const dev = parallel(asyncRunServer, initBrowserSync, watchPaths); +const dev = parallel(asyncRunServer, watchPaths); {%- else %} -const dev = parallel(runServer, initBrowserSync, watchPaths); +const dev = parallel(runServer, watchPaths); {%- endif %} {%- else %} -const dev = parallel(initBrowserSync, watchPaths); +const dev = parallel(watchPaths); {%- endif %} task('default', series(build, dev)); diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json index 0cc93797d..ca66fae58 100644 --- a/{{cookiecutter.project_slug}}/package.json +++ b/{{cookiecutter.project_slug}}/package.json @@ -8,7 +8,6 @@ "autoprefixer": "^10.4.0", "babel-loader": "^10.0.0", "bootstrap": "^5.2.3", - "browser-sync": "^3.0.2", "css-loader": "^7.1.2", "gulp-concat": "^2.6.1", "concurrently": "^9.0.0", diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index 961f9d744..fd3109dfb 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -39,3 +39,4 @@ django-debug-toolbar==6.0.0 # https://github.com/jazzband/django-debug-toolbar django-extensions==4.1 # https://github.com/django-extensions/django-extensions django-coverage-plugin==3.1.1 # https://github.com/nedbat/django_coverage_plugin pytest-django==4.11.1 # https://github.com/pytest-dev/pytest-django +django-browser-reload==1.15.0 # https://github.com/adamchainz/django-browser-reload From a247d22693dd1b685c1f2d98f7d4c6e4ac2deee2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Sep 2025 23:01:52 +0000 Subject: [PATCH 3/3] Fix post-generation hook to handle missing browser-sync package gracefully Co-authored-by: MauGx3 <225707+MauGx3@users.noreply.github.com> --- hooks/post_gen_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 02fd91c07..ca4e45b1f 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -128,7 +128,7 @@ def update_package_json(remove_dev_deps=None, remove_keys=None, scripts=None): package_json = Path("package.json") content = json.loads(package_json.read_text()) for package_name in remove_dev_deps: - content["devDependencies"].pop(package_name) + content["devDependencies"].pop(package_name, None) for key in remove_keys: content.pop(key) content["scripts"].update(scripts)