UNPKG

bundle-wizard

Version:

Analyze the JavaScript loaded by a website

247 lines (224 loc) 7.35 kB
import 'sanitize.css' import './index.scss' import React, { useEffect } from 'react' import ReactDOM from 'react-dom' import { Flipper } from 'react-flip-toolkit' import Treemap from './Treemap' import Breadcrumbs from './Breadcrumbs' import Summary from './Summary' import Tooltip from './Tooltip' import Code from './Code' import { findMostLikelyPath, usePrevious, filterData } from './utils' import ControlPanel from './ControlPanel' import throttle from 'lodash.throttle' const jsonOptions = { headers: { 'Content-Type': 'application/json' } } // TODO: figure out why this isn't working with use effect hooks + state let originalFileMapping = {} const findBranch = (id, data) => { let cachedBranch const inner = branch => { if (cachedBranch) return if (branch.id === id) cachedBranch = branch if (branch.children) branch.children.forEach(inner) } inner(data) return cachedBranch } const Dashboard = () => { const [data, _setData] = React.useState(null) const [hovered, setHovered] = React.useState(null) const [showSummary, setShowSummary] = React.useState(false) const [showAllChildren, setShowAllChildren] = React.useState(false) const [showCoverage, setShowCoverage] = React.useState(true) const [topLevelData, setTopLevelData] = React.useState({}) const [searchStr, _setSearchStr] = React.useState( new URLSearchParams(window.location.search).get('search') || '' ) const setSearchStr = str => { const queryParams = new URLSearchParams(window.location.search) queryParams.set('search', window.encodeURIComponent(str)) history.replaceState(null, null, '?' + queryParams.toString()) _setSearchStr(str) } const [ showScriptsWithoutSourcemaps, setShowScriptsWithoutSourcemaps ] = React.useState(true) const [code, setCode] = React.useState(false) const isTopLevel = data && data.name === 'topLevel' const toggleScriptsWithoutSourcemaps = () => { setShowScriptsWithoutSourcemaps(!showScriptsWithoutSourcemaps) } const setData = React.useCallback( data => { _setData(data) setHovered(null) }, [_setData, setHovered] ) useEffect(() => { fetch('./treeData.json', jsonOptions).then(response => { response.json().then(data => { // order is important here for setGraphRoot setTopLevelData(data) setData(data) }) }) }, []) useEffect(() => { fetch('./originalFileMapping.json', jsonOptions).then(response => { response .json() .then(data => { // TODO: figure out why setCodeIfNecessary func doesnt work properly originalFileMapping = data }) .catch(() => { console.error('couldnt load originalFileMapping.json!') }) }) }, []) const setGraphRoot = React.useCallback( id => { setData(findBranch(id, topLevelData)) }, [setData, topLevelData] ) const previousData = usePrevious(data) useEffect( function setCodeIfNecessary() { if ( data && data !== previousData && (!data.children || data.children.length === 0) ) { // const isJSON = data.id.match(/json$/) // if (isJSON) { // fetch(`./originalFiles/${data.name.split('/').slice(-1)[0]}`) // .then(response => response.text()) // .then(text => { // if (text) setCode({ text, name: data.name, data }) // }) // .catch(e => { // console.log(e) // setCode(null) // }) // return // } const simplifiedName = data.name.replace('.js', '') const fileKeys = Object.keys(originalFileMapping) if (!fileKeys) { return console.error('unable to access original file data') } else { const matchingKeys = fileKeys.filter( key => key.indexOf(simplifiedName) !== -1 ) const mostLikelyPath = findMostLikelyPath(matchingKeys, data.id) const id = originalFileMapping[mostLikelyPath] fetch(`./originalFiles/${id}.json`) .then(response => response.json()) .then(text => { if (text) setCode({ text, name: mostLikelyPath, data }) }) .catch(e => { console.log(e) setCode(null) }) } } }, [data, code, previousData] ) if (!data) return <div className="loading">loading...</div> const showingCode = Boolean(code) return ( <Flipper flipKey={showingCode}> <div className={!showCoverage && 'hide-coverage'}> <Tooltip hovered={hovered} /> <nav className="nav"> <div className="logo"> Analysis of <b>{(topLevelData || {}).url}</b> </div> <ul> <li className={!showSummary && 'active'}> <a href="#" onClick={e => { e.preventDefault() e.stopPropagation() setShowSummary(false) }} > Treemap </a> </li> <li className={showSummary && 'active'}> <a href="#" onClick={e => { e.preventDefault() e.stopPropagation() setShowSummary(true) }} > Summary </a> </li> </ul> </nav> {showSummary ? ( <Summary data={topLevelData} setGraphRoot={(...args) => { setShowSummary(false) setGraphRoot(...args) }} /> ) : ( <> <Breadcrumbs data={data} isTopLevel={isTopLevel} setGraphRoot={(...args) => { setCode(null) setGraphRoot(...args) }} hovered={hovered} toggleScriptsWithoutSourcemaps={toggleScriptsWithoutSourcemaps} showScriptsWithoutSourcemaps={showScriptsWithoutSourcemaps} /> <Treemap data={filterData(data, searchStr)} setGraphRoot={setGraphRoot} setHovered={setHovered} showScriptsWithoutSourcemaps={showScriptsWithoutSourcemaps} showingCode={showingCode} showAllChildren={showAllChildren} /> {showingCode && ( <Code {...code} setHovered={setHovered} id={data.id} /> )} {!showingCode && ( <ControlPanel toggleScriptsWithoutSourcemaps={toggleScriptsWithoutSourcemaps} showScriptsWithoutSourcemaps={showScriptsWithoutSourcemaps} setShowCoverage={setShowCoverage} showCoverage={showCoverage} isTopLevel={isTopLevel} showAllChildren={showAllChildren} setShowAllChildren={setShowAllChildren} setSearchStr={setSearchStr} searchStr={searchStr} /> )} </> )} </div> </Flipper> ) } ReactDOM.render(<Dashboard />, document.getElementById('container'))