Skip to content

Commit fbdc622

Browse files
committed
[change] Reduce library size #392
Closes #392
1 parent c32f626 commit fbdc622

File tree

12 files changed

+306
-31
lines changed

12 files changed

+306
-31
lines changed

README.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,25 +137,39 @@ yarn start
137137

138138
## Building the library
139139

140-
To build the production-ready library:
140+
NetJSONGraph.js provides **two build variants** to optimize bundle size for different use cases:
141+
142+
### 1. Full Bundle (Recommended for standalone usage)
143+
144+
Build the complete library with all dependencies included:
141145

142146
```bash
143-
yarn build
147+
yarn build:full
144148
```
145149

146-
**Output**: Single optimized bundle with all dependencies included.
150+
**Output**:
147151

148152
- `netjsongraph.[hash].min.js` - Complete library with ECharts and Leaflet
149-
- `netjsongraph.[hash].min.js.map` - Source map for debugging
150153
- Compressed versions (`.gz` and `.br`) for optimized delivery
151154

152-
The build includes:
155+
**Use when**: You want a standalone library with all dependencies bundled.
156+
157+
### 2. ECharts-Only Bundle (Optimized for projects with existing Leaflet)
158+
159+
Build the library without Leaflet, expecting it to be provided externally:
160+
161+
```bash
162+
yarn build:echarts-only
163+
```
164+
165+
**Output**:
166+
167+
- `netjsongraph.echarts.[hash].min.js` - Library with ECharts only
168+
- Compressed versions (`.gz` and `.br`)
153169

154-
- **ECharts** for network graph rendering
155-
- **Leaflet** for geographic map rendering
156-
- **Core NetJSONGraph.js** functionality
170+
**Use when**: Your project already includes Leaflet (e.g., via django-leaflet in OpenWISP projects). This reduces bundle size by ~144 KiB.
157171

158-
This unified bundle approach ensures compatibility and simplifies deployment while maintaining optimal performance through advanced webpack optimizations.
172+
**Requirements**: Leaflet must be loaded before NetJSONGraph (available as global `L` object).
159173

