From 50c3e5ba261db4ee8197cf9c9b234a8d1ad3f152 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 25 Jun 2025 18:32:21 -0700 Subject: [PATCH 1/4] Include default metas for char_set and viewport If the user does not override the char_set or viewport metas with their own, then include these as defaults. --- reflex/compiler/utils.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py index 22a176e93c3..4061406eacc 100644 --- a/reflex/compiler/utils.py +++ b/reflex/compiler/utils.py @@ -359,21 +359,34 @@ def create_document_root( Returns: The document root. """ - head_components = [ - *( - head_components - or [ - # Default meta tags if user does not provide. - Meta.create(char_set="utf-8"), - Meta.create( - name="viewport", content="width=device-width, initial-scale=1" - ), - ] - ), - # Always include the framework meta and link tags. + existing_meta_types = set() + + for component in head_components or []: + if isinstance(component, Meta): + if component.char_set: # pyright: ignore[reportAttributeAccessIssue] + existing_meta_types.add("char_set") + if component.name == "viewport": # pyright: ignore[reportAttributeAccessIssue] + existing_meta_types.add("viewport") + + # Always include the framework meta and link tags. + always_head_components = [ ReactMeta.create(), Links.create(), ] + maybe_head_components = [] + # Only include these if the user has not specified them. + if "char_set" not in existing_meta_types: + maybe_head_components.append(Meta.create(char_set="utf-8")) + if "viewport" not in existing_meta_types: + maybe_head_components.append( + Meta.create(name="viewport", content="width=device-width, initial-scale=1") + ) + + head_components = [ + *(head_components or []), + *maybe_head_components, + *always_head_components, + ] return Html.create( Head.create(*head_components), Body.create( From e7a80000a7a3430beaf0f928b658ffa591c4e79f Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 25 Jun 2025 18:34:36 -0700 Subject: [PATCH 2/4] fix tests --- tests/units/compiler/test_compiler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/units/compiler/test_compiler.py b/tests/units/compiler/test_compiler.py index 74f62c4297e..f83560c3e28 100644 --- a/tests/units/compiler/test_compiler.py +++ b/tests/units/compiler/test_compiler.py @@ -387,9 +387,9 @@ def test_create_document_root(): html_custom_attrs={"project": "reflex"}, ) assert isinstance(root, utils.Html) - assert len(root.children[0].children) == 4 + assert len(root.children[0].children) == 6 names = [c.tag for c in root.children[0].children] - assert names == ["Scripts", "Scripts", "Meta", "Links"] + assert names == ["Scripts", "Scripts", "meta", "meta", "Meta", "Links"] lang = root.lang # pyright: ignore [reportAttributeAccessIssue] assert isinstance(lang, LiteralStringVar) assert lang.equals(Var.create("rx")) From 320a0804edf032d91a1a68dc4eb3d566d44f40d2 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 25 Jun 2025 20:19:28 -0700 Subject: [PATCH 3/4] Create actual test cases for this feature Because if you don't test, then you assuredly have bugs or will. --- tests/units/compiler/test_compiler.py | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/units/compiler/test_compiler.py b/tests/units/compiler/test_compiler.py index f83560c3e28..4e4a618c4b8 100644 --- a/tests/units/compiler/test_compiler.py +++ b/tests/units/compiler/test_compiler.py @@ -376,6 +376,8 @@ def test_create_document_root(): assert isinstance(root.children[0].children[2], document.Meta) assert isinstance(root.children[0].children[3], document.Links) + +def test_create_document_root_with_scripts(): # Test with components. comps = [ utils.Scripts.create(src="foo.js"), @@ -395,3 +397,37 @@ def test_create_document_root(): assert lang.equals(Var.create("rx")) assert isinstance(root.custom_attrs, dict) assert root.custom_attrs == {"project": "reflex"} + + +def test_create_document_root_with_meta_char_set(): + # Test with components. + comps = [ + utils.Meta.create(char_set="cp1252"), + ] + root = utils.create_document_root( + head_components=comps, + ) + assert isinstance(root, utils.Html) + assert len(root.children[0].children) == 4 + names = [c.tag for c in root.children[0].children] + assert names == ["meta", "meta", "Meta", "Links"] + assert str(root.children[0].children[0].char_set) == '"cp1252"' # pyright: ignore [reportAttributeAccessIssue] + + +def test_create_document_root_with_meta_viewport(): + # Test with components. + comps = [ + utils.Meta.create(http_equiv="refresh", content="5"), + utils.Meta.create(name="viewport", content="foo"), + ] + root = utils.create_document_root( + head_components=comps, + ) + assert isinstance(root, utils.Html) + assert len(root.children[0].children) == 5 + names = [c.tag for c in root.children[0].children] + assert names == ["meta", "meta", "meta", "Meta", "Links"] + assert str(root.children[0].children[0].http_equiv) == '"refresh"' # pyright: ignore [reportAttributeAccessIssue] + assert str(root.children[0].children[1].name) == '"viewport"' # pyright: ignore [reportAttributeAccessIssue] + assert str(root.children[0].children[1].content) == '"foo"' # pyright: ignore [reportAttributeAccessIssue] + assert str(root.children[0].children[2].char_set) == '"utf-8"' # pyright: ignore [reportAttributeAccessIssue] From da13ad66780741910cbb1a56e25e76afb6438e8c Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 25 Jun 2025 20:19:50 -0700 Subject: [PATCH 4/4] handle the fact that props are Var --- reflex/compiler/utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py index 4061406eacc..6bbb0a2c79d 100644 --- a/reflex/compiler/utils.py +++ b/reflex/compiler/utils.py @@ -363,9 +363,12 @@ def create_document_root( for component in head_components or []: if isinstance(component, Meta): - if component.char_set: # pyright: ignore[reportAttributeAccessIssue] + if component.char_set is not None: # pyright: ignore[reportAttributeAccessIssue] existing_meta_types.add("char_set") - if component.name == "viewport": # pyright: ignore[reportAttributeAccessIssue] + if ( + (name := component.name) is not None # pyright: ignore[reportAttributeAccessIssue] + and name.equals(Var.create("viewport")) + ): existing_meta_types.add("viewport") # Always include the framework meta and link tags.