perf: memoize filetree computation (#490)
* perf: memoize filetree computation * format * var -> let
This commit is contained in:
		@@ -4,6 +4,7 @@ import explorerStyle from "./styles/explorer.scss"
 | 
				
			|||||||
// @ts-ignore
 | 
					// @ts-ignore
 | 
				
			||||||
import script from "./scripts/explorer.inline"
 | 
					import script from "./scripts/explorer.inline"
 | 
				
			||||||
import { ExplorerNode, FileNode, Options } from "./ExplorerNode"
 | 
					import { ExplorerNode, FileNode, Options } from "./ExplorerNode"
 | 
				
			||||||
 | 
					import { QuartzPluginData } from "../plugins/vfile"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Options interface defined in `ExplorerNode` to avoid circular dependency
 | 
					// Options interface defined in `ExplorerNode` to avoid circular dependency
 | 
				
			||||||
const defaultOptions = {
 | 
					const defaultOptions = {
 | 
				
			||||||
@@ -27,49 +28,58 @@ const defaultOptions = {
 | 
				
			|||||||
} satisfies Options
 | 
					} satisfies Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ((userOpts?: Partial<Options>) => {
 | 
					export default ((userOpts?: Partial<Options>) => {
 | 
				
			||||||
  function Explorer({ allFiles, displayClass, fileData }: QuartzComponentProps) {
 | 
					  // Parse config
 | 
				
			||||||
    // Parse config
 | 
					  const opts: Options = { ...defaultOptions, ...userOpts }
 | 
				
			||||||
    const opts: Options = { ...defaultOptions, ...userOpts }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Construct tree from allFiles
 | 
					  // memoized
 | 
				
			||||||
    const fileTree = new FileNode("")
 | 
					  let fileTree: FileNode
 | 
				
			||||||
    allFiles.forEach((file) => fileTree.add(file, 1))
 | 
					  let jsonTree: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					  function constructFileTree(allFiles: QuartzPluginData[]) {
 | 
				
			||||||
     * Keys of this object must match corresponding function name of `FileNode`,
 | 
					    if (!fileTree) {
 | 
				
			||||||
     * while values must be the argument that will be passed to the function.
 | 
					      // Construct tree from allFiles
 | 
				
			||||||
     *
 | 
					      fileTree = new FileNode("")
 | 
				
			||||||
     * e.g. entry for FileNode.sort: `sort: opts.sortFn` (value is sort function from options)
 | 
					      allFiles.forEach((file) => fileTree.add(file, 1))
 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    const functions = {
 | 
					 | 
				
			||||||
      map: opts.mapFn,
 | 
					 | 
				
			||||||
      sort: opts.sortFn,
 | 
					 | 
				
			||||||
      filter: opts.filterFn,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Execute all functions (sort, filter, map) that were provided (if none were provided, only default "sort" is applied)
 | 
					      /**
 | 
				
			||||||
    if (opts.order) {
 | 
					       * Keys of this object must match corresponding function name of `FileNode`,
 | 
				
			||||||
      // Order is important, use loop with index instead of order.map()
 | 
					       * while values must be the argument that will be passed to the function.
 | 
				
			||||||
      for (let i = 0; i < opts.order.length; i++) {
 | 
					       *
 | 
				
			||||||
        const functionName = opts.order[i]
 | 
					       * e.g. entry for FileNode.sort: `sort: opts.sortFn` (value is sort function from options)
 | 
				
			||||||
        if (functions[functionName]) {
 | 
					       */
 | 
				
			||||||
          // for every entry in order, call matching function in FileNode and pass matching argument
 | 
					      const functions = {
 | 
				
			||||||
          // e.g. i = 0; functionName = "filter"
 | 
					        map: opts.mapFn,
 | 
				
			||||||
          // converted to: (if opts.filterFn) => fileTree.filter(opts.filterFn)
 | 
					        sort: opts.sortFn,
 | 
				
			||||||
 | 
					        filter: opts.filterFn,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // @ts-ignore
 | 
					      // Execute all functions (sort, filter, map) that were provided (if none were provided, only default "sort" is applied)
 | 
				
			||||||
          // typescript cant statically check these dynamic references, so manually make sure reference is valid and ignore warning
 | 
					      if (opts.order) {
 | 
				
			||||||
          fileTree[functionName].call(fileTree, functions[functionName])
 | 
					        // Order is important, use loop with index instead of order.map()
 | 
				
			||||||
 | 
					        for (let i = 0; i < opts.order.length; i++) {
 | 
				
			||||||
 | 
					          const functionName = opts.order[i]
 | 
				
			||||||
 | 
					          if (functions[functionName]) {
 | 
				
			||||||
 | 
					            // for every entry in order, call matching function in FileNode and pass matching argument
 | 
				
			||||||
 | 
					            // e.g. i = 0; functionName = "filter"
 | 
				
			||||||
 | 
					            // converted to: (if opts.filterFn) => fileTree.filter(opts.filterFn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // @ts-ignore
 | 
				
			||||||
 | 
					            // typescript cant statically check these dynamic references, so manually make sure reference is valid and ignore warning
 | 
				
			||||||
 | 
					            fileTree[functionName].call(fileTree, functions[functionName])
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Get all folders of tree. Initialize with collapsed state
 | 
				
			||||||
 | 
					      const folders = fileTree.getFolderPaths(opts.folderDefaultState === "collapsed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Stringify to pass json tree as data attribute ([data-tree])
 | 
				
			||||||
 | 
					      jsonTree = JSON.stringify(folders)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get all folders of tree. Initialize with collapsed state
 | 
					  function Explorer({ allFiles, displayClass, fileData }: QuartzComponentProps) {
 | 
				
			||||||
    const folders = fileTree.getFolderPaths(opts.folderDefaultState === "collapsed")
 | 
					    constructFileTree(allFiles)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Stringify to pass json tree as data attribute ([data-tree])
 | 
					 | 
				
			||||||
    const jsonTree = JSON.stringify(folders)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div class={`explorer ${displayClass}`}>
 | 
					      <div class={`explorer ${displayClass}`}>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user