160174
### Run Tests
161175

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"test": "jest --silent",
99
"dev": "webpack serve --open --mode development",
1010
"start": "yarn dev",
11-
"build": "webpack --progress --mode production",
11+
"build": "yarn build:full",
12+
"build:full": "webpack --progress --mode production --env BUILD_TYPE=full",
13+
"build:echarts-only": "webpack --progress --mode production --env BUILD_TYPE=echarts-only",
1214
"coverage": "jest --silent --coverage",
1315
"coveralls": "jest --silent -f ./coverage/lcov.info && cat ./coverage/lcov.info | coveralls || echo 'no coverage file found'",
1416
"precommit": "lint-staged",
@@ -85,5 +87,13 @@
8587
"leaflet": "^1.8.0",
8688
"zrender": "^6.0.0"
8789
},
90+
"peerDependencies": {
91+
"leaflet": "^1.8.0"
92+
},
93+
"peerDependenciesMeta": {
94+
"leaflet": {
95+
"optional": true
96+
}
97+
},
8898
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
8999
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<title>NetJSON Cluster - ECharts Only Build Example</title>
5+
<meta charset="utf-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<!-- Leaflet loaded externally -->
8+
<link
9+
rel="stylesheet"
10+
href="https://unpkg.com/[email protected]/dist/leaflet.css"
11+
integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
12+
crossorigin=""
13+
/>
14+
<script
15+
src="https://unpkg.com/[email protected]/dist/leaflet.js"
16+
integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
17+
crossorigin=""
18+
></script>
19+
<!-- theme can be easily customized via css -->
20+
<link href="../lib/css/netjsongraph-theme.css" rel="stylesheet" />
21+
<link href="../lib/css/netjsongraph.css" rel="stylesheet" />
22+
<style type="text/css">
23+
body {
24+
margin: 0;
25+
padding: 0;
26+
font-family: Arial, sans-serif;
27+
}
28+
#legend h4 {
29+
margin: 10px 0;
30+
text-align: center;
31+
}
32+
#legend {
33+
position: absolute;
34+
right: 25px;
35+
bottom: 25px;
36+
width: auto;
37+
height: auto;
38+
max-width: 250px;
39+
padding: 8px 15px;
40+
background: #fbfbfb;
41+
border-radius: 8px;
42+
color: #000;
43+
font-family: Arial, sans-serif;
44+
font-size: 14px;
45+
z-index: 1000;
46+
user-select: text;
47+
}
48+
#legend p {
49+
margin: 10px 0;
50+
display: flex;
51+
align-items: center;
52+
}
53+
#legend span {
54+
width: 16px;
55+
margin-right: 5px;
56+
}
57+
.status-ok,
58+
.status-problem,
59+
.status-critical {
60+
display: inline-block;
61+
width: 15px;
62+
height: 15px;
63+
margin-right: 5px;
64+
border-radius: 50%;
65+
}
66+
.status-ok {
67+
background-color: #1ba619;
68+
}
69+
.status-problem {
70+
background-color: #ffa500;
71+
}
72+
.status-critical {
73+
background-color: #c92517;
74+
}
75+
#build-info {
76+
position: absolute;
77+
top: 15px;
78+
right: 15px;
79+
background: rgba(251, 251, 251, 0.95);
80+
padding: 8px 12px;
81+
border-radius: 6px;
82+
font-size: 12px;
83+
font-family: monospace;
84+
color: #333;
85+
z-index: 1000;
86+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
87+
}
88+
#build-info strong {
89+
color: #1ba619;
90+
}
91+
</style>
92+
</head>
93+
<body>
94+
<div id="build-info">
95+
Build: <strong>echarts-only</strong> | Leaflet: <strong>External</strong>
96+
</div>
97+
<script type="text/javascript">
98+
const map = new NetJSONGraph("../assets/data/netjson-clustering.json", {
99+
render: "map",
100+
clustering: true,
101+
clusteringThreshold: 2,
102+
clusterRadius: 80,
103+
disableClusteringAtLevel: 18,
104+
clusteringAttribute: "status",
105+
clusterSeparation: 20,
106+
mapOptions: {
107+
center: [55.98, 11.54],
108+
zoom: 4,
109+
minZoom: 3,
110+
maxZoom: 18,
111+
// No label configuration to keep the view clean
112+
},
113+
// defaults categories and colors
114+
// shown here to make customization easier
115+
// nodeCategories: [
116+
// {name: "ok", nodeStyle: {color: "#1ba619"}},
117+
// {name: "problem", nodeStyle: {color: "#ffa500"}},
118+
// {name: "critical", nodeStyle: {color: "#c92517"}},
119+
// ]
120+
});
121+
122+
// Build legend UI
123+
const createLegend = (key, className) => {
124+
const legendItem = document.createElement("p");
125+
const legendIcon = document.createElement("span");
126+
legendIcon.setAttribute("class", className);
127+
legends.appendChild(legendItem);
128+
legendItem.appendChild(legendIcon);
129+
legendItem.innerHTML += key;
130+
return legendItem;
131+
};
132+
133+
const legends = document.createElement("div");
134+
legends.setAttribute("id", "legend");
135+
const legendsHeader = document.createElement("h4");
136+
legendsHeader.textContent = "Node Status";
137+
legends.appendChild(legendsHeader);
138+
legends.appendChild(createLegend("OK", "status-ok"));
139+
legends.appendChild(createLegend("Problem", "status-problem"));
140+
legends.appendChild(createLegend("Critical", "status-critical"));
141+
document.body.appendChild(legends);
142+
143+
// Render map
144+
try {
145+
map.render();
146+
} catch (e) {
147+
console.error("Error initializing NetJSONGraph:", e);
148+
}
149+
</script>
150+
</body>
151+
</html>

public/example_templates/netjsonmap-indoormap.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
1111
crossorigin=""
1212
/>
13+
<script
14+
src="https://unpkg.com/[email protected]/dist/leaflet.js"
15+
integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
16+
crossorigin=""
17+
></script>
1318
<!-- theme can be easily customized via css -->
1419
<link href="../lib/css/netjsongraph-theme.css" rel="stylesheet" />
1520
<link href="../lib/css/netjsongraph.css" rel="stylesheet" />

src/js/echarts-leaflet/LeafletCoordSys.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import {util, graphic, matrix} from "echarts/core";
2-
import {
3-
Layer,
4-
DomUtil,
5-
Projection,
6-
LatLng,
7-
map as lMap,
8-
control,
9-
tileLayer as lTileLayer,
10-
} from "leaflet";
2+
import getLeaflet from "../leaflet-loader";
113

