Skip to content

Commit

Permalink
perf: memoize filetree computation (jackyzha0#490)
Browse files Browse the repository at this point in the history
* perf: memoize filetree computation

* format

* var -> let
  • Loading branch information
jackyzha0 authored Sep 20, 2023
1 parent 16d33fb commit 4845223
Showing 1 changed file with 44 additions and 34 deletions.
78 changes: 44 additions & 34 deletions quartz/components/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import explorerStyle from "./styles/explorer.scss"
// @ts-ignore
import script from "./scripts/explorer.inline"
import { ExplorerNode, FileNode, Options } from "./ExplorerNode"
import { QuartzPluginData } from "../plugins/vfile"

// Options interface defined in `ExplorerNode` to avoid circular dependency
const defaultOptions = {
Expand All @@ -27,49 +28,58 @@ const defaultOptions = {
} satisfies Options

export default ((userOpts?: Partial<Options>) => {
function Explorer({ allFiles, displayClass, fileData }: QuartzComponentProps) {
// Parse config
const opts: Options = { ...defaultOptions, ...userOpts }
// Parse config
const opts: Options = { ...defaultOptions, ...userOpts }

// Construct tree from allFiles
const fileTree = new FileNode("")
allFiles.forEach((file) => fileTree.add(file, 1))
// memoized
let fileTree: FileNode
let jsonTree: string

/**
* Keys of this object must match corresponding function name of `FileNode`,
* while values must be the argument that will be passed to the function.
*
* e.g. entry for FileNode.sort: `sort: opts.sortFn` (value is sort function from options)
*/
const functions = {
map: opts.mapFn,
sort: opts.sortFn,
filter: opts.filterFn,
}
function constructFileTree(allFiles: QuartzPluginData[]) {
if (!fileTree) {
// Construct tree from allFiles
fileTree = new FileNode("")
allFiles.forEach((file) => fileTree.add(file, 1))

/**
* Keys of this object must match corresponding function name of `FileNode`,
* while values must be the argument that will be passed to the function.
*
* e.g. entry for FileNode.sort: `sort: opts.sortFn` (value is sort function from options)
*/
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) {
// 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)
// Execute all functions (sort, filter, map) that were provided (if none were provided, only default "sort" is applied)
if (opts.order) {
// 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])
// @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")
// 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])
const jsonTree = JSON.stringify(folders)
// Stringify to pass json tree as data attribute ([data-tree])
jsonTree = JSON.stringify(folders)
}
}

function Explorer({ allFiles, displayClass, fileData }: QuartzComponentProps) {
constructFileTree(allFiles)
return (
<div class={`explorer ${displayClass}`}>
<button
Expand Down

0 comments on commit 4845223

Please sign in to comment.