소스 검색

Website: Faster search page (#4731)

This PR speeds up the documentation search page in the following ways: 

- Client, who is responsible* for running Fuse.js fuzzy search, needs to
send back the indices only, not the entire content.
- This saves unnecessary uplink bandwidth from client to server.
Messages went from 37KB to 0.5KB.
- When the page is narrow, an indicator which means the page is on
mobile clients, return 25 (a quarter of the original) results
- According to Lighthouse, the benchmark for page speed, mobile browsers
are a quarter as fast as desktop browsers, so I chose the value from
there.
- Let Fuse.js do the limiting of results, instead of us `.slice`
- Theoreticlly slightly faster, since Fuse.js doesn't have to sort the
entire list and provide a big return object.

As far as what I can tell, the search results before and after this PR
are exactly the same.

*tried to find a Python substitute but came up dry...

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Evan Chan 6 일 전
부모
커밋
863c858a68
1개의 변경된 파일15개의 추가작업 그리고 7개의 파일을 삭제
  1. 15 7
      website/search.py

+ 15 - 7
website/search.py

@@ -1,6 +1,7 @@
 from nicegui import __version__, background_tasks, events, ui
 
 from .documentation import CustomRestructuredText as custom_restructured_text
+from .documentation.search import search_index
 
 
 class Search:
@@ -55,19 +56,26 @@ class Search:
     def handle_input(self, e: events.ValueChangeEventArguments) -> None:
         async def handle_input() -> None:
             with self.results:
-                results = await ui.run_javascript(f'return window.fuse.search("{e.value}").slice(0, 100)', timeout=6)
+                indices = await ui.run_javascript(f'''
+                    const isMobile = window.innerWidth < 610;
+                    const limit = isMobile ? 25 : 100;
+                    return window.fuse.search("{e.value}", {{ limit }}).map(result => result.refIndex);
+                ''', timeout=6)
                 self.results.clear()
                 with ui.list().props('bordered separator'):
-                    for result in results:
-                        if not result['item']['content']:
+                    for index in indices:
+                        if not 0 <= index < len(search_index):
+                            continue
+                        result_item = search_index[index]
+                        if not result_item['content']:
                             continue
                         with ui.item().props('clickable'):
                             with ui.item_section():
-                                with ui.link(target=result['item']['url']):
-                                    ui.item_label(result['item']['title'])
+                                with ui.link(target=result_item['url']):
+                                    ui.item_label(result_item['title'])
                                     with ui.item_label().props('caption'):
-                                        intro = result['item']['content'].split(':param')[0]
-                                        if result['item']['format'] == 'md':
+                                        intro = result_item['content'].split(':param')[0]
+                                        if result_item['format'] == 'md':
                                             element = ui.markdown(intro)
                                         else:
                                             element = custom_restructured_text(intro)