UNPKG

3.76 kBJavaScriptView Raw
1const path = require('path');
2const fs = require('fs');
3const http = require('http');
4
5const WebSocket = require('ws');
6const _ = require('lodash');
7const express = require('express');
8const ejs = require('ejs');
9const opener = require('opener');
10const mkdir = require('mkdirp');
11const { bold } = require('chalk');
12
13const Logger = require('./Logger');
14const analyzer = require('./analyzer');
15
16const projectRoot = path.resolve(__dirname, '..');
17
18module.exports = {
19 startServer,
20 generateReport,
21 // deprecated
22 start: startServer
23};
24
25async function startServer(bundleStats, opts) {
26 const {
27 port = 8888,
28 host = '127.0.0.1',
29 openBrowser = true,
30 bundleDir = null,
31 logger = new Logger(),
32 defaultSizes = 'parsed'
33 } = opts || {};
34
35 let chartData = getChartData(logger, bundleStats, bundleDir);
36
37 if (!chartData) return;
38
39 const app = express();
40
41 // Explicitly using our `ejs` dependency to render templates
42 // Fixes #17
43 app.engine('ejs', require('ejs').renderFile);
44 app.set('view engine', 'ejs');
45 app.set('views', `${projectRoot}/views`);
46 app.use(express.static(`${projectRoot}/public`));
47
48 app.use('/', (req, res) => {
49 res.render('viewer', {
50 mode: 'server',
51 get chartData() { return JSON.stringify(chartData) },
52 defaultSizes: JSON.stringify(defaultSizes)
53 });
54 });
55
56 const server = http.createServer(app);
57
58 await new Promise(resolve => {
59 server.listen(port, host, () => {
60 resolve();
61
62 const url = `http://${host}:${server.address().port}`;
63
64 logger.info(
65 `${bold('Webpack Bundle Analyzer')} is started at ${bold(url)}\n` +
66 `Use ${bold('Ctrl+C')} to close it`
67 );
68
69 if (openBrowser) {
70 opener(url);
71 }
72 });
73 });
74
75 const wss = new WebSocket.Server({ server });
76
77 return {
78 ws: wss,
79 http: server,
80 updateChartData
81 };
82
83 function updateChartData(bundleStats) {
84 const newChartData = getChartData(logger, bundleStats, bundleDir);
85
86 if (!newChartData) return;
87
88 chartData = newChartData;
89
90 wss.clients.forEach(client => {
91 if (client.readyState === WebSocket.OPEN) {
92 client.send(JSON.stringify({
93 event: 'chartDataUpdated',
94 data: newChartData
95 }));
96 }
97 });
98 }
99}
100
101function generateReport(bundleStats, opts) {
102 const {
103 openBrowser = true,
104 reportFilename = 'report.html',
105 bundleDir = null,
106 logger = new Logger(),
107 defaultSizes = 'parsed'
108 } = opts || {};
109
110 const chartData = getChartData(logger, bundleStats, bundleDir);
111
112 if (!chartData) return;
113
114 ejs.renderFile(
115 `${projectRoot}/views/viewer.ejs`,
116 {
117 mode: 'static',
118 chartData: JSON.stringify(chartData),
119 assetContent: getAssetContent,
120 defaultSizes: JSON.stringify(defaultSizes)
121 },
122 (err, reportHtml) => {
123 if (err) return logger.error(err);
124
125 const reportFilepath = path.resolve(bundleDir || process.cwd(), reportFilename);
126
127 mkdir.sync(path.dirname(reportFilepath));
128 fs.writeFileSync(reportFilepath, reportHtml);
129
130 logger.info(
131 `${bold('Webpack Bundle Analyzer')} saved report to ${bold(reportFilepath)}`
132 );
133
134 if (openBrowser) {
135 opener(`file://${reportFilepath}`);
136 }
137 }
138 );
139}
140
141function getAssetContent(filename) {
142 return fs.readFileSync(`${projectRoot}/public/${filename}`, 'utf8');
143}
144
145function getChartData(logger, ...args) {
146 let chartData;
147
148 try {
149 chartData = analyzer.getViewerData(...args, { logger });
150 } catch (err) {
151 logger.error(`Could't analyze webpack bundle:\n${err}`);
152 chartData = null;
153 }
154
155 if (_.isEmpty(chartData)) {
156 logger.error("Could't find any javascript bundles in provided stats file");
157 chartData = null;
158 }
159
160 return chartData;
161}