인프런 커뮤니티 질문&답변

hellonyang님의 프로필 이미지
hellonyang

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)

component_js_dependencies 시 defer, async load

작성

·

114

0

안녕하세요 강의 잘 수강하고 있습니다.


django_components를 사용할 때
template 에서 {% component_js_dependencies %}로 js 로드시

해당 script를 async, defer로 로드할 수 있는 방법이 있을까요?

답변 2

1

이진석님의 프로필 이미지
이진석
지식공유자

해당 코드를 살펴보니, component_js_dependencies 호출 시에 수집된 컴포넌트 클래스 목록의 순서가, 해당 템플릿 태그가 호출이 될 때마다 변경이 되는 django-components 라이브러리의 버그(?)가 있네요.

컴포넌트 클래스 목록을 사전으로 관리되고 있고, 이를 집합으로 가공하는 과정에서 클래스 목록 순서가 그때그때 달라지네요. 그래서 compress 명령 때와 서비스 때의 컴포넌트 클래스 목록은 같지만 순서가 달라서 생성되는 HTML 코드가 다르니까 해싱 key도 달라지는 문제로 보여집니다.

https://github.com/EmilStenstrom/django-components/blob/master/src/django_components/templatetags/component_tags.py#L41

get_components_from_registry 함수 내에서 unique_component_classes 집합 생성 후에, 클래스 이름으로 정렬을 한 번 해주면 이 문제가 해결될 것으로 보여집니다. 한 번 이슈를 제기해봐야겠네요.

--

일단 아래와 같이 몽키패치를 해보실 수 있으시겠습니다.

# core/patch_django_components.py

from django_components.component_registry import ComponentRegistry
from django_components.templatetags import component_tags


def new_get_components_from_registry(registry: ComponentRegistry):

    unique_component_classes = set(registry.all().values())

    # added
    unique_component_classes = sorted(
        unique_component_classes,
        key=lambda cls: cls.__name__,
    )

    components = []
    for component_class in unique_component_classes:
        components.append(component_class(component_class.__name__))

    return components


setattr(
    component_tags, "get_components_from_registry", new_get_components_from_registry
)

위 코드 저장하시고, settings 등에서 임포트해주시면, get_components_from_registry 함수를 바꿀 수 있습니다.

살펴보시고 댓글 남겨주세요. :-)

1

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

component_js_dependencies 템플릿 태그에서는 각 Component 의 render_js_dependencies 메서드를 호출하여 "<script src=js경로></script>\n<script src=js경로></script>" 문자열을 생성합니다.

관련 소스 코드 : https://github.com/EmilStenstrom/django-components/blob/master/src/django_components/component.py#L173

위 소스코드를 보시면, render_js_dependencies 메서드 내에서 <script>{self.js}</script> 코드와 self.media.render_js() 코드를 통해 script 태그를 조합하여, script 태그 문자열을 조합하는 데요. 기본 구현에서는 script 태그에 src 속성 외에는 추가 속성은 지원하고 있지 않습니다.

이 script 태그에 async와 defer 속성을 추가하실려면, 각 Component 클래스의 render_js_dependencies 메서드를 재정의하신 후에, 아래처럼 문자열 변경으로 원하시는 속성을 추가해주실 수 있습니다.

@component.register("예시")
class ExampleComponent(component.Component):
    # 생략

    def render_js_dependencies(self) -> SafeString:
        html = super().render_js_dependencies()
        html = html.replace("<script", "<script defer")
        return mark_safe(html)

살펴보시고 댓글 남겨주세요.

화이팅입니다. :-)

hellonyang님의 프로필 이미지
hellonyang
질문자

안녕하세요 답변주셔서 감사합니다.
답변주신 내용을 적용해서 서비스를 배포중에 한가지 더 문제가 있더라구요.
강의 내용을 벗어날 수도 있지만 혹시나 답변을 주실 수 있는 부분인가 싶어 여쭤봅니다!

제가 django-compress를 사용중인데 배포시에는 COMPRESS_OFFLINE = True 로 설정해서 배포를 합니다.
예를들면 아래와 같이 코드를 사용하고 있습니다.
```
{% block extra_css %} {% compress css %} <link rel="stylesheet" href="{% static 'css/example.css' %}"> {% endcompress %} {% endblock extra_css %}
```

근데 offline compress를 사용하면 compress사이에 동적으로 생성되는 값을 넣을수가 없는 것 같더라구요.
```
{% compress js %} {% component_js_dependencies %} {% endcompress %}
```
위와 같은 코드를 compress하면 js 스크립트가 렌더되지 않은 상태여서 해당 스크립트를 인식하지 못하게 되는 것 같습니다

혹시 이부분을 해결할 수 있는 방법을 알고 계실까요? 🙏

hellonyang님의 프로필 이미지
hellonyang

작성한 질문수

질문하기