UNPKG

4.66 kBJavaScriptView Raw
1const path = require('path');
2const fs = require('fs');
3const http = require('http');
4
5const WebSocket = require('ws');
6const sirv = require('sirv');
7const _ = require('lodash');
8const {bold} = require('chalk');
9
10const Logger = require('./Logger');
11const analyzer = require('./analyzer');
12const {open} = require('./utils');
13const {renderViewer} = require('./template');
14
15const projectRoot = path.resolve(__dirname, '..');
16
17function resolveTitle(reportTitle) {
18 if (typeof reportTitle === 'function') {
19 return reportTitle();
20 } else {
21 return reportTitle;
22 }
23}
24
25module.exports = {
26 startServer,
27 generateReport,
28 generateJSONReport,
29 // deprecated
30 start: startServer
31};
32
33async function startServer(bundleStats, opts) {
34 const {
35 port = 8888,
36 host = '127.0.0.1',
37 openBrowser = true,
38 bundleDir = null,
39 logger = new Logger(),
40 defaultSizes = 'parsed',
41 excludeAssets = null,
42 reportTitle
43 } = opts || {};
44
45 const analyzerOpts = {logger, excludeAssets};
46
47 let chartData = getChartData(analyzerOpts, bundleStats, bundleDir);
48
49 if (!chartData) return;
50
51 const sirvMiddleware = sirv(`${projectRoot}/public`, {
52 // disables caching and traverse the file system on every request
53 dev: true
54 });
55
56 const server = http.createServer((req, res) => {
57 if (req.method === 'GET' && req.url === '/') {
58 const html = renderViewer({
59 mode: 'server',
60 title: resolveTitle(reportTitle),
61 chartData,
62 defaultSizes,
63 enableWebSocket: true
64 });
65 res.writeHead(200, {'Content-Type': 'text/html'});
66 res.end(html);
67 } else {
68 sirvMiddleware(req, res);
69 }
70 });
71
72 await new Promise(resolve => {
73 server.listen(port, host, () => {
74 resolve();
75
76 const url = `http://${host}:${server.address().port}`;
77
78 logger.info(
79 `${bold('Webpack Bundle Analyzer')} is started at ${bold(url)}\n` +
80 `Use ${bold('Ctrl+C')} to close it`
81 );
82
83 if (openBrowser) {
84 open(url, logger);
85 }
86 });
87 });
88
89 const wss = new WebSocket.Server({server});
90
91 wss.on('connection', ws => {
92 ws.on('error', err => {
93 // Ignore network errors like `ECONNRESET`, `EPIPE`, etc.
94 if (err.errno) return;
95
96 logger.info(err.message);
97 });
98 });
99
100 return {
101 ws: wss,
102 http: server,
103 updateChartData
104 };
105
106 function updateChartData(bundleStats) {
107 const newChartData = getChartData(analyzerOpts, bundleStats, bundleDir);
108
109 if (!newChartData) return;
110
111 chartData = newChartData;
112
113 wss.clients.forEach(client => {
114 if (client.readyState === WebSocket.OPEN) {
115 client.send(JSON.stringify({
116 event: 'chartDataUpdated',
117 data: newChartData
118 }));
119 }
120 });
121 }
122}
123
124async function generateReport(bundleStats, opts) {
125 const {
126 openBrowser = true,
127 reportFilename,
128 reportTitle,
129 bundleDir = null,
130 logger = new Logger(),
131 defaultSizes = 'parsed',
132 excludeAssets = null
133 } = opts || {};
134
135 const chartData = getChartData({logger, excludeAssets}, bundleStats, bundleDir);
136
137 if (!chartData) return;
138
139 const reportHtml = renderViewer({
140 mode: 'static',
141 title: resolveTitle(reportTitle),
142 chartData,
143 defaultSizes,
144 enableWebSocket: false
145 });
146 const reportFilepath = path.resolve(bundleDir || process.cwd(), reportFilename);
147
148 fs.mkdirSync(path.dirname(reportFilepath), {recursive: true});
149 fs.writeFileSync(reportFilepath, reportHtml);
150
151 logger.info(`${bold('Webpack Bundle Analyzer')} saved report to ${bold(reportFilepath)}`);
152
153 if (openBrowser) {
154 open(`file://${reportFilepath}`, logger);
155 }
156}
157
158async function generateJSONReport(bundleStats, opts) {
159 const {reportFilename, bundleDir = null, logger = new Logger(), excludeAssets = null} = opts || {};
160
161 const chartData = getChartData({logger, excludeAssets}, bundleStats, bundleDir);
162
163 if (!chartData) return;
164
165 await fs.promises.mkdir(path.dirname(reportFilename), {recursive: true});
166 await fs.promises.writeFile(reportFilename, JSON.stringify(chartData));
167
168 logger.info(`${bold('Webpack Bundle Analyzer')} saved JSON report to ${bold(reportFilename)}`);
169}
170
171function getChartData(analyzerOpts, ...args) {
172 let chartData;
173 const {logger} = analyzerOpts;
174
175 try {
176 chartData = analyzer.getViewerData(...args, analyzerOpts);
177 } catch (err) {
178 logger.error(`Could't analyze webpack bundle:\n${err}`);
179 logger.debug(err.stack);
180 chartData = null;
181 }
182
183 if (_.isPlainObject(chartData) && _.isEmpty(chartData)) {
184 logger.error("Could't find any javascript bundles in provided stats file");
185 chartData = null;
186 }
187
188 return chartData;
189}