compiler.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """Compiler variables."""
  2. import enum
  3. from enum import Enum
  4. from types import SimpleNamespace
  5. from reflex.base import Base
  6. from reflex.constants import Dirs
  7. from reflex.utils.imports import ImportVar
  8. # The prefix used to create setters for state vars.
  9. SETTER_PREFIX = "set_"
  10. # The file used to specify no compilation.
  11. NOCOMPILE_FILE = "nocompile"
  12. class Ext(SimpleNamespace):
  13. """Extension used in Reflex."""
  14. # The extension for JS files.
  15. JS = ".js"
  16. # The extension for python files.
  17. PY = ".py"
  18. # The extension for css files.
  19. CSS = ".css"
  20. # The extension for zip files.
  21. ZIP = ".zip"
  22. # The extension for executable files on Windows.
  23. EXE = ".exe"
  24. class CompileVars(SimpleNamespace):
  25. """The variables used during compilation."""
  26. # The expected variable name where the rx.App is stored.
  27. APP = "app"
  28. # The expected variable name where the API object is stored for deployment.
  29. API = "api"
  30. # The name of the router variable.
  31. ROUTER = "router"
  32. # The name of the socket variable.
  33. SOCKET = "socket"
  34. # The name of the variable to hold API results.
  35. RESULT = "result"
  36. # The name of the final variable.
  37. FINAL = "final"
  38. # The name of the process variable.
  39. PROCESSING = "processing"
  40. # The name of the state variable.
  41. STATE = "state"
  42. # The name of the events variable.
  43. EVENTS = "events"
  44. # The name of the initial hydrate event.
  45. HYDRATE = "hydrate"
  46. # The name of the is_hydrated variable.
  47. IS_HYDRATED = "is_hydrated"
  48. # The name of the function to add events to the queue.
  49. ADD_EVENTS = "addEvents"
  50. # The name of the var storing any connection error.
  51. CONNECT_ERROR = "connectErrors"
  52. # The name of the function for converting a dict to an event.
  53. TO_EVENT = "Event"
  54. # The name of the internal on_load event.
  55. ON_LOAD_INTERNAL = "reflex___state____on_load_internal_state.on_load_internal"
  56. # The name of the internal event to update generic state vars.
  57. UPDATE_VARS_INTERNAL = (
  58. "reflex___state____update_vars_internal_state.update_vars_internal"
  59. )
  60. # The name of the frontend event exception state
  61. FRONTEND_EXCEPTION_STATE = "reflex___state____frontend_event_exception_state"
  62. # The full name of the frontend exception state
  63. FRONTEND_EXCEPTION_STATE_FULL = (
  64. f"reflex___state____state.{FRONTEND_EXCEPTION_STATE}"
  65. )
  66. class PageNames(SimpleNamespace):
  67. """The name of basic pages deployed in NextJS."""
  68. # The name of the index page.
  69. INDEX_ROUTE = "index"
  70. # The name of the app root page.
  71. APP_ROOT = "_app"
  72. # The root stylesheet filename.
  73. STYLESHEET_ROOT = "styles"
  74. # The name of the document root page.
  75. DOCUMENT_ROOT = "_document"
  76. # The name of the theme page.
  77. THEME = "theme"
  78. # The module containing components.
  79. COMPONENTS = "components"
  80. # The module containing shared stateful components
  81. STATEFUL_COMPONENTS = "stateful_components"
  82. class ComponentName(Enum):
  83. """Component names."""
  84. BACKEND = "Backend"
  85. FRONTEND = "Frontend"
  86. def zip(self):
  87. """Give the zip filename for the component.
  88. Returns:
  89. The lower-case filename with zip extension.
  90. """
  91. return self.value.lower() + Ext.ZIP
  92. class Imports(SimpleNamespace):
  93. """Common sets of import vars."""
  94. EVENTS = {
  95. "react": [ImportVar(tag="useContext")],
  96. f"/{Dirs.CONTEXTS_PATH}": [ImportVar(tag="EventLoopContext")],
  97. f"/{Dirs.STATE_PATH}": [ImportVar(tag=CompileVars.TO_EVENT)],
  98. }
  99. class Hooks(SimpleNamespace):
  100. """Common sets of hook declarations."""
  101. EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
  102. AUTOFOCUS = """
  103. // Set focus to the specified element.
  104. const focusRef = useRef(null)
  105. useEffect(() => {
  106. if (focusRef.current) {
  107. focusRef.current.focus();
  108. }
  109. })"""
  110. FRONTEND_ERRORS = f"""
  111. const logFrontendError = (error, info) => {{
  112. if (process.env.NODE_ENV === "production") {{
  113. addEvents([Event("{CompileVars.FRONTEND_EXCEPTION_STATE_FULL}.handle_frontend_exception", {{
  114. stack: error.stack,
  115. }})])
  116. }}
  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