compiler.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. """Compiler variables."""
  2. import enum
  3. import os
  4. from enum import Enum
  5. from types import SimpleNamespace
  6. from reflex.base import Base
  7. from reflex.constants import Dirs, Env
  8. from reflex.utils.imports import ImportVar
  9. # The prefix used to create setters for state vars.
  10. SETTER_PREFIX = "set_"
  11. # The file used to specify no compilation.
  12. NOCOMPILE_FILE = "nocompile"
  13. # The env var to toggle minification of states.
  14. ENV_MINIFY_STATES = "REFLEX_MINIFY_STATES"
  15. class Ext(SimpleNamespace):
  16. """Extension used in Reflex."""
  17. # The extension for JS files.
  18. JS = ".js"
  19. # The extension for python files.
  20. PY = ".py"
  21. # The extension for css files.
  22. CSS = ".css"
  23. # The extension for zip files.
  24. ZIP = ".zip"
  25. # The extension for executable files on Windows.
  26. EXE = ".exe"
  27. def minify_states() -> bool:
  28. """Whether to minify states.
  29. Returns:
  30. True if states should be minified.
  31. """
  32. from reflex.config import environment
  33. env = environment.REFLEX_MINIFY_STATES.get()
  34. if env is not None:
  35. return env
  36. # minify states in prod by default
  37. return environment.REFLEX_ENV_MODE.get() == Env.PROD
  38. class CompileVars(SimpleNamespace):
  39. """The variables used during compilation."""
  40. # The expected variable name where the rx.App is stored.
  41. APP = "app"
  42. # The expected variable name where the API object is stored for deployment.
  43. API = "api"
  44. # The name of the router variable.
  45. ROUTER = "router"
  46. # The name of the socket variable.
  47. SOCKET = "socket"
  48. # The name of the variable to hold API results.
  49. RESULT = "result"
  50. # The name of the final variable.
  51. FINAL = "final"
  52. # The name of the process variable.
  53. PROCESSING = "processing"
  54. # The name of the state variable.
  55. STATE = "state"
  56. # The name of the events variable.
  57. EVENTS = "events"
  58. # The name of the initial hydrate event.
  59. HYDRATE = "hydrate"
  60. # The name of the is_hydrated variable.
  61. IS_HYDRATED = "is_hydrated"
  62. # The name of the function to add events to the queue.
  63. ADD_EVENTS = "addEvents"
  64. # The name of the var storing any connection error.
  65. CONNECT_ERROR = "connectErrors"
  66. # The name of the function for converting a dict to an event.
  67. TO_EVENT = "Event"
  68. @classmethod
  69. def MINIFY_STATES(cls) -> bool:
  70. """Whether to minify states.
  71. Returns:
  72. True if states should be minified.
  73. """
  74. return minify_states()
  75. class PageNames(SimpleNamespace):
  76. """The name of basic pages deployed in NextJS."""
  77. # The name of the index page.
  78. INDEX_ROUTE = "index"
  79. # The name of the app root page.
  80. APP_ROOT = "_app"
  81. # The root stylesheet filename.
  82. STYLESHEET_ROOT = "styles"
  83. # The name of the document root page.
  84. DOCUMENT_ROOT = "_document"
  85. # The name of the theme page.
  86. THEME = "theme"
  87. # The module containing components.
  88. COMPONENTS = "components"
  89. # The module containing shared stateful components
  90. STATEFUL_COMPONENTS = "stateful_components"
  91. class ComponentName(Enum):
  92. """Component names."""
  93. BACKEND = "Backend"
  94. FRONTEND = "Frontend"
  95. def zip(self):
  96. """Give the zip filename for the component.
  97. Returns:
  98. The lower-case filename with zip extension.
  99. """
  100. return self.value.lower() + Ext.ZIP
  101. class Imports(SimpleNamespace):
  102. """Common sets of import vars."""
  103. EVENTS = {
  104. "react": [ImportVar(tag="useContext")],
  105. f"$/{Dirs.CONTEXTS_PATH}": [ImportVar(tag="EventLoopContext")],
  106. f"$/{Dirs.STATE_PATH}": [ImportVar(tag=CompileVars.TO_EVENT)],
  107. }
  108. class Hooks(SimpleNamespace):
  109. """Common sets of hook declarations."""
  110. EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
  111. AUTOFOCUS = """
  112. // Set focus to the specified element.
  113. const focusRef = useRef(null)
  114. useEffect(() => {
  115. if (focusRef.current) {
  116. focusRef.current.focus();
  117. }
  118. })"""
  119. class MemoizationDisposition(enum.Enum):
  120. """The conditions under which a component should be memoized."""
  121. # If the component uses state or events, it should be memoized.
  122. STATEFUL = "stateful"
  123. ALWAYS = "always"
  124. NEVER = "never"
  125. class MemoizationMode(Base):
  126. """The mode for memoizing a Component."""
  127. # The conditions under which the component should be memoized.
  128. disposition: MemoizationDisposition = MemoizationDisposition.STATEFUL
  129. # Whether children of this component should be memoized first.
  130. recursive: bool = True
  131. class SpecialAttributes(enum.Enum):
  132. """Special attributes for components.
  133. These are placed in custom_attrs and rendered as-is rather than converting
  134. to a style prop.
  135. """
  136. DATA_UNDERSCORE = "data_"
  137. DATA_DASH = "data-"
  138. ARIA_UNDERSCORE = "aria_"
  139. ARIA_DASH = "aria-"
  140. @classmethod
  141. def is_special(cls, attr: str) -> bool:
  142. """Check if the attribute is special.
  143. Args:
  144. attr: the attribute to check
  145. Returns:
  146. True if the attribute is special.
  147. """
  148. return any(attr.startswith(value.value) for value in cls)