"use strict"; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const path = require('path'); const fs = require('fs'); const http = require('http'); const WebSocket = require('ws'); const _ = require('lodash'); const express = require('express'); const ejs = require('ejs'); const opener = require('opener'); const mkdir = require('mkdirp'); const { bold } = require('chalk'); const Logger = require('./Logger'); const analyzer = require('./analyzer'); const projectRoot = path.resolve(__dirname, '..'); const assetsRoot = path.join(projectRoot, 'public'); function resolveTitle(reportTitle) { if (typeof reportTitle === 'function') { return reportTitle(); } else { return reportTitle; } } module.exports = { startServer, generateReport, generateJSONReport, // deprecated start: startServer }; function startServer(_x, _x2) { return _startServer.apply(this, arguments); } function _startServer() { _startServer = _asyncToGenerator(function* (bundleStats, opts) { const { port = 8888, host = '127.0.0.1', openBrowser = true, bundleDir = null, logger = new Logger(), defaultSizes = 'parsed', excludeAssets = null, reportTitle } = opts || {}; const analyzerOpts = { logger, excludeAssets }; let chartData = getChartData(analyzerOpts, bundleStats, bundleDir); if (!chartData) return; const app = express(); // Explicitly using our `ejs` dependency to render templates // Fixes #17 app.engine('ejs', require('ejs').renderFile); app.set('view engine', 'ejs'); app.set('views', `${projectRoot}/views`); app.use(express.static(`${projectRoot}/public`)); app.use('/', (req, res) => { res.render('viewer', { mode: 'server', title: resolveTitle(reportTitle), get chartData() { return chartData; }, defaultSizes, enableWebSocket: true, // Helpers escapeJson }); }); const server = http.createServer(app); yield new Promise(resolve => { server.listen(port, host, () => { resolve(); const url = `http://${host}:${server.address().port}`; logger.info(`${bold('Webpack Bundle Analyzer')} is started at ${bold(url)}\n` + `Use ${bold('Ctrl+C')} to close it`); if (openBrowser) { opener(url); } }); }); const wss = new WebSocket.Server({ server }); wss.on('connection', ws => { ws.on('error', err => { // Ignore network errors like `ECONNRESET`, `EPIPE`, etc. if (err.errno) return; logger.info(err.message); }); }); return { ws: wss, http: server, updateChartData }; function updateChartData(bundleStats) { const newChartData = getChartData(analyzerOpts, bundleStats, bundleDir); if (!newChartData) return; chartData = newChartData; wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ event: 'chartDataUpdated', data: newChartData })); } }); } }); return _startServer.apply(this, arguments); } function generateReport(_x3, _x4) { return _generateReport.apply(this, arguments); } function _generateReport() { _generateReport = _asyncToGenerator(function* (bundleStats, opts) { const { openBrowser = true, reportFilename, reportTitle, bundleDir = null, logger = new Logger(), defaultSizes = 'parsed', excludeAssets = null } = opts || {}; const chartData = getChartData({ logger, excludeAssets }, bundleStats, bundleDir); if (!chartData) return; yield new Promise((resolve, reject) => { ejs.renderFile(`${projectRoot}/views/viewer.ejs`, { mode: 'static', title: resolveTitle(reportTitle), chartData, defaultSizes, enableWebSocket: false, // Helpers assetContent: getAssetContent, escapeJson }, (err, reportHtml) => { try { if (err) { logger.error(err); reject(err); return; } const reportFilepath = path.resolve(bundleDir || process.cwd(), reportFilename); mkdir.sync(path.dirname(reportFilepath)); fs.writeFileSync(reportFilepath, reportHtml); logger.info(`${bold('Webpack Bundle Analyzer')} saved report to ${bold(reportFilepath)}`); if (openBrowser) { opener(`file://${reportFilepath}`); } resolve(); } catch (e) { reject(e); } }); }); }); return _generateReport.apply(this, arguments); } function generateJSONReport(_x5, _x6) { return _generateJSONReport.apply(this, arguments); } function _generateJSONReport() { _generateJSONReport = _asyncToGenerator(function* (bundleStats, opts) { const { reportFilename, bundleDir = null, logger = new Logger(), excludeAssets = null } = opts || {}; const chartData = getChartData({ logger, excludeAssets }, bundleStats, bundleDir); if (!chartData) return; mkdir.sync(path.dirname(reportFilename)); fs.writeFileSync(reportFilename, JSON.stringify(chartData)); logger.info(`${bold('Webpack Bundle Analyzer')} saved JSON report to ${bold(reportFilename)}`); }); return _generateJSONReport.apply(this, arguments); } function getAssetContent(filename) { const assetPath = path.join(assetsRoot, filename); if (!assetPath.startsWith(assetsRoot)) { throw new Error(`"${filename}" is outside of the assets root`); } return fs.readFileSync(assetPath, 'utf8'); } /** * Escapes `<` characters in JSON to safely use it in `