quick webpack 5 update
This commit is contained in:
Родитель
9f3b220c94
Коммит
cf943d45d7
|
@ -27,6 +27,7 @@ jobs:
|
|||
action: "upload"
|
||||
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
|
||||
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
|
||||
app_build_command: "npm run build"
|
||||
app_location: "/" # App source code path
|
||||
api_location: "api" # Api source code path - optional
|
||||
output_location: "/dist" # Built app content directory - optional
|
||||
|
|
|
@ -42,8 +42,4 @@ jspm_packages
|
|||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
/public/samples
|
||||
!/public/samples/sample1.msp.gz
|
||||
!/public/samples/sample2.msp.gz
|
||||
/dist
|
||||
/.vscode
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
113
package.json
113
package.json
|
@ -8,8 +8,8 @@
|
|||
"test": "mocha --opts mocha.opts && npm run test:fmt && npm run test:lint",
|
||||
"test:fmt": "prettier --list-different \"src/**/*.{tsx,ts}\" || echo \"Run npm run fmt to fix formatting on these files\"",
|
||||
"test:lint": "tslint --project tsconfig.json \"src/**/*.{ts,tsx}\"",
|
||||
"build": "webpack --config webpack.production.js",
|
||||
"start": "webpack-dev-server --open",
|
||||
"build": "tsc -p tsconfig.package.json && webpack --config webpack.production.js",
|
||||
"start": "webpack serve",
|
||||
"prepare": "tsc -p tsconfig.package.json"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -30,75 +30,76 @@
|
|||
},
|
||||
"homepage": "https://github.com/mixer/webpack-bundle-compare#readme",
|
||||
"dependencies": {
|
||||
"bfj": "^6.1.1",
|
||||
"js-base64": "^2.5.1",
|
||||
"bfj": "^7.0.2",
|
||||
"js-base64": "^3.6.0",
|
||||
"msgpack-lite": "^0.1.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mixer/retrieval": "^2.0.2",
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/cytoscape": "^3.4.3",
|
||||
"@types/filesize": "^4.1.0",
|
||||
"@types/fixed-data-table-2": "^0.8.3",
|
||||
"@types/js-base64": "^2.3.1",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/msgpack-lite": "^0.1.6",
|
||||
"@types/node": "^12.0.4",
|
||||
"@mixer/retrieval": "^2.0.3",
|
||||
"@types/chai": "^4.2.17",
|
||||
"@types/cytoscape": "^3.14.15",
|
||||
"@types/filesize": "^4.2.0",
|
||||
"@types/fixed-data-table-2": "^0.8.4",
|
||||
"@types/js-base64": "^3.0.0",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"@types/msgpack-lite": "^0.1.7",
|
||||
"@types/node": "^15.0.2",
|
||||
"@types/pako": "^1.0.1",
|
||||
"@types/react": "^16.8.19",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/react-redux": "^7.0.9",
|
||||
"@types/react-router-dom": "^4.3.3",
|
||||
"@types/react-tabs": "^2.3.1",
|
||||
"@types/react": "^17.0.5",
|
||||
"@types/react-dom": "^17.0.3",
|
||||
"@types/react-redux": "^7.1.16",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"@types/react-tabs": "^2.3.2",
|
||||
"@types/sigmajs": "^1.0.27",
|
||||
"@types/webpack": "^4.4.32",
|
||||
"chai": "^4.2.0",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"css-loader": "^2.1.1",
|
||||
"cytoscape": "^3.7.0",
|
||||
"cytoscape-dagre": "^2.2.2",
|
||||
"cytoscape-fcose": "^1.0.0",
|
||||
"dayjs": "^1.8.14",
|
||||
"filesize": "^4.1.2",
|
||||
"fixed-data-table-2": "^0.8.26",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"chai": "^4.3.4",
|
||||
"copy-webpack-plugin": "^8.1.1",
|
||||
"css-loader": "^5.2.4",
|
||||
"cytoscape": "^3.18.2",
|
||||
"cytoscape-dagre": "^2.3.2",
|
||||
"cytoscape-fcose": "^2.0.0",
|
||||
"dayjs": "^1.10.4",
|
||||
"filesize": "^6.3.0",
|
||||
"fixed-data-table-2": "^1.1.3",
|
||||
"flexboxgrid": "^6.3.1",
|
||||
"fs-extra": "^8.0.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mocha": "^6.1.4",
|
||||
"node-sass": "^4.12.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"mocha": "^8.4.0",
|
||||
"node-sass": "^5.0.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pako": "^1.0.10",
|
||||
"prettier": "^1.17.1",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-github-corner": "^2.3.0",
|
||||
"react-icons": "^3.7.0",
|
||||
"react-redux": "^7.0.3",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-tabs": "^3.0.0",
|
||||
"redux": "^4.0.1",
|
||||
"redux-devtools-extension": "^2.13.8",
|
||||
"redux-observable": "^1.1.0",
|
||||
"pako": "^2.0.3",
|
||||
"prettier": "^2.2.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-github-corner": "^2.5.0",
|
||||
"react-icons": "^4.2.0",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-tabs": "^3.2.2",
|
||||
"redux": "^4.1.0",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"redux-observable": "^1.2.0",
|
||||
"reselect": "^4.0.0",
|
||||
"rxjs": "^6.5.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"rxjs": "^6.0.0",
|
||||
"sass-loader": "^11.0.1",
|
||||
"sigma": "^1.2.1",
|
||||
"style-loader": "^0.23.1",
|
||||
"ts-loader": "^6.0.2",
|
||||
"ts-node": "^8.2.0",
|
||||
"tslint": "^5.17.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"ts-loader": "^9.1.2",
|
||||
"ts-node": "^9.1.1",
|
||||
"tslint": "^5.20.1",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typesafe-actions": "^4.4.0",
|
||||
"typescript": "^3.5.1",
|
||||
"webpack": "^4.32.2",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-server": "^3.4.1",
|
||||
"worker-loader": "^2.0.0"
|
||||
"typesafe-actions": "^5.1.0",
|
||||
"typescript": "^4.2.4",
|
||||
"webpack": "^5.36.2",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"arrowParens": "avoid",
|
||||
"tabWidth": 2
|
||||
}
|
||||
}
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -1,6 +1,6 @@
|
|||
# @mixer/webpack-bundle-compare
|
||||
|
||||
This is a tool that allows you to compare webpack bundle analysis files over time. Check it out [here](https://webpackbundlecomparison.z5.web.core.windows.net).
|
||||
This is a tool that allows you to compare webpack bundle analysis files over time. Check it out [here](https://happy-water-0887b0b1e.azurestaticapps.net).
|
||||
|
||||
![](./screenshot.png)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { connect } from 'react-redux';
|
|||
import { fetchBundlephobiaData } from '../redux/actions';
|
||||
import { getBundlephobiaData, IAppState } from '../redux/reducer';
|
||||
import { IBundlephobiaStats } from '../redux/services/bundlephobia-api';
|
||||
import * as styles from './bundlephobia-stats.component.scss';
|
||||
import styles from './bundlephobia-stats.component.scss';
|
||||
import { Errors } from './errors.component';
|
||||
import { SideEffectHint, TreeShakeHint } from './hints/hints.component';
|
||||
import { BasePanel } from './panels/base-panel.component';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import * as styles from './button.component.scss';
|
||||
import styles from './button.component.scss';
|
||||
import { classes } from './util';
|
||||
|
||||
type Props = React.DetailedHTMLProps<
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as filesize from 'filesize';
|
||||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import {
|
||||
compareNodeModules,
|
||||
getNodeModuleCount,
|
||||
|
@ -19,8 +19,8 @@ import { formatPercent } from './util';
|
|||
|
||||
export const DashboardChunkPage: React.FC<{
|
||||
chunk: number;
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
}> = ({ first, last, chunk }) => {
|
||||
const firstObj = first.chunks!.find(c => c.id === chunk);
|
||||
const lastSize = last.chunks!.find(c => c.id === chunk);
|
||||
|
|
|
@ -9,8 +9,8 @@ import {
|
|||
IoIosWarning,
|
||||
} from 'react-icons/io';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import { Stats } from 'webpack';
|
||||
import * as styles from './dashboard-header.component.scss';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import styles from './dashboard-header.component.scss';
|
||||
|
||||
const DashboardHeaderItem: React.FC<{ icon: IconType; href?: string | (() => void) }> = props => {
|
||||
const inner = (
|
||||
|
@ -34,8 +34,8 @@ const DashboardHeaderItem: React.FC<{ icon: IconType; href?: string | (() => voi
|
|||
};
|
||||
|
||||
export const DashboardBuildDate: React.FC<{
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
}> = ({ first, last }) => {
|
||||
const from = first.builtAt;
|
||||
const to = last.builtAt;
|
||||
|
@ -56,21 +56,21 @@ export const DashboardBuildDate: React.FC<{
|
|||
);
|
||||
};
|
||||
|
||||
export const DashboardWarningCount: React.FC<{ last: Stats.ToJsonOutput }> = ({ last }) => (
|
||||
export const DashboardWarningCount: React.FC<{ last: StatsCompilation }> = ({ last }) => (
|
||||
<DashboardHeaderItem
|
||||
icon={IoIosWarning}
|
||||
href={last.warnings.length ? '/dashboard/output' : undefined}
|
||||
href={last.warnings?.length ? '/dashboard/output' : undefined}
|
||||
>
|
||||
{last.warnings.length} Warnings
|
||||
{last.warnings?.length ?? 0} Warnings
|
||||
</DashboardHeaderItem>
|
||||
);
|
||||
|
||||
export const DashboardErrorCount: React.FC<{ last: Stats.ToJsonOutput }> = ({ last }) => (
|
||||
export const DashboardErrorCount: React.FC<{ last: StatsCompilation }> = ({ last }) => (
|
||||
<DashboardHeaderItem
|
||||
icon={IoIosCloseCircleOutline}
|
||||
href={last.errors.length ? '/dashboard/output' : undefined}
|
||||
href={last.errors?.length ? '/dashboard/output' : undefined}
|
||||
>
|
||||
{last.errors.length} Errors
|
||||
{last.errors?.length ?? 0} Errors
|
||||
</DashboardHeaderItem>
|
||||
);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import { getDirectImportsOfNodeModule } from '../stat-reducers';
|
||||
import { BundlephobiaStats } from './bundlephobia-stats.component';
|
||||
import { NodeModuleDependentGraph } from './graphs/dependent-graph.component';
|
||||
|
@ -8,8 +8,8 @@ import { ImportsStatsRow } from './imports-stats-row.component';
|
|||
|
||||
export const DashboardNodeModulePage: React.FC<{
|
||||
name: string;
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
}> = ({ first, last, name }) => {
|
||||
const firstImports = getDirectImportsOfNodeModule(first, name);
|
||||
const lastImports = getDirectImportsOfNodeModule(last, name);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as filesize from 'filesize';
|
||||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import {
|
||||
getAverageChunkSize,
|
||||
getEntryChunkSize,
|
||||
|
@ -10,12 +10,6 @@ import {
|
|||
getTotalModuleCount,
|
||||
getTreeShakablePercent,
|
||||
} from '../stat-reducers';
|
||||
import { ModuleTable } from './module-table.component';
|
||||
import { OverviewSuggestions } from './overview-suggestions';
|
||||
import { CounterPanel } from './panels/counter-panel.component';
|
||||
import { PanelArrangement } from './panels/panel-arrangement.component';
|
||||
import { formatDuration, formatPercent } from './util';
|
||||
|
||||
import { ChunkGraph } from './graphs/chunk-graph.component';
|
||||
import {
|
||||
AverageChunkSize,
|
||||
|
@ -23,10 +17,15 @@ import {
|
|||
TreeShakeHint,
|
||||
WhatIsAnEntrypoint,
|
||||
} from './hints/hints.component';
|
||||
import { ModuleTable } from './module-table.component';
|
||||
import { OverviewSuggestions } from './overview-suggestions';
|
||||
import { CounterPanel } from './panels/counter-panel.component';
|
||||
import { PanelArrangement } from './panels/panel-arrangement.component';
|
||||
import { formatDuration, formatPercent } from './util';
|
||||
|
||||
export const DashboardOverview: React.FC<{
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
}> = ({ first, last }) => {
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as filesize from 'filesize';
|
||||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import {
|
||||
getImportsOfName,
|
||||
getWebpackModulesMap,
|
||||
|
@ -14,8 +14,8 @@ import { PanelArrangement } from './panels/panel-arrangement.component';
|
|||
|
||||
export const DashboardOwnModulePage: React.FC<{
|
||||
name: string;
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
}> = ({ first, last, name }) => {
|
||||
const firstRoot = getWebpackModulesMap(first)[name];
|
||||
const lastRoot = getWebpackModulesMap(last)[name];
|
||||
|
@ -34,7 +34,7 @@ export const DashboardOwnModulePage: React.FC<{
|
|||
<PanelArrangement>
|
||||
<CounterPanel
|
||||
title="Total Size"
|
||||
value={lastRoot ? lastRoot.size : 0}
|
||||
value={lastRoot?.size ?? 0}
|
||||
oldValue={firstRoot ? firstRoot.size : 0}
|
||||
formatter={filesize}
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Base64 } from 'js-base64';
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Redirect, Route, RouteChildrenProps } from 'react-router';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import { getKnownStats, IAppState } from '../redux/reducer';
|
||||
import { DashboardChunkPage } from './dashboard-chunk-page.component';
|
||||
import {
|
||||
|
@ -13,10 +14,10 @@ import {
|
|||
import { DashboardNodeModulePage } from './dashboard-node-module-page.component';
|
||||
import { DashboardOverview } from './dashboard-overview';
|
||||
import { DashboardOwnModulePage } from './dashboard-own-module-page.component';
|
||||
import * as styles from './dashboard.component.scss';
|
||||
import styles from './dashboard.component.scss';
|
||||
|
||||
interface IProps {
|
||||
stats: Stats.ToJsonOutput[];
|
||||
stats: StatsCompilation[];
|
||||
}
|
||||
|
||||
class DashboardComponent extends React.PureComponent<IProps> {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
IAppState,
|
||||
} from '../redux/reducer';
|
||||
import { Button } from './button.component';
|
||||
import * as styles from './enter-urls.component.scss';
|
||||
import styles from './enter-urls.component.scss';
|
||||
import { Errors } from './errors.component';
|
||||
import { ProgressBar } from './progress-bar.component';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IError, IRetrievalError } from '@mixer/retrieval';
|
||||
import * as React from 'react';
|
||||
import * as styles from './errors.component.scss';
|
||||
import styles from './errors.component.scss';
|
||||
import { classes } from './util';
|
||||
|
||||
interface IProps {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as cytoscape from 'cytoscape';
|
||||
import * as React from 'react';
|
||||
import { IoIosContract, IoIosExpand } from 'react-icons/io';
|
||||
import * as styles from './base-graph.component.scss';
|
||||
import styles from './base-graph.component.scss';
|
||||
import { filterUnattachedEdges } from './graph-tool';
|
||||
|
||||
// tslint:disable-next-line
|
||||
|
@ -197,10 +197,7 @@ export default class BaseGraph extends React.PureComponent<IProps, { filter: Fil
|
|||
|
||||
let lastPath: cytoscape.CollectionReturnValue | null = null;
|
||||
graph.on('mouseover', 'node', ev => {
|
||||
lastPath = graph
|
||||
.elements()
|
||||
.dijkstra({ root: ev.target, directed: true })
|
||||
.pathTo(root);
|
||||
lastPath = graph.elements().dijkstra({ root: ev.target, directed: true }).pathTo(root);
|
||||
lastPath.addClass('highlighted');
|
||||
});
|
||||
|
||||
|
|
|
@ -2,15 +2,15 @@ import * as cytoscape from 'cytoscape';
|
|||
import { Base64 } from 'js-base64';
|
||||
import * as React from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import { compareAllModules, getNodeModuleFromIdentifier } from '../../stat-reducers';
|
||||
import { Placeholder } from '../placeholder.component';
|
||||
import { linkToModule, linkToNodeModule } from '../util';
|
||||
import { expandModuleComparison, LazyBaseGraph } from './graph-tool';
|
||||
|
||||
interface IProps {
|
||||
previous: Stats.ToJsonOutput;
|
||||
stats: Stats.ToJsonOutput;
|
||||
previous: StatsCompilation;
|
||||
stats: StatsCompilation;
|
||||
chunkId: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as cytoscape from 'cytoscape';
|
||||
import * as React from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import { fileSizeNode, LazyBaseGraph } from './graph-tool';
|
||||
|
||||
interface IProps {
|
||||
previous: Stats.ToJsonOutput;
|
||||
stats: Stats.ToJsonOutput;
|
||||
previous: StatsCompilation;
|
||||
stats: StatsCompilation;
|
||||
maxBubbleArea?: number;
|
||||
minBubbleArea?: number;
|
||||
}
|
||||
|
@ -50,7 +50,8 @@ export const ChunkGraph = withRouter(
|
|||
const previous = this.props.previous.chunks!.find(c => c.id === chunk.id);
|
||||
|
||||
// If the chunk has a friendly name, render that in the chart. Otherwise, list the chunk id.
|
||||
const chunkLabel = chunk.names.length > 0 ? chunk.names[0] : `Chunk ${chunk.id}`;
|
||||
const chunkLabel =
|
||||
chunk.names && chunk.names.length > 0 ? chunk.names[0] : `Chunk ${chunk.id}`;
|
||||
|
||||
return {
|
||||
data: fileSizeNode({
|
||||
|
@ -68,7 +69,7 @@ export const ChunkGraph = withRouter(
|
|||
const edges: cytoscape.EdgeDefinition[] = [];
|
||||
|
||||
for (const chunk of chunks) {
|
||||
for (const parent of chunk.parents) {
|
||||
for (const parent of chunk.parents ?? []) {
|
||||
edges.push({
|
||||
data: {
|
||||
id: `edge${parent}to${chunk.id}`,
|
||||
|
|
|
@ -2,21 +2,21 @@ import * as cytoscape from 'cytoscape';
|
|||
import { Base64 } from 'js-base64';
|
||||
import * as React from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation, StatsModule } from 'webpack';
|
||||
import {
|
||||
compareAllModules,
|
||||
getDirectImportsOfNodeModule,
|
||||
getImportsOfName,
|
||||
getNodeModuleFromIdentifier,
|
||||
normalizeName,
|
||||
replaceLoaderInIdentifier,
|
||||
replaceLoaderInIdentifier
|
||||
} from '../../stat-reducers';
|
||||
import { color, linkToModule, linkToNodeModule } from '../util';
|
||||
import { expandModuleComparison, LazyBaseGraph } from './graph-tool';
|
||||
|
||||
interface IProps {
|
||||
previous: Stats.ToJsonOutput;
|
||||
stats: Stats.ToJsonOutput;
|
||||
previous: StatsCompilation;
|
||||
stats: StatsCompilation;
|
||||
chunkId?: number;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ interface IState {
|
|||
}
|
||||
|
||||
const createDependentGraph = <P extends {}>(
|
||||
rootFinder: (props: IProps & P) => Stats.FnModules[],
|
||||
rootFinder: (props: IProps & P) => StatsModule[],
|
||||
rootLabel: (props: IProps & P) => string,
|
||||
) =>
|
||||
withRouter(
|
||||
|
@ -91,6 +91,10 @@ const createDependentGraph = <P extends {}>(
|
|||
});
|
||||
|
||||
for (const direct of directImports) {
|
||||
if (!direct.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const directId = Base64.encodeURI(direct.name);
|
||||
edges.push({
|
||||
data: {
|
||||
|
@ -123,7 +127,7 @@ export const NodeModuleDependentGraph = createDependentGraph<{ name: string }>(
|
|||
/**
|
||||
* Graphs the dependent tree for a node module.
|
||||
*/
|
||||
export const GenericDependentGraph = createDependentGraph<{ root: Stats.FnModules }>(
|
||||
props => getImportsOfName(props.stats, props.root.name),
|
||||
export const GenericDependentGraph = createDependentGraph<{ root: StatsModule }>(
|
||||
props => props.root.name ? getImportsOfName(props.stats, props.root.name) : [],
|
||||
props => replaceLoaderInIdentifier(props.root.name),
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
|||
import * as ReactDOM from 'react-dom';
|
||||
import { IoIosInformationCircleOutline } from 'react-icons/io';
|
||||
import { classes } from '../util';
|
||||
import * as styles from './hint-button.component.scss';
|
||||
import styles from './hint-button.component.scss';
|
||||
|
||||
export class HintButton extends React.PureComponent<
|
||||
{ hint: React.ComponentType<{}>; className?: string },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { Stats, StatsModule } from 'webpack';
|
||||
import {
|
||||
getConcatenationParent,
|
||||
getImportType,
|
||||
|
@ -7,14 +7,14 @@ import {
|
|||
replaceLoaderInIdentifier,
|
||||
} from '../stat-reducers';
|
||||
import { ButWaitTheresMore } from './but-wait-theres-more.component';
|
||||
import * as styles from './imports-list.component.scss';
|
||||
import styles from './imports-list.component.scss';
|
||||
import { ModuleTypeBadge } from './panels/node-module-panel.component';
|
||||
import { Placeholder } from './placeholder.component';
|
||||
|
||||
/**
|
||||
* Prints the list of modules that import the target modules.
|
||||
*/
|
||||
export const ImportsList: React.FC<{ targets: Stats.FnModules[] }> = ({ targets }) =>
|
||||
export const ImportsList: React.FC<{ targets: StatsModule[] }> = ({ targets }) =>
|
||||
targets.length === 0 ? (
|
||||
<Placeholder>This module is not imported in the lastest build.</Placeholder>
|
||||
) : (
|
||||
|
@ -25,7 +25,8 @@ export const ImportsList: React.FC<{ targets: Stats.FnModules[] }> = ({ targets
|
|||
return (
|
||||
<div key={i} className={styles.importBox}>
|
||||
<div className={styles.title}>
|
||||
{target.name} in chunk {getConcatenationParent(target).chunks.join(', ')}
|
||||
{target.name} in chunk{' '}
|
||||
{getConcatenationParent(target).chunks?.join(', ') ?? '<anonymous>'}
|
||||
<span style={{ flex: 1 }} />
|
||||
<ModuleTypeBadge type={getImportType(target)} />
|
||||
</div>
|
||||
|
@ -41,7 +42,7 @@ export const ImportsList: React.FC<{ targets: Stats.FnModules[] }> = ({ targets
|
|||
/**
|
||||
* Prints the list of issuers that import any of the target modules.
|
||||
*/
|
||||
export const IssuerTree: React.FC<{ targets: Stats.FnModules[] }> = ({ targets }) =>
|
||||
export const IssuerTree: React.FC<{ targets: StatsModule[] }> = ({ targets }) =>
|
||||
targets.length === 0 ? (
|
||||
<Placeholder>This module is not imported in the lastest build.</Placeholder>
|
||||
) : (
|
||||
|
@ -52,7 +53,8 @@ export const IssuerTree: React.FC<{ targets: Stats.FnModules[] }> = ({ targets }
|
|||
target.issuerPath && (
|
||||
<div key={i} className={styles.importBox}>
|
||||
<div className={styles.title}>
|
||||
{target.name} in chunk {getConcatenationParent(target).chunks.join(', ')}
|
||||
{target.name} in chunk{' '}
|
||||
{getConcatenationParent(target).chunks?.join(', ') ?? '<anonymous>'}
|
||||
<span style={{ flex: 1 }} />
|
||||
<ModuleTypeBadge type={getImportType(target)} />
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as filesize from 'filesize';
|
||||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsModule } from 'webpack';
|
||||
import { getReasons } from '../stat-reducers';
|
||||
import { DependentModules, TotalNodeModuleSize, UniqueEntrypoints } from './hints/hints.component';
|
||||
import { CounterPanel } from './panels/counter-panel.component';
|
||||
|
@ -11,15 +11,15 @@ import { color } from './util';
|
|||
* Prints the list of modules that import the target modules.
|
||||
*/
|
||||
export const ImportsStatsRow: React.FC<{
|
||||
oldTargets: Stats.FnModules[];
|
||||
newTargets: Stats.FnModules[];
|
||||
oldTargets: StatsModule[];
|
||||
newTargets: StatsModule[];
|
||||
}> = ({ oldTargets, newTargets }) => (
|
||||
<PanelArrangement>
|
||||
<CounterPanel
|
||||
title="Total Size"
|
||||
hint={TotalNodeModuleSize}
|
||||
value={newTargets.reduce((acc, t) => acc + t.size, 0)}
|
||||
oldValue={oldTargets.reduce((acc, t) => acc + t.size, 0)}
|
||||
value={newTargets.reduce((acc, t) => acc + (t.size || 0), 0)}
|
||||
oldValue={oldTargets.reduce((acc, t) => acc + (t.size || 0), 0)}
|
||||
formatter={filesize}
|
||||
/>
|
||||
<CounterPanel
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import * as filesize from 'filesize';
|
||||
import { Cell, Column, ColumnCellProps, Table } from 'fixed-data-table-2';
|
||||
import 'fixed-data-table-2/dist/fixed-data-table.css';
|
||||
import * as React from 'react';
|
||||
import { Stats } from 'webpack';
|
||||
import { IoIosArrowRoundDown, IoIosArrowRoundUp } from 'react-icons/io';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import {
|
||||
compareAllModules,
|
||||
getNodeModuleFromIdentifier,
|
||||
IWebpackModuleComparisonOutput,
|
||||
replaceLoaderInIdentifier,
|
||||
} from '../stat-reducers';
|
||||
import * as styles from './module-table.component.scss';
|
||||
|
||||
import 'fixed-data-table-2/dist/fixed-data-table.css';
|
||||
import { IoIosArrowRoundDown, IoIosArrowRoundUp } from 'react-icons/io';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import styles from './module-table.component.scss';
|
||||
import {
|
||||
formatDifference,
|
||||
formatPercentageDifference,
|
||||
|
@ -21,8 +20,8 @@ import {
|
|||
} from './util';
|
||||
|
||||
interface IProps {
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
inChunk?: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import * as filesize from 'filesize';
|
||||
import * as React from 'react';
|
||||
import { IoIosInformationCircleOutline, IoIosThumbsUp } from 'react-icons/io';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import {
|
||||
getEntryChunkSize,
|
||||
getNodeModuleSize,
|
||||
getTotalChunkSize,
|
||||
getTreeShakablePercent,
|
||||
} from '../stat-reducers';
|
||||
import * as styles from './overview-suggestions.component.scss';
|
||||
import styles from './overview-suggestions.component.scss';
|
||||
import { classes, formatPercent } from './util';
|
||||
|
||||
interface IProps {
|
||||
first: Stats.ToJsonOutput;
|
||||
last: Stats.ToJsonOutput;
|
||||
first: StatsCompilation;
|
||||
last: StatsCompilation;
|
||||
}
|
||||
|
||||
const epsilon = 1024 * 2;
|
||||
|
||||
function nodeModuleSizeTip(first: Stats.ToJsonOutput, last: Stats.ToJsonOutput) {
|
||||
function nodeModuleSizeTip(first: StatsCompilation, last: StatsCompilation) {
|
||||
const firstNodeModuleSize = getNodeModuleSize(first);
|
||||
const lastNodeModuleSize = getNodeModuleSize(last);
|
||||
if (lastNodeModuleSize > firstNodeModuleSize + epsilon) {
|
||||
|
@ -51,7 +51,7 @@ function nodeModuleSizeTip(first: Stats.ToJsonOutput, last: Stats.ToJsonOutput)
|
|||
return null;
|
||||
}
|
||||
|
||||
function entrypointTip(last: Stats.ToJsonOutput) {
|
||||
function entrypointTip(last: StatsCompilation) {
|
||||
const totalSize = getTotalChunkSize(last);
|
||||
const entrySize = getEntryChunkSize(last);
|
||||
const isMajority = entrySize > totalSize / 2;
|
||||
|
@ -83,7 +83,7 @@ function entrypointTip(last: Stats.ToJsonOutput) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function treeShakeTip(last: Stats.ToJsonOutput) {
|
||||
function treeShakeTip(last: StatsCompilation) {
|
||||
const percent = getTreeShakablePercent(last);
|
||||
if (percent > 0.8) {
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import { HintButton } from '../hints/hint-button.component';
|
||||
import { classes } from '../util';
|
||||
import * as styles from './panels.component.scss';
|
||||
import styles from './panels.component.scss';
|
||||
|
||||
export const enum ArrowDirection {
|
||||
Up,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import { color, formatValue } from '../util';
|
||||
import { BasePanel } from './base-panel.component';
|
||||
import * as styles from './panels.component.scss';
|
||||
import styles from './panels.component.scss';
|
||||
import { StatDelta } from './stat-delta.component';
|
||||
|
||||
interface IProps {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { RouteComponentProps, withRouter } from 'react-router';
|
|||
import { ImportType, INodeModule, INodeModuleComparisonOutput } from '../../stat-reducers';
|
||||
import { classes, color, linkToNodeModule } from '../util';
|
||||
import { BasePanel } from './base-panel.component';
|
||||
import * as styles from './panels.component.scss';
|
||||
import styles from './panels.component.scss';
|
||||
import { StatDelta } from './stat-delta.component';
|
||||
|
||||
interface IProps {
|
||||
|
@ -24,16 +24,16 @@ const getSizeInChunk = (nodeModule?: INodeModule, chunk?: number) => {
|
|||
|
||||
let sum = 0;
|
||||
for (const m of nodeModule.modules) {
|
||||
if (m.chunks.includes(chunk)) {
|
||||
sum += m.size;
|
||||
if (m.chunks?.includes(chunk)) {
|
||||
sum += m.size || 0;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
};
|
||||
|
||||
export const NodeModulePanel = withRouter<IProps & RouteComponentProps<{}>>(
|
||||
({ comparison, inChunk, history }) => {
|
||||
export const NodeModulePanel = withRouter(
|
||||
({ comparison, inChunk, history }: IProps & RouteComponentProps<{}>) => {
|
||||
const oldSize = getSizeInChunk(comparison.old, inChunk);
|
||||
const newSize = getSizeInChunk(comparison.new, inChunk);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import * as styles from './panels.component.scss';
|
||||
import styles from './panels.component.scss';
|
||||
|
||||
export const PanelArrangement: React.FC = props => (
|
||||
<div className={styles.arrangement}>{props.children}</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import * as styles from './placeholder.component.scss';
|
||||
import styles from './placeholder.component.scss';
|
||||
|
||||
export const Placeholder: React.FC = props => (
|
||||
<div className={styles.placeholder}>{props.children}</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import * as styles from './progress-bar.component.scss';
|
||||
import styles from './progress-bar.component.scss';
|
||||
import { classes } from './util';
|
||||
|
||||
interface IProps {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Base64 } from 'js-base64';
|
||||
import * as styles from './util.component.scss';
|
||||
import styles from './util.component.scss';
|
||||
|
||||
export const classes = (...classList: Array<string | null | undefined>) => {
|
||||
let str = '';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IError } from '@mixer/retrieval';
|
||||
import { ActionType, createAsyncAction, createStandardAction } from 'typesafe-actions';
|
||||
import { Stats } from 'webpack';
|
||||
import { ActionType, createAction, createAsyncAction } from 'typesafe-actions';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import { IBundlephobiaStats } from './services/bundlephobia-api';
|
||||
|
||||
export interface ILoadableResource {
|
||||
|
@ -18,7 +18,7 @@ export const doAnalysis = createAsyncAction(
|
|||
'doAnalysisCancel',
|
||||
)<
|
||||
{ resource: ILoadableResource },
|
||||
{ resource: ILoadableResource; data: Stats.ToJsonOutput },
|
||||
{ resource: ILoadableResource; data: StatsCompilation },
|
||||
IError & { resource: ILoadableResource },
|
||||
{ resource: ILoadableResource }
|
||||
>();
|
||||
|
@ -35,19 +35,19 @@ export const fetchBundlephobiaData = createAsyncAction(
|
|||
/**
|
||||
* Loads bundles for all the requested urls.
|
||||
*/
|
||||
export const loadAllUrls = createStandardAction('loadAllUrls')<{
|
||||
export const loadAllUrls = createAction('loadAllUrls')<{
|
||||
resources: ILoadableResource[];
|
||||
}>();
|
||||
|
||||
/**
|
||||
* Clears loaded bundles.
|
||||
*/
|
||||
export const clearLoadedBundles = createStandardAction('clearLoadedBundles')();
|
||||
export const clearLoadedBundles = createAction('clearLoadedBundles')();
|
||||
|
||||
/**
|
||||
* Indicates that a webworker errored.
|
||||
*/
|
||||
export const webworkerErrored = createStandardAction('webworkerErrored')<IError>();
|
||||
export const webworkerErrored = createAction('webworkerErrored')<IError>();
|
||||
|
||||
export type CompareAction = ActionType<
|
||||
| typeof doAnalysis
|
||||
|
|
|
@ -5,17 +5,17 @@ import {
|
|||
Retrieval,
|
||||
RetrievalState,
|
||||
success,
|
||||
workingRetrival,
|
||||
workingRetrival
|
||||
} from '@mixer/retrieval';
|
||||
import { createSelector } from 'reselect';
|
||||
import { getType } from 'typesafe-actions';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import {
|
||||
clearLoadedBundles,
|
||||
CompareAction,
|
||||
doAnalysis,
|
||||
fetchBundlephobiaData,
|
||||
loadAllUrls,
|
||||
loadAllUrls
|
||||
} from './actions';
|
||||
import { IBundlephobiaStats } from './services/bundlephobia-api';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export interface IAppState {
|
|||
/**
|
||||
* List of bundle loading states.
|
||||
*/
|
||||
bundles: Readonly<{ [url: string]: Retrieval<Stats.ToJsonOutput> }>;
|
||||
bundles: Readonly<{ [url: string]: Retrieval<StatsCompilation> }>;
|
||||
|
||||
/**
|
||||
* Mapping of bundlephobia dependency information.
|
||||
|
@ -130,7 +130,7 @@ export const getBundleData = (url: string) => (state: IAppState) =>
|
|||
export const getKnownStats = createSelector(
|
||||
getBundleMap,
|
||||
map => {
|
||||
const output: Stats.ToJsonOutput[] = [];
|
||||
const output: StatsCompilation[] = [];
|
||||
for (const key of Object.keys(map)) {
|
||||
const value = map[key];
|
||||
if (value.state === RetrievalState.Succeeded) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Stats } from 'webpack';
|
||||
import { Stats, StatsCompilation, StatsModule } from 'webpack';
|
||||
|
||||
const anyPathSeparator = /\/|\\/;
|
||||
|
||||
|
@ -62,14 +62,14 @@ const cacheByArg = <T extends Function>(fn: T): T => {
|
|||
/**
|
||||
* Returns the size of all chunks from the stats.
|
||||
*/
|
||||
export const getTotalChunkSize = cacheByArg((stats: Stats.ToJsonOutput) =>
|
||||
export const getTotalChunkSize = cacheByArg((stats: StatsCompilation) =>
|
||||
stats.chunks!.reduce((sum, chunk) => sum + chunk.size, 0),
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the size of the entry chunk(s).
|
||||
*/
|
||||
export const getEntryChunkSize = cacheByArg((stats: Stats.ToJsonOutput) =>
|
||||
export const getEntryChunkSize = cacheByArg((stats: StatsCompilation) =>
|
||||
stats.chunks!.filter(c => c.entry).reduce((sum, chunk) => sum + chunk.size, 0),
|
||||
);
|
||||
|
||||
|
@ -99,7 +99,7 @@ export interface INodeModule {
|
|||
/**
|
||||
* Modules imported from this dependency.
|
||||
*/
|
||||
modules: Stats.FnModules[];
|
||||
modules: StatsModule[];
|
||||
|
||||
/**
|
||||
* Type of the node module.
|
||||
|
@ -129,26 +129,26 @@ export const getNodeModuleFromIdentifier = (identifier: string): string | null =
|
|||
return null;
|
||||
};
|
||||
|
||||
const concatParents = new WeakMap<Stats.FnModules, Stats.FnModules>();
|
||||
const concatParents = new WeakMap<StatsModule, StatsModule>();
|
||||
|
||||
/**
|
||||
* Returns the concatenation parent in which the given module resides. Will
|
||||
* returnt he module itself if it's already top-level.
|
||||
*/
|
||||
export const getConcatenationParent = (m: Stats.FnModules): Stats.FnModules =>
|
||||
export const getConcatenationParent = (m: StatsModule): StatsModule =>
|
||||
concatParents.get(m) || m;
|
||||
|
||||
/**
|
||||
* Get webpack modules, either globally ro in a single chunk.
|
||||
*/
|
||||
export const getWebpackModules = cacheByArg((stats: Stats.ToJsonOutput, filterToChunk?: number) => {
|
||||
const modules: Stats.FnModules[] = [];
|
||||
export const getWebpackModules = cacheByArg((stats: StatsCompilation, filterToChunk?: number) => {
|
||||
const modules: StatsModule[] = [];
|
||||
if (!stats.modules) {
|
||||
return modules;
|
||||
}
|
||||
|
||||
for (const parent of stats.modules) {
|
||||
if (filterToChunk !== undefined && !parent.chunks.includes(filterToChunk)) {
|
||||
if (filterToChunk !== undefined && !parent.chunks?.includes(filterToChunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -172,8 +172,8 @@ export const getWebpackModules = cacheByArg((stats: Stats.ToJsonOutput, filterTo
|
|||
* Returns a mapping of normalized identifiers in the chunk to module data.
|
||||
*/
|
||||
export const getWebpackModulesMap = cacheByArg(
|
||||
(stats: Stats.ToJsonOutput, filterToChunk?: number) => {
|
||||
const mapping: { [name: string]: Stats.FnModules } = {};
|
||||
(stats: StatsCompilation, filterToChunk?: number) => {
|
||||
const mapping: { [name: string]: StatsModule } = {};
|
||||
for (const m of getWebpackModules(stats, filterToChunk)) {
|
||||
mapping[normalizeName(m.name)] = m;
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ export const getWebpackModulesMap = cacheByArg(
|
|||
/**
|
||||
* Gets the type of import of the given module.
|
||||
*/
|
||||
export const getImportType = (importedModule: Stats.FnModules) => {
|
||||
export const getImportType = (importedModule: StatsModule) => {
|
||||
let flags = 0;
|
||||
for (const reason of getReasons(importedModule)) {
|
||||
if (reason.type) {
|
||||
|
@ -203,11 +203,11 @@ export const getImportType = (importedModule: Stats.FnModules) => {
|
|||
/**
|
||||
* Returns the number of dependencies.
|
||||
*/
|
||||
export const getNodeModules = cacheByArg((stats: Stats.ToJsonOutput, inChunk?: number) => {
|
||||
export const getNodeModules = cacheByArg((stats: StatsCompilation, inChunk?: number) => {
|
||||
const modules: { [key: string]: INodeModule } = {};
|
||||
|
||||
for (const importedModule of getWebpackModules(stats, inChunk)) {
|
||||
const packageName = getNodeModuleFromIdentifier(importedModule.identifier);
|
||||
const packageName = getNodeModuleFromIdentifier(importedModule.identifier!);
|
||||
if (!packageName) {
|
||||
continue;
|
||||
}
|
||||
|
@ -217,12 +217,12 @@ export const getNodeModules = cacheByArg((stats: Stats.ToJsonOutput, inChunk?: n
|
|||
if (!previous) {
|
||||
modules[packageName] = {
|
||||
name: packageName,
|
||||
totalSize: importedModule.size,
|
||||
totalSize: importedModule.size || 0,
|
||||
modules: [importedModule],
|
||||
importType: moduleType,
|
||||
};
|
||||
} else {
|
||||
previous.totalSize += importedModule.size;
|
||||
previous.totalSize += importedModule.size || 0;
|
||||
previous.importType |= moduleType;
|
||||
previous.modules.push(importedModule);
|
||||
}
|
||||
|
@ -269,16 +269,16 @@ export interface IWebpackModuleComparisonOutput {
|
|||
fromSize: number;
|
||||
toSize: number;
|
||||
nodeModule?: string;
|
||||
old?: Stats.FnModules;
|
||||
new?: Stats.FnModules;
|
||||
old?: StatsModule;
|
||||
new?: StatsModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a grouped comparison of the old and new modules from the stats.
|
||||
*/
|
||||
export const compareAllModules = (
|
||||
oldStats: Stats.ToJsonOutput,
|
||||
newStats: Stats.ToJsonOutput,
|
||||
oldStats: StatsCompilation,
|
||||
newStats: StatsCompilation,
|
||||
inChunk?: number,
|
||||
) => {
|
||||
const oldModules = getWebpackModules(oldStats, inChunk);
|
||||
|
@ -286,29 +286,37 @@ export const compareAllModules = (
|
|||
|
||||
const output: { [name: string]: IWebpackModuleComparisonOutput } = {};
|
||||
for (const m of oldModules) {
|
||||
if (!m.identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const normalized = normalizeName(m.name);
|
||||
output[normalized] = {
|
||||
name: normalized,
|
||||
type: identifyModuleType(m.identifier),
|
||||
nodeModule: getNodeModuleFromIdentifier(m.identifier) || undefined,
|
||||
toSize: 0,
|
||||
fromSize: m.size,
|
||||
fromSize: m.size || 0,
|
||||
old: m,
|
||||
};
|
||||
}
|
||||
|
||||
for (const m of newModules) {
|
||||
if (!m.identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const normalized = normalizeName(m.name);
|
||||
if (output[normalized]) {
|
||||
output[normalized].new = m;
|
||||
output[normalized].toSize = m.size;
|
||||
output[normalized].toSize = m.size || 0;
|
||||
} else {
|
||||
output[normalized] = {
|
||||
name: normalized,
|
||||
type: identifyModuleType(m.identifier),
|
||||
nodeModule: getNodeModuleFromIdentifier(m.identifier) || undefined,
|
||||
fromSize: 0,
|
||||
toSize: m.size,
|
||||
toSize: m.size || 0,
|
||||
new: m,
|
||||
};
|
||||
}
|
||||
|
@ -330,8 +338,8 @@ export interface INodeModuleComparisonOutput {
|
|||
* Returns a grouped comparison of the old and new modules from the stats.
|
||||
*/
|
||||
export const compareNodeModules = (
|
||||
oldStats: Stats.ToJsonOutput,
|
||||
newStats: Stats.ToJsonOutput,
|
||||
oldStats: StatsCompilation,
|
||||
newStats: StatsCompilation,
|
||||
inChunk?: number,
|
||||
) => {
|
||||
const oldModules = getNodeModules(oldStats, inChunk);
|
||||
|
@ -356,7 +364,7 @@ export const compareNodeModules = (
|
|||
/**
|
||||
* Gets the number of node modules.
|
||||
*/
|
||||
export const getNodeModuleSize = cacheByArg((stats: Stats.ToJsonOutput, inChunk?: number) => {
|
||||
export const getNodeModuleSize = cacheByArg((stats: StatsCompilation, inChunk?: number) => {
|
||||
let total = 0;
|
||||
const modules = getNodeModules(stats, inChunk);
|
||||
for (const key of Object.keys(modules)) {
|
||||
|
@ -369,13 +377,13 @@ export const getNodeModuleSize = cacheByArg((stats: Stats.ToJsonOutput, inChunk?
|
|||
/**
|
||||
* Gets the number of node modules.
|
||||
*/
|
||||
export const getNodeModuleCount = (stats: Stats.ToJsonOutput, inChunk?: number) =>
|
||||
export const getNodeModuleCount = (stats: StatsCompilation, inChunk?: number) =>
|
||||
Object.keys(getNodeModules(stats, inChunk)).length;
|
||||
|
||||
/**
|
||||
* Gets the number of node modules.
|
||||
*/
|
||||
export const getTreeShakablePercent = cacheByArg((stats: Stats.ToJsonOutput, inChunk?: number) => {
|
||||
export const getTreeShakablePercent = cacheByArg((stats: StatsCompilation, inChunk?: number) => {
|
||||
const modules = Object.values(getNodeModules(stats, inChunk));
|
||||
if (modules.length === 0) {
|
||||
return 1;
|
||||
|
@ -394,13 +402,13 @@ export const getTreeShakablePercent = cacheByArg((stats: Stats.ToJsonOutput, inC
|
|||
/**
|
||||
* Gets the number of node modules.
|
||||
*/
|
||||
export const getTotalModuleCount = (stats: Stats.ToJsonOutput, inChunk?: number) =>
|
||||
export const getTotalModuleCount = (stats: StatsCompilation, inChunk?: number) =>
|
||||
getWebpackModules(stats, inChunk)!.length;
|
||||
|
||||
/**
|
||||
* Gets the number of node modules.
|
||||
*/
|
||||
export const getAverageChunkSize = (stats: Stats.ToJsonOutput) => {
|
||||
export const getAverageChunkSize = (stats: StatsCompilation) => {
|
||||
let sum = 0;
|
||||
for (const chunk of stats.chunks!) {
|
||||
sum += chunk.size;
|
||||
|
@ -434,18 +442,18 @@ export interface IModuleTreeNode {
|
|||
/**
|
||||
* Gets the reasons that the module was imported. Fix for broken webpack typings here.
|
||||
*/
|
||||
export const getReasons = (m: Stats.FnModules): Stats.Reason[] => m.reasons as any;
|
||||
export const getReasons = (m: StatsModule): Stats.Reason[] => m.reasons as any;
|
||||
|
||||
/**
|
||||
* Gets all direct imports of the given node module.
|
||||
*/
|
||||
export const getDirectImportsOfNodeModule = (stats: Stats.ToJsonOutput, name: string) =>
|
||||
stats.modules!.filter(m => getNodeModuleFromIdentifier(m.name) === name);
|
||||
export const getDirectImportsOfNodeModule = (stats: StatsCompilation, name: string) =>
|
||||
stats.modules!.filter(m => m.name && getNodeModuleFromIdentifier(m.name) === name);
|
||||
|
||||
/**
|
||||
* Gets all direct imports of the given node module.
|
||||
*/
|
||||
export const getImportsOfName = (stats: Stats.ToJsonOutput, name: string): Stats.FnModules[] => {
|
||||
export const getImportsOfName = (stats: StatsCompilation, name: string): StatsModule[] => {
|
||||
const modules = getWebpackModulesMap(stats);
|
||||
const root = modules[name];
|
||||
if (!root) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { decode } from 'msgpack-lite';
|
||||
import { inflate } from 'pako';
|
||||
import { from, Observable } from 'rxjs';
|
||||
import { Stats } from 'webpack';
|
||||
import { StatsCompilation } from 'webpack';
|
||||
import { CompareAction, doAnalysis, ILoadableResource } from '../redux/actions';
|
||||
import { ErrorCode } from '../redux/reducer';
|
||||
import { Semaphore } from './semaphore';
|
||||
|
@ -52,14 +52,14 @@ export function download(resource: ILoadableResource): Observable<CompareAction>
|
|||
);
|
||||
}
|
||||
|
||||
function processDownload(rawResponse: ArrayBuffer): Stats.ToJsonOutput {
|
||||
function processDownload(rawResponse: ArrayBuffer): StatsCompilation {
|
||||
const asArray = new Uint8Array(rawResponse);
|
||||
const data = asArray[0] === 0x1f && asArray[1] === 0x8b ? inflate(asArray) : asArray;
|
||||
const stats: Stats.ToJsonOutput =
|
||||
const stats: StatsCompilation =
|
||||
data[0] === '{'.charCodeAt(0) ? JSON.parse(new TextDecoder().decode(data)) : decode(data);
|
||||
|
||||
if (stats.modules) {
|
||||
stats.modules = stats.modules.filter(m => m.chunks.length !== 0);
|
||||
stats.modules = stats.modules.filter(m => m.chunks && m.chunks.length !== 0);
|
||||
}
|
||||
|
||||
return stats;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { createWriteStream } from 'fs';
|
|||
import { createEncodeStream } from 'msgpack-lite';
|
||||
import { resolve } from 'path';
|
||||
import { PassThrough } from 'stream';
|
||||
import { Compiler, Stats } from 'webpack';
|
||||
import { Compiler, Stats, StatsCompilation } from 'webpack';
|
||||
import { createGzip } from 'zlib';
|
||||
|
||||
export const enum StatsFormat {
|
||||
|
@ -51,7 +51,7 @@ const defaultFilename = (gzip: boolean, format: StatsFormat) => {
|
|||
|
||||
const writeToStream = (
|
||||
options: IPluginOptions,
|
||||
data: Stats.ToJsonOutput,
|
||||
data: StatsCompilation,
|
||||
stream: NodeJS.WritableStream,
|
||||
) => {
|
||||
if (options.format === StatsFormat.MsgPack) {
|
||||
|
@ -129,7 +129,8 @@ export class BundleComparisonPlugin {
|
|||
if (compiler.hooks) {
|
||||
compiler.hooks.done.tapAsync(BundleComparisonPlugin.name, handler);
|
||||
} else {
|
||||
compiler.plugin('done', handler);
|
||||
// webpack 3
|
||||
(compiler as any).plugin('done', handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ module.exports = {
|
|||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: true,
|
||||
localIdentName: '[local]__[hash:base64:5]',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -50,7 +49,9 @@ module.exports = {
|
|||
new HtmlWebpackPlugin({
|
||||
title: 'Webpack Bundle Compare',
|
||||
}),
|
||||
new CopyPlugin([{ from: path.join(__dirname, 'public'), to: 'public' }]),
|
||||
new CopyPlugin({
|
||||
patterns: [{ from: 'public/**/*.*', to: 'public' }],
|
||||
}),
|
||||
new DefinePlugin({
|
||||
INITIAL_FILES: process.env.WBC_FILES
|
||||
? JSON.stringify(process.env.WBC_FILES.split(','))
|
||||
|
|
Загрузка…
Ссылка в новой задаче