123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- import {Fragment} from 'react';
- import styled from '@emotion/styled';
- import Card from 'sentry/components/card';
- import * as Layout from 'sentry/components/layouts/thirds';
- import ExternalLink from 'sentry/components/links/externalLink';
- import PanelTable from 'sentry/components/panels/panelTable';
- import {SegmentedControl} from 'sentry/components/segmentedControl';
- import {t} from 'sentry/locale';
- import {space} from 'sentry/styles/space';
- import {formatBytesBase2} from 'sentry/utils';
- import useRouter from 'sentry/utils/useRouter';
- import {bundleStats as stats} from 'sentry/views/bundleAnalyzer';
- import {CardSection} from 'sentry/views/performance/transactionSummary/transactionVitals/styles';
- enum BundleType {
- ASSETS = 'assets',
- IN_APP = 'in_app',
- PACKAGES = 'packages',
- OTHER = 'other',
- }
- const BUNDLE_TYPES = [
- {
- key: BundleType.ASSETS,
- label: t('Assets'),
- },
- {
- key: BundleType.IN_APP,
- label: t('In App'),
- },
- {
- key: BundleType.PACKAGES,
- label: t('Packages'),
- },
- // {
- // key: BundleType.OTHER,
- // label: t('Other'),
- // },
- ];
- const chunks = stats.chunks;
- const assets = stats.assets.sort((a, b) => b.size - a.size);
- const modules = stats.modules;
- const inAppModules = modules
- .filter(
- m =>
- m.moduleType.startsWith('javascript') &&
- m.name.startsWith('./app') &&
- !m.name.endsWith('namespace object')
- )
- .sort((a, b) => b.size - a.size);
- const packageModules = modules
- .filter(m => m.name.startsWith('../node_modules'))
- .sort((a, b) => b.size - a.size);
- export default function BundleDetails() {
- const router = useRouter();
- const bundleType = router.location.query.bundleType ?? BundleType.ASSETS;
- function handleBundleAnalysisSelection(type: BundleType) {
- router.replace({
- ...router.location,
- query: {
- ...router.location.query,
- bundleType: type,
- },
- });
- }
- function getPanelItems() {
- switch (bundleType) {
- case BundleType.ASSETS: {
- return assets.map(asset => (
- <Fragment key={`asset-${asset.name}`}>
- <div>{asset.name}</div>
- <div>{formatBytesBase2(asset.size)}</div>
- </Fragment>
- ));
- }
- case BundleType.IN_APP: {
- return inAppModules.map(module => (
- <Fragment
- key={`module-${module.name}-${
- module?.chunks[0] ? module?.chunks[0] : '_sentry_no_chunk'
- }`}
- >
- <ExternalLink
- href={`https://github.com/getsentry/sentry/blob/master/static/${module.name.replace(
- './',
- ''
- )}`}
- >
- {module.name}
- </ExternalLink>
- <div>{formatBytesBase2(module.size)}</div>
- </Fragment>
- ));
- }
- case BundleType.PACKAGES: {
- return packageModules.map(module => {
- const npmPackageName = getNpmPackageFromNodeModules(module.name);
- return (
- <Fragment
- key={`module-${module.name}-${
- module?.chunks[0] ? module?.chunks[0] : '_sentry_no_chunk'
- }`}
- >
- <ExternalLink href={`https://www.npmjs.com/package/${npmPackageName}`}>
- {module.name.replace('../node_modules/', '')}
- </ExternalLink>
- <div>{formatBytesBase2(module.size)}</div>
- </Fragment>
- );
- });
- }
- default: {
- throw new Error('Invalid bundle type');
- }
- }
- }
- const entrypoints = chunks.filter(c => c.entry);
- return (
- <Layout.Body>
- <Layout.Main fullWidth>
- <CardWrapper>
- {entrypoints.map(entrypoint => (
- <StyledCard key={entrypoint.id}>
- <CardSection>
- <div>{entrypoint.id}</div>
- <StatNumber>{formatBytesBase2(entrypoint.size)}</StatNumber>
- </CardSection>
- </StyledCard>
- ))}
- </CardWrapper>
- <SegmentedControlWrapper key="segmented-control">
- <SegmentedControl
- aria-label={t('Bundle Analysis Type')}
- size="sm"
- value={bundleType}
- onChange={key => handleBundleAnalysisSelection(key as BundleType)}
- >
- {BUNDLE_TYPES.map(({key, label}) => (
- <SegmentedControl.Item key={key} textValue={label}>
- {label}
- </SegmentedControl.Item>
- ))}
- </SegmentedControl>
- </SegmentedControlWrapper>
- <PanelTable headers={[t('Name'), t('Size')]}>{getPanelItems()}</PanelTable>
- </Layout.Main>
- </Layout.Body>
- );
- }
- function getNpmPackageFromNodeModules(name: string): string {
- const path = name.replace('../node_modules/', '');
- const pathComponents = path.split('/');
- for (let i = pathComponents.length - 1; i >= 0; i--) {
- if (pathComponents[i] === 'node_modules') {
- const maybePackageName = pathComponents[i + 1];
- if (maybePackageName.startsWith('@')) {
- return maybePackageName + pathComponents[i + 2];
- }
- return maybePackageName;
- }
- }
- if (pathComponents[0].startsWith('@')) {
- return pathComponents[0] + pathComponents[1];
- }
- return pathComponents[0];
- }
- const StyledCard = styled(Card)`
- margin-right: ${space(1)};
- `;
- const SegmentedControlWrapper = styled('div')`
- padding-bottom: ${space(2)};
- `;
- export const StatNumber = styled('div')`
- font-size: 32px;
- `;
- export const CardWrapper = styled('div')`
- display: flex;
- `;
|