Skip to content

Commit 68ed674

Browse files
committed
[chore] Add different build variants support
Signed-off-by: Sankalp <[email protected]>
1 parent 32ea2ab commit 68ed674

File tree

5 files changed

+215
-60
lines changed

5 files changed

+215
-60
lines changed

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,48 @@ yarn install
2121
yarn start
2222
```
2323

24+
## Build Variants
25+
26+
NetJSONGraph.js offers **3 optimized build variants** to match different integration needs:
27+
28+
### **Chunked Build**
29+
30+
```bash
31+
yarn build:chunks
32+
```
33+
34+
**Output**: Separate files for optimal loading
35+
36+
- `netjsongraph.[hash].min.js` - Core library
37+
- `echarts.[hash].min.js` - Graph rendering
38+
- `leaflet.[hash].min.js` - Map rendering
39+
40+
**Best for**: Large applications with conditional loading
41+
42+
### **ECharts Bundle**
43+
44+
```bash
45+
yarn build:echarts
46+
```
47+
48+
**Output**: Single file optimized for graphs
49+
50+
- `netjsongraph-with-echarts.[hash].min.js`
51+
52+
**Best for**: Pages showing only network topology graphs
53+
54+
### **Complete Bundle**
55+
56+
```bash
57+
yarn build:complete
58+
```
59+
60+
**Output**: Single file with all features
61+
62+
- `netjsongraph-complete.[hash].min.js`
63+
64+
**Best for**: Pages with both graphs and maps
65+
2466
### Run Tests
2567

2668
The test suite includes browser tests, so **ensure that ChromeDriver is installed** before running them.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
"dev": "webpack serve --open --mode development",
1010
"start": "yarn dev",
1111
"build": "webpack --progress --mode production",
12+
"build:chunks": "webpack --progress --mode production --env BUILD_TYPE=chunks",
13+
"build:echarts": "webpack --progress --mode production --env BUILD_TYPE=echarts-bundle",
14+
"build:complete": "webpack --progress --mode production --env BUILD_TYPE=complete-bundle",
15+
"build:all": "yarn build:chunks && yarn build:echarts && yarn build:complete",
1216
"coverage": "jest --silent --coverage",
1317
"coveralls": "jest --silent -f ./coverage/lcov.info && cat ./coverage/lcov.info | coveralls || echo 'no coverage file found'",
1418
"precommit": "lint-staged",

src/js/netjsongraph.gui.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,21 @@ class NetJSONGraphGUI {
236236
keyLabel.setAttribute("class", "njg-keyLabel");
237237
const valueLabel = document.createElement("span");
238238
valueLabel.setAttribute("class", "njg-valueLabel");
239-
keyLabel.innerHTML = formatKeyLabel(key);
240-
const displayVal =
241-
typeof val === "string" ? val.replace(/\n/g, "<br/>") : String(val);
242-
valueLabel.innerHTML = displayVal;
239+
if (key === "location") {
240+
keyLabel.innerHTML = "Location";
241+
valueLabel.innerHTML = `${Math.round(data[key].lat * 1000) / 1000}, ${
242+
Math.round(data[key].lng * 1000) / 1000
243+
}`;
244+
} else if (key === "localAddresses") {
245+
keyLabel.innerHTML = "Local Addresses";
246+
valueLabel.innerHTML = data[key].join("<br/>");
247+
} else {
248+
keyLabel.innerHTML = key;
249+
// Preserve multiline values
250+
const displayVal = typeof val === "string" ? val.replace(/\n/g, "<br/>") : val;
251+
valueLabel.innerHTML = displayVal;
252+
}
253+
243254
infoItems.appendChild(keyLabel);
244255
infoItems.appendChild(valueLabel);
245256
parent.appendChild(infoItems);

src/js/netjsongraph.js

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1+
/* eslint-disable no-undef */
12
import NetJSONGraphCore from "./netjsongraph.core";
2-
import {NetJSONGraphRender, echarts, L} from "./netjsongraph.render";
3-
import registerLeafletSystem from "../../lib/js/echarts-leaflet/index";
3+
import {NetJSONGraphRender, echarts} from "./netjsongraph.render";
44
import NetJSONGraphGUI from "./netjsongraph.gui";
55
import attachClientsOverlay from "./netjsongraph.clients";
66

7+
let L;
8+
let registerLeafletSystem;
9+
if (typeof __INCLUDE_LEAFLET__ !== "undefined" && __INCLUDE_LEAFLET__) {
10+
// eslint-disable-next-line import/no-dynamic-require,global-require
11+
const renderModule = require("./netjsongraph.render");
12+
// eslint-disable-next-line import/no-dynamic-require,global-require
13+
const leafletModule = require("../../lib/js/echarts-leaflet/index");
14+
L = renderModule.L;
15+
registerLeafletSystem = leafletModule.default;
16+
}
17+
718
const colorTool = require("zrender/lib/tool/color");
819
const {each} = require("zrender/lib/core/util");
920
const env = require("zrender/lib/core/env");
@@ -36,12 +47,25 @@ class NetJSONGraph {
3647
* @returns {Object} - The final configuration object.
3748
*/
3849
initializeConfig(config = {}) {
50+
let renderFunction;
51+
if (config.render === "map") {
52+
if (typeof __INCLUDE_LEAFLET__ !== "undefined" && __INCLUDE_LEAFLET__) {
53+
renderFunction = NetJSONGraphRender.prototype.mapRender;
54+
} else {
55+
const buildType =
56+
typeof __BUILD_TYPE__ !== "undefined" ? __BUILD_TYPE__ : "unknown";
57+
console.warn(
58+
`Map rendering not available in ${buildType} bundle. Use complete bundle or chunked build.`,
59+
);
60+
renderFunction = NetJSONGraphRender.prototype.graphRender;
61+
}
62+
} else {
63+
renderFunction = NetJSONGraphRender.prototype.graphRender;
64+
}
65+
3966
return {
4067
...config,
41-
render:
42-
config.render === "map"
43-
? NetJSONGraphRender.prototype.mapRender
44-
: NetJSONGraphRender.prototype.graphRender,
68+
render: renderFunction,
4569
onInit: this.onInit,
4670
onRender: this.onRender,
4771
onUpdate: this.onUpdate,
@@ -123,33 +147,45 @@ class NetJSONGraph {
123147
this.gui.nodeLinkInfoContainer = this.gui.createNodeLinkInfoContainer();
124148
}
125149
if (this.config.switchMode && this.utils.isNetJSON(this.data)) {
126-
this.gui.renderModeSelector.onclick = () => {
127-
// Switch from map to graph mode, first clear canvasContainer and then render
128-
if (this.config.render === this.utils.mapRender) {
129-
this.config.render = this.utils.graphRender;
130-
const canvasContainer = this.echarts
131-
.getZr()
132-
.painter.getViewportRoot().parentNode;
133-
this.echarts.clear();
134-
this.utils.graphRender(this.data, this);
135-
canvasContainer.style.background =
136-
// eslint-disable-next-line no-underscore-dangle
137-
this.echarts.getZr()._backgroundColor;
138-
139-
// Hide Openstreetmap credits in the bottom right corner
140-
document.querySelector(".leaflet-control-attribution").style.display = "none";
141-
// Hide zoom control buttons in top right corner
142-
document.querySelector(".leaflet-control-zoom").style.display = "none";
143-
} else {
144-
this.echarts.clear();
145-
this.config.render = this.utils.mapRender;
146-
this.utils.mapRender(this.data, this);
147-
// Show OpenStreetMap credits and zoom control buttons in map mode
148-
document.querySelector(".leaflet-control-attribution").style.display =
149-
"block";
150-
document.querySelector(".leaflet-control-zoom").style.display = "block";
151-
}
152-
};
150+
if (
151+
typeof __INCLUDE_MAP_SWITCHING__ !== "undefined" &&
152+
__INCLUDE_MAP_SWITCHING__
153+
) {
154+
this.gui.renderModeSelector.onclick = () => {
155+
// Switch from map to graph mode, first clear canvasContainer and then render
156+
if (this.config.render === this.utils.mapRender) {
157+
this.config.render = this.utils.graphRender;
158+
const canvasContainer = this.echarts
159+
.getZr()
160+
.painter.getViewportRoot().parentNode;
161+
this.echarts.clear();
162+
this.utils.graphRender(this.data, this);
163+
canvasContainer.style.background =
164+
// eslint-disable-next-line no-underscore-dangle
165+
this.echarts.getZr()._backgroundColor;
166+
167+
// Hide Openstreetmap credits in the bottom right corner
168+
document.querySelector(".leaflet-control-attribution").style.display =
169+
"none";
170+
// Hide zoom control buttons in top right corner
171+
document.querySelector(".leaflet-control-zoom").style.display = "none";
172+
} else {
173+
this.echarts.clear();
174+
this.config.render = this.utils.mapRender;
175+
this.utils.mapRender(this.data, this);
176+
// Show OpenStreetMap credits and zoom control buttons in map mode
177+
document.querySelector(".leaflet-control-attribution").style.display =
178+
"block";
179+
document.querySelector(".leaflet-control-zoom").style.display = "block";
180+
}
181+
};
182+
} else {
183+
const buildType =
184+
typeof __BUILD_TYPE__ !== "undefined" ? __BUILD_TYPE__ : "unknown";
185+
console.warn(
186+
`switchMode not available in ${buildType} bundle - map rendering not included`,
187+
);
188+
}
153189
}
154190
this.utils.hideLoading.call(this);
155191

@@ -160,12 +196,17 @@ class NetJSONGraph {
160196
}
161197
}
162198

163-
registerLeafletSystem(echarts, L, {
164-
colorTool,
165-
each,
166-
env,
167-
});
199+
if (typeof __INCLUDE_LEAFLET__ !== "undefined" && __INCLUDE_LEAFLET__) {
200+
registerLeafletSystem(echarts, L, {
201+
colorTool,
202+
each,
203+
env,
204+
});
205+
window.L = L;
206+
} else {
207+
const buildType = typeof __BUILD_TYPE__ !== "undefined" ? __BUILD_TYPE__ : "unknown";
208+
console.info(`NetJSONGraph ${buildType} Bundle loaded - Graph rendering only`);
209+
}
168210

169211
window.NetJSONGraph = NetJSONGraph;
170212
window.echarts = echarts;
171-
window.L = L;

webpack.config.js

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const path = require("path");
22
const fs = require("fs");
3+
const webpack = require("webpack");
34
const TerserPlugin = require("terser-webpack-plugin");
45
const HtmlWebpackPlugin = require("html-webpack-plugin");
56
const CopyPlugin = require("copy-webpack-plugin");
@@ -67,23 +68,19 @@ module.exports = (env, argv) => {
6768
const isProduction = argv.mode === "production";
6869
const isDevelopment = !isProduction;
6970

70-
return {
71-
entry: {
72-
netjsongraph: "./src/js/netjsongraph.js",
73-
},
74-
output: {
75-
path: path.resolve(__dirname, "dist"),
76-
filename: isProduction ? "[name].[contenthash:8].min.js" : "[name].js",
77-
chunkFilename: isProduction
78-
? "chunks/[name].[contenthash:8].chunk.js"
79-
: "chunks/[name].chunk.js",
80-
clean: true,
81-
publicPath: "/",
82-
},
83-
devtool: argv.mode === "development" ? "eval-source-map" : "source-map",
84-
optimization: {
85-
minimize: isProduction,
86-
minimizer: getMinimizers(isProduction),
71+
// Multi-build strategy: chunks, echarts-bundle, complete-bundle
72+
const buildType = env?.BUILD_TYPE || "chunks";
73+
74+
// Base entry configuration
75+
const baseEntry = {
76+
netjsongraph: "./src/js/netjsongraph.js",
77+
};
78+
79+
// Build-specific configurations
80+
const buildConfigs = {
81+
// Separate chunks
82+
chunks: {
83+
entry: baseEntry,
8784
splitChunks: {
8885
chunks: "all",
8986
cacheGroups: {
@@ -113,6 +110,56 @@ module.exports = (env, argv) => {
113110
},
114111
},
115112
},
113+
filename: isProduction ? "[name].[contenthash:8].min.js" : "[name].js",
114+
chunkFilename: isProduction
115+
? "chunks/[name].[contenthash:8].chunk.js"
116+
: "chunks/[name].chunk.js",
117+
buildType: "chunks",
118+
},
119+
120+
// Library + ECharts bundle (single file)
121+
"echarts-bundle": {
122+
entry: {
123+
"netjsongraph-with-echarts": "./src/js/netjsongraph.js", // Use main file
124+
},
125+
splitChunks: false,
126+
filename: isProduction ? "[name].[contenthash:8].min.js" : "[name].js",
127+
chunkFilename: isProduction
128+
? "bundles/[name].[contenthash:8].chunk.js"
129+
: "bundles/[name].chunk.js",
130+
buildType: "echarts-only",
131+
},
132+
133+
// Complete bundle (everything)
134+
"complete-bundle": {
135+
entry: {
136+
"netjsongraph-complete": "./src/js/netjsongraph.js",
137+
},
138+
splitChunks: false,
139+
filename: isProduction ? "[name].[contenthash:8].min.js" : "[name].js",
140+
chunkFilename: isProduction
141+
? "complete/[name].[contenthash:8].chunk.js"
142+
: "complete/[name].chunk.js",
143+
buildType: "complete",
144+
},
145+
};
146+
147+
const currentBuild = buildConfigs[buildType];
148+
149+
return {
150+
entry: currentBuild.entry,
151+
output: {
152+
path: path.resolve(__dirname, "dist"),
153+
filename: currentBuild.filename,
154+
chunkFilename: currentBuild.chunkFilename,
155+
clean: buildType === "chunks",
156+
publicPath: "/",
157+
},
158+
devtool: argv.mode === "development" ? "eval-source-map" : "source-map",
159+
optimization: {
160+
minimize: isProduction,
161+
minimizer: getMinimizers(isProduction),
162+
splitChunks: currentBuild.splitChunks,
116163
usedExports: true,
117164
sideEffects: false,
118165
providedExports: true,
@@ -162,6 +209,16 @@ module.exports = (env, argv) => {
162209
},
163210
},
164211
plugins: [
212+
// Define build-time constants for conditional compilation
213+
new webpack.DefinePlugin({
214+
__BUILD_TYPE__: JSON.stringify(currentBuild.buildType),
215+
__INCLUDE_LEAFLET__: JSON.stringify(
216+
currentBuild.buildType === "complete" || currentBuild.buildType === "chunks",
217+
),
218+
__INCLUDE_MAP_SWITCHING__: JSON.stringify(
219+
currentBuild.buildType === "complete" || currentBuild.buildType === "chunks",
220+
),
221+
}),
165222
...templates,
166223
new CopyPlugin({
167224
patterns: [

0 commit comments

Comments
 (0)