I'm developing a site (live), making a lot of css modification. I'm having to wait several minutes before the changes can be displayed in a browser. I've turned off as much caching as I'm aware of such as /performance, the two core caching modules, cPanel, and default/settings.local.php. I can't identify what's using caching still. The behavior is random. Sometimes the css changes take effect immediately, but mostly it takes several minutes. I can't even fix it with "clear cache." I just have to wait a few minutes.
What's strange is I'm using three browsers: Chrome, FF, and Brave. Sometimes the changes will take effect immediately on one of these and not the others, but that switches. So, FF will work while the other two have to wait. Then Chrome will work and the others have to wait and so on. Even clearing browser data/cookies/cache doesn't work. Frustrating!
I'm not using Views or Block caching, or any contrib caching modules. Having disabled all the cache I mentioned above does slow down my admin pages, but I really don't mind that. I just need my css changes to be taken immediately.
Please help me set my caching correctly for my environment. I don't need any caching right now. There is tons of resources on caching, but I'm finding that not all agree on what's best practice. Frustrating!
My site will never have anonymous users (except for the login page). Caching for anons will be unnecessary. So, if this means I can permanently disable some of these cache systems, please let me know.
I've added below my modules, settings.php, settings.local.php, and .htaccess files.
VM?
These are my modules:
| admin_content_notification |
| auto_entitylabel |
| collapsiblock |
| ctools |
| ds |
| empty_fields |
| entity_print |
| entity_reference_revisions |
| eva |
| field_display_label |
| field_group |
| field_permissions |
| form_mode_control |
| jquery_ui |
| login_destination |
| module_filter |
| node_view_permissions |
| page_manager |
| paragraphs |
| pathauto |
| pdf_reader |
| prepopulate |
| save_edit |
| simple_gmap |
| taxonomy_manager |
| token |
| vertical_tabs_config |
| view_unpublished |
| views_autosubmit |
My settings.local.php:
<?php
// @codingStandardsIgnoreFile
/**
* @file
* Local development override configuration feature.
*
* To activate this feature, copy and rename it such that its path plus
* filename is 'sites/default/settings.local.php'. Then, go to the bottom of
* 'sites/default/settings.php' and uncomment the commented lines that mention
* 'settings.local.php'.
*
* If you are using a site name in the path, such as 'sites/example.com', copy
* this file to 'sites/example.com/settings.local.php', and uncomment the lines
* at the bottom of 'sites/example.com/settings.php'.
*/
/**
* Assertions.
*
* The Drupal project primarily uses runtime assertions to enforce the
* expectations of the API by failing when incorrect calls are made by code
* under development.
*
* @see http://php.net/assert
* @see https://www.drupal.org/node/2492225
*
* If you are using PHP 7.0 it is strongly recommended that you set
* zend.assertions=1 in the PHP.ini file (It cannot be changed from .htaccess
* or runtime) on development machines and to 0 in production.
*
* @see https://wiki.php.net/rfc/expectations
*/
assert_options(ASSERT_ACTIVE, TRUE);
\Drupal\Component\Assertion\Handle::register();
/**
* Enable local development services.
*/
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';
/**
* Show all error messages, with backtrace information.
*
* In case the error level could not be fetched from the database, as for
* example the database connection failed, we rely only on this value.
*/
$config['system.logging']['error_level'] = 'verbose';
/**
* Disable CSS and JS aggregation.
*/
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
/**
* Disable the render cache.
*
* Note: you should test with the render cache enabled, to ensure the correct
* cacheability metadata is present. However, in the early stages of
* development, you may want to disable it.
*
* This setting disables the render cache by using the Null cache back-end
* defined by the development.services.yml file above.
*
* Only use this setting once the site has been installed.
*/
$settings['cache']['bins']['render'] = 'cache.backend.null';
/**
* Disable caching for migrations.
*
* Uncomment the code below to only store migrations in memory and not in the
* database. This makes it easier to develop custom migrations.
*/
$settings['cache']['bins']['discovery_migration'] = 'cache.backend.memory';
/**
* Disable Internal Page Cache.
*
* Note: you should test with Internal Page Cache enabled, to ensure the correct
* cacheability metadata is present. However, in the early stages of
* development, you may want to disable it.
*
* This setting disables the page cache by using the Null cache back-end
* defined by the development.services.yml file above.
*
* Only use this setting once the site has been installed.
*/
$settings['cache']['bins']['page'] = 'cache.backend.null';
/**
* Disable Dynamic Page Cache.
*
* Note: you should test with Dynamic Page Cache enabled, to ensure the correct
* cacheability metadata is present (and hence the expected behavior). However,
* in the early stages of development, you may want to disable it.
*/
# $settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';
/**
* Allow test modules and themes to be installed.
*
* Drupal ignores test modules and themes by default for performance reasons.
* During development it can be useful to install test extensions for debugging
* purposes.
*/
# $settings['extension_discovery_scan_tests'] = TRUE;
/**
* Enable access to rebuild.php.
*
* This setting can be enabled to allow Drupal's php and database cached
* storage to be cleared via the rebuild.php page. Access to this page can also
* be gained by generating a query string from rebuild_token_calculator.sh and
* using these parameters in a request to rebuild.php.
*/
# $settings['rebuild_access'] = TRUE;
/**
* Skip file system permissions hardening.
*
* The system module will periodically check the permissions of your site's
* site directory to ensure that it is not writable by the website user. For
* sites that are managed with a version control system, this can cause problems
* when files in that directory such as settings.php are updated, because the
* user pulling in the changes won't have permissions to modify files in the
* directory.
*/
$settings['skip_permissions_hardening'] = TRUE;
/**
* Exclude modules from configuration synchronization.
*
* On config export sync, no config or dependent config of any excluded module
* is exported. On config import sync, any config of any installed excluded
* module is ignored. In the exported configuration, it will be as if the
* excluded module had never been installed. When syncing configuration, if an
* excluded module is already installed, it will not be uninstalled by the
* configuration synchronization, and dependent configuration will remain
* intact. This affects only configuration synchronization; single import and
* export of configuration are not affected.
*
* Drupal does not validate or sanity check the list of excluded modules. For
* instance, it is your own responsibility to never exclude required modules,
* because it would mean that the exported configuration can not be imported
* anymore.
*
* This is an advanced feature and using it means opting out of some of the
* guarantees the configuration synchronization provides. It is not recommended
* to use this feature with modules that affect Drupal in a major way such as
* the language or field module.
*/
# $settings['config_exclude_modules'] = ['devel', 'stage_file_proxy'];
My settings.php (applicable section)
/**
* Load local development override configuration, if available.
*
* Create a settings.local.php file to override variables on secondary (staging,
* development, etc.) installations of this site.
*
* Typical uses of settings.local.php include:
* - Disabling caching.
* - Disabling JavaScript/CSS compression.
* - Rerouting outgoing emails.
*
* Keep this code block at the end of this file to take full effect.
*/
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
include $app_root . '/' . $site_path . '/settings.local.php';
}
My .htaccess
#
# Apache/PHP/Drupal settings:
#
# Protect files and directories from prying eyes.
<FilesMatch "\.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
</IfModule>
</FilesMatch>
# Don't show directory listings for URLs which map to a directory.
Options -Indexes
# Set the default handler.
DirectoryIndex index.php index.html index.htm
# Add correct encoding for SVGZ.
AddType image/svg+xml svg svgz
AddEncoding gzip svgz
# Most of the following PHP settings cannot be changed at runtime. See
# sites/default/default.settings.php and
# Drupal\Core\DrupalKernel::bootEnvironment() for settings that can be
# changed at runtime.
# PHP 7, Apache 1 and 2.
<IfModule mod_php7.c>
php_value assert.active 0
</IfModule>
# Requires mod_expires to be enabled.
<IfModule mod_expires.c>
# Enable expirations.
ExpiresActive On
# Cache all files for 2 weeks after access (A).
ExpiresDefault A1209600
<FilesMatch \.php$>
# Do not allow PHP scripts to be cached unless they explicitly send cache
# headers themselves. Otherwise all scripts would have to overwrite the
# headers set by mod_expires if they want another caching behavior. This may
# fail if an error occurs early in the bootstrap process, and it may cause
# problems if a non-Drupal PHP file is installed in a subdirectory.
ExpiresActive Off
</FilesMatch>
</IfModule>
# Set a fallback resource if mod_rewrite is not enabled. This allows Drupal to
# work without clean URLs. This requires Apache version >= 2.2.16. If Drupal is
# not accessed by the top level URL (i.e.: http://example.com/drupal/ instead of
# http://example.com/), the path to index.php will need to be adjusted.
<IfModule !mod_rewrite.c>
FallbackResource /index.php
</IfModule>
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Set "protossl" to "s" if we were accessed via https://. This is used later
# if you enable "www." stripping or enforcement, in order to ensure that
# you don't bounce between http and https.
RewriteRule ^ - [E=protossl]
RewriteCond %{HTTPS} on
RewriteRule ^ - [E=protossl:s]
# Make sure Authorization HTTP header is available to PHP
# even when running as CGI or FastCGI.
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Block access to "hidden" directories whose names begin with a period. This
# includes directories used by version control systems such as Subversion or
# Git to store control files. Files whose names begin with a period, as well
# as the control files used by CVS, are protected by the FilesMatch directive
# above.
#
# NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
# not possible to block access to entire directories from .htaccess because
# <DirectoryMatch> is not allowed here.
#
# If you do not have mod_rewrite installed, you should remove these
# directories from your webroot or otherwise protect them from being
# downloaded.
RewriteRule "/\.|^\.(?!well-known/)" - [F]
# If your site can be accessed both with and without the 'www.' prefix, you
# can use one of the following settings to redirect users to your preferred
# URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
#
# To redirect all users to access the site WITH the 'www.' prefix,
# (http://example.com/foo will be redirected to http://www.example.com/foo)
# uncomment the following:
# RewriteCond %{HTTP_HOST} .
# RewriteCond %{HTTP_HOST} !^www\. [NC]
# RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#
# To redirect all users to access the site WITHOUT the 'www.' prefix,
# (http://www.example.com/foo will be redirected to http://example.com/foo)
# uncomment the following:
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
# Modify the RewriteBase if you are using Drupal in a subdirectory or in a
# VirtualDocumentRoot and the rewrite rules are not working properly.
# For example if your site is at http://example.com/drupal uncomment and
# modify the following line:
# RewriteBase /drupal
#
# If your site is running in a VirtualDocumentRoot at http://example.com/,
# uncomment the following line:
# RewriteBase /
# Redirect common PHP files to their new locations.
RewriteCond %{REQUEST_URI} ^(.*)?/(install\.php) [OR]
RewriteCond %{REQUEST_URI} ^(.*)?/(rebuild\.php)
RewriteCond %{REQUEST_URI} !core
RewriteRule ^ %1/core/%2 [L,QSA,R=301]
# Rewrite install.php during installation to see if mod_rewrite is working
RewriteRule ^core/install\.php core/install.php?rewrite=ok [QSA,L]
# Pass all requests not referring directly to files in the filesystem to
# index.php.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]
# For security reasons, deny access to other PHP files on public sites.
# Note: The following URI conditions are not anchored at the start (^),
# because Drupal may be located in a subdirectory. To further improve
# security, you can replace '!/' with '!^/'.
# Allow access to PHP files in /core (like authorize.php or install.php):
RewriteCond %{REQUEST_URI} !/core/[^/]*\.php$
# Allow access to test-specific PHP files:
RewriteCond %{REQUEST_URI} !/core/modules/system/tests/https?\.php
# Allow access to Statistics module's custom front controller.
# Copy and adapt this rule to directly execute PHP files in contributed or
# custom modules or to run another PHP application in the same directory.
RewriteCond %{REQUEST_URI} !/core/modules/statistics/statistics\.php$
# Deny access to any other PHP files that do not match the rules above.
# Specifically, disallow autoload.php from being served directly.
RewriteRule "^(.+/.*|autoload)\.php($|/)" - [F]
# Rules to correctly serve gzip compressed CSS and JS files.
# Requires both mod_rewrite and mod_headers to be enabled.
<IfModule mod_headers.c>
# Serve gzip compressed CSS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
# Serve gzip compressed JS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
# Serve correct content types, and prevent double compression.
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=no-brotli:1]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=no-brotli:1]
<FilesMatch "(\.js\.gz|\.css\.gz)$">
# Serve correct encoding type.
Header set Content-Encoding gzip
# Force proxies to cache gzipped & non-gzipped css/js files separately.
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
</IfModule>
# Various header fixes.
<IfModule mod_headers.c>
# Disable content sniffing, since it's an attack vector.
Header always set X-Content-Type-Options nosniff
# Disable Proxy header, since it's an attack vector.
RequestHeader unset Proxy
</IfModule>
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php74” package as the default “PHP” programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit
# BEGIN cPanel-generated php ini directives, do not edit
# Manual editing of this file may result in unexpected behavior.
# To make changes to this file, use the cPanel MultiPHP INI Editor (Home >> Software >> MultiPHP INI Editor)
# For more information, read our documentation (https://go.cpanel.net/EA4ModifyINI)
<IfModule php7_module>
php_flag display_errors Off
php_value max_execution_time 30
php_value max_input_time 60
php_value max_input_vars 1000
php_value memory_limit 128M
php_value post_max_size 21M
php_value session.gc_maxlifetime 1440
php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
php_value upload_max_filesize 20M
php_flag zlib.output_compression Off
</IfModule>
<IfModule lsapi_module>
php_flag display_errors Off
php_value max_execution_time 30
php_value max_input_time 60
php_value max_input_vars 1000
php_value memory_limit 128M
php_value post_max_size 21M
php_value session.gc_maxlifetime 1440
php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
php_value upload_max_filesize 20M
php_flag zlib.output_compression Off
</IfModule>
# END cPanel-generated php ini directives, do not edit
Comments
I may have fixed it...
After going through the settings.local.php I just posted I noticed I forgot "Disable Dynamic Page Cache." So far it seems to have done the trick.
Well, it was working since my
Well, it was working since my last comment, but it's back to doing the same thing now.
Drupal has many levels of
Drupal has many levels of internal caching, from caching render arrays, caching conditions, caching views, caching database queries.
Usually, the solution is to add a cache context to whatever it is that is being cached incorrectly.
Contact me to contract me for D7 -> D10/11 migrations.
Finding the cache that's
Finding the cache that's causing the lag is the issue.
If it can help find the
If it can help find the culprit, I've timed the cache lag to be 60-70 seconds.