124
/* eslint-disable no-underscore-dangle */
135
// Underscore dangling allowed to identify internal methods and variable
@@ -17,6 +9,20 @@ import {
179
* @return {function} LeafletCoordSys
1810
*/
1911
function createLeafletCoordSystem() {
12+
const L = getLeaflet();
13+
if (!L) {
14+
throw new Error("Leaflet api is not loaded");
15+
}
16+
const {
17+
Layer,
18+
DomUtil,
19+
Projection,
20+
LatLng,
21+
map: lMap,
22+
control,
23+
tileLayer: lTileLayer,
24+
} = L;
25+
2026
const CustomOverlay = Layer.extend({
2127
initialize(container) {
2228
this._container = container;

src/js/echarts-leaflet/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@ import {registerCoordinateSystem, registerAction} from "echarts/core";
22
import createLeafletCoordSystem from "./LeafletCoordSys";
33
import extendLeafletModel from "./LeafletModel";
44
import extendLeafletView from "./LeafletView";
5+
import getLeaflet from "../leaflet-loader";
56

67
/**
78
* echarts register leaflet coord system
89
*/
910
export function registerLeafletSystem() {
11+
const L = getLeaflet(true);
12+
if (!L) {
13+
// Leaflet is not available, so we can't register the Leaflet coordinate system.
14+
// This is fine for graph-only rendering.
15+
return;
16+
}
17+
1018
extendLeafletModel();
1119
extendLeafletView();
1220

src/js/leaflet-loader.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* eslint-disable import/no-mutable-exports */
2+
/**
3+
* Leaflet loader - conditionally uses bundled Leaflet or global L
4+
*
5+
* This module provides a way to use either:
6+
* 1. Bundled Leaflet (for full bundle) - imported from 'leaflet' package
7+
* 2. Global Leaflet (for echarts-only bundle) - expects window.L to be available
8+
*
9+
* The BUNDLE_LEAFLET variable is defined by webpack DefinePlugin during build.
10+
*/
11+
12+
let L;
13+
14+
export default function getLeaflet(suppressError = false) {
15+
if (L) {
16+
return L;
17+
}
18+
19+
// BUNDLE_LEAFLET is defined by webpack DefinePlugin
20+
// For full build: BUNDLE_LEAFLET = true
21+
// For echarts-only build: BUNDLE_LEAFLET = false
22+
// eslint-disable-next-line no-undef
23+
if (typeof BUNDLE_LEAFLET !== "undefined" && BUNDLE_LEAFLET) {
24+
// eslint-disable-next-line global-require
25+
L = require("leaflet");
26+
} else {
27+
if (typeof window === "undefined" || !window.L) {
28+
if (!suppressError) {
29+
console.error(
30+
"Leaflet (L) is not defined! Make sure Leaflet is loaded before NetJSONGraph.",
31+
);
32+
}
33+
return null;
34+
}
35+
L = window.L;
36+
}
37+
return L;
38+
}

src/js/netjsongraph.config.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {CRS} from "leaflet";
1+
import getLeaflet from "./leaflet-loader";
22

33
/**
44
* Default options
@@ -44,7 +44,6 @@ const NetJSONGraphDefaultConfig = {
4444
showMetaOnNarrowScreens: false,
4545
showLabelsAtZoomLevel: 13,
4646
showGraphLabelsAtZoom: null,
47-
crs: CRS.EPSG3857,
4847
echartsOption: {
4948
aria: {
5049
show: true,
@@ -354,9 +353,19 @@ const NetJSONGraphDefaultConfig = {
354353
* @this {object} The instantiated object of NetJSONGraph
355354
*
356355
*/
357-
/* istanbul ignore next */
358356
onReady() {},
359357
};
360358

359+
const config = {...NetJSONGraphDefaultConfig};
360+
361+
Object.defineProperty(config, "crs", {
362+
get() {
363+
const L = getLeaflet();
364+
return L ? L.CRS.EPSG3857 : null;
365+
},
366+
enumerable: true,
367+
configurable: true,
368+
});
369+
361370
export const {prepareData} = NetJSONGraphDefaultConfig;
362-
export default {...NetJSONGraphDefaultConfig};
371+
export default config;

src/js/netjsongraph.geojson.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {geoJSON} from "leaflet";
1+
import getLeaflet from "./leaflet-loader";
22
/*
33
* Dedicated GeoJSON utilities for netjsongraph.js.
44
*/
@@ -133,6 +133,12 @@ export function addPolygonOverlays(self) {
133133
return; // nothing to do
134134
}
135135

136+
const L = getLeaflet();
137+
if (!L) {
138+
return;
139+
}
140+
const {geoJSON} = L;
141+
136142
const map = self.leaflet; // Leaflet map instance
137143
const polygonFeatures = self.originalGeoJSON.features.filter(
138144
(f) =>

0 commit comments

Comments
 (0)