68 CSS JS 바로 적용하기- 웹 캐싱 무효화
68.1 css js 파일 적용 후에도 반영이 안된다
filename.js?ver=20221021 이렇게 버전으로 관리하려다가
매번 수정할 때마다 숫자 바꿔주는게 귀찮아서
https://docs.djangoproject.com/en/4.1/ref/에서 찾아보니 ManifestStaticFilesStorage를 발견했다.
CSS, JS 등 정적파일 이름의 해시값으로 관리하면
내용이 변경되면 브라우저에서 파일을 로드하므로 바로 적용된 화면을 볼 수 있으며,
내용이 변경될 경우만 로드하기때문에 트래픽을 절감할 수 있다.
개발자가 작업하면서 파일을 반영하고 캐시비우기+새로고침이 아닌 F5만 하면 된다는점도 좋다.
브라우저 캐싱
css , js 파일 등 정적파일들은 웹사이트 접속시에 사용자 PC의 특정 폴더에 저장해놓고 사용자가 재 방문시 웹사이트에서 파일을 다운로드하는 것이 아닌 사용자 PC에 저장되어 있는 파일을 읽음으로써 빠르게 불러오고 서버에는 트래픽 낭비를 방지할 수 있는 효과
68.2 ManifestStaticFilesStorage ValueError Missing staticfiles manifest entry for XXXX
DJango Documentation에서는
ManifestStaticFilesStorage 를 setting.py에 적용해주면 된다고 하였으나 안된다.
#https://docs.djangoproject.com/en/4.1/ref/contrib/staticfiles/#manifeststaticfilesstorage
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
ValueError: Missing staticfiles manifest entry for XXXX 에러가 발생하며 서버가 종료된다. ㅠㅠ
https://docs.djangoproject.com/en/4.1/ref/contrib/staticfiles/#manifeststaticfilesstorage
68.3 hashed_name 상속 - base.py storage.py
ManifestStaticFilesStorage 에러해결을 위해 이것저것 해보다가
github에서 해결한 소스를 발견했다.
storage.py의 hashed_name를 오버라이딩하여 해당 에러 부분을 제거한 소스였다.
소스출처: https://github.com/InhaBas/Inhabas.com/blob/dev/Back_end/IBAS/storage.py
setting파일에 myapp.common.storage.StaticFilesMd5HashingStorage 추가
/config/settings/base.py
#https://docs.djangoproject.com/en/4.1/ref/contrib/staticfiles/#manifeststaticfilesstorage
# STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
#https://github.com/InhaBas/Inhabas.com/blob/dev/Back_end/IBAS/storage.py
STATICFILES_STORAGE = 'myapp.common.storage.StaticFilesMd5HashingStorage'
/myapp/common/storage.py 소스
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
from urllib.parse import unquote, urlsplit, urlunsplit
import os
class StaticFilesMd5HashingStorage(ManifestStaticFilesStorage):
manifest_strict = False
def hashed_name(self, name, content=None, filename=None):
# `filename` is the name of file to hash if `content` isn't given.
# `name` is the base name to construct the new hashed filename from.
parsed_name = urlsplit(unquote(name))
clean_name = parsed_name.path.strip()
filename = (filename and urlsplit(unquote(filename)).path.strip()) or clean_name
opened = content is None
if opened:
if not self.exists(filename):
# raise ValueError("The file '%s' could not be found with %r." % (filename, self))
return name
try:
content = self.open(filename)
except OSError:
# Handle directory paths and fragments
return name
try:
file_hash = self.file_hash(clean_name, content)
finally:
if opened:
content.close()
path, filename = os.path.split(clean_name)
root, ext = os.path.splitext(filename)
file_hash = ('.%s' % file_hash) if file_hash else ''
hashed_name = os.path.join(path, "%s%s%s" %
(root, file_hash, ext))
unparsed_name = list(parsed_name)
unparsed_name[2] = hashed_name
# Special casing for a @font-face hack, like url(myfont.eot?#iefix")
# http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax
if '?#' in name and not unparsed_name[3]:
unparsed_name[2] += '?'
return urlunsplit(unparsed_name)
68.4 python manage.py collectstatic
static root의 파일을 모두 삭제하고
쉘에서 python manage.py collectstatic 명령을 치면
bootstrap.bundle.3ddb03a6eb14.js 형식의 파일들이 생성되는 것을 볼수 있다.
python manage.py collectstatic