-
Notifications
You must be signed in to change notification settings - Fork 35
/
report.js
executable file
·106 lines (89 loc) · 2.93 KB
/
report.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env node
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
const path = require('path')
const fs = require('fs')
const gzSize = require('gzip-size')
const mkdirp = require('mkdirp')
const { getBuildOutputDirectory, getOptions } = require('./utils')
// Pull options from `package.json`
const options = getOptions()
const BUILD_OUTPUT_DIRECTORY = getBuildOutputDirectory(options)
// first we check to make sure that the build output directory exists
const nextMetaRoot = path.join(process.cwd(), BUILD_OUTPUT_DIRECTORY)
try {
fs.accessSync(nextMetaRoot, fs.constants.R_OK)
} catch (err) {
console.error(
`No build output found at "${nextMetaRoot}" - you may not have your working directory set correctly, or not have run "next build".`
)
process.exit(1)
}
// if so, we can import the build manifest
const buildMeta = require(path.join(nextMetaRoot, 'build-manifest.json'))
// this memory cache ensures we dont read any script file more than once
// bundles are often shared between pages
const memoryCache = {}
// since _app is the template that all other pages are rendered into,
// every page must load its scripts. we'll measure its size here
const globalBundle = buildMeta.pages['/_app']
const globalBundleSizes = getScriptSizes(globalBundle)
// next, we calculate the size of each page's scripts, after
// subtracting out the global scripts
const allPageSizes = Object.values(buildMeta.pages).reduce(
(acc, scriptPaths, i) => {
const pagePath = Object.keys(buildMeta.pages)[i]
const scriptSizes = getScriptSizes(
scriptPaths.filter((scriptPath) => !globalBundle.includes(scriptPath))
)
acc[pagePath] = scriptSizes
return acc
},
{}
)
// format and write the output
const rawData = JSON.stringify({
...allPageSizes,
__global: globalBundleSizes,
})
// log ouputs to the gh actions panel
console.log(rawData)
mkdirp.sync(path.join(nextMetaRoot, 'analyze/'))
fs.writeFileSync(
path.join(nextMetaRoot, 'analyze/__bundle_analysis.json'),
rawData
)
// --------------
// Util Functions
// --------------
// given an array of scripts, return the total of their combined file sizes
function getScriptSizes(scriptPaths) {
const res = scriptPaths.reduce(
(acc, scriptPath) => {
const [rawSize, gzipSize] = getScriptSize(scriptPath)
acc.raw += rawSize
acc.gzip += gzipSize
return acc
},
{ raw: 0, gzip: 0 }
)
return res
}
// given an individual path to a script, return its file size
function getScriptSize(scriptPath) {
const encoding = 'utf8'
const p = path.join(nextMetaRoot, scriptPath)
let rawSize, gzipSize
if (Object.keys(memoryCache).includes(p)) {
rawSize = memoryCache[p][0]
gzipSize = memoryCache[p][1]
} else {
const textContent = fs.readFileSync(p, encoding)
rawSize = Buffer.byteLength(textContent, encoding)
gzipSize = gzSize.sync(textContent)
memoryCache[p] = [rawSize, gzipSize]
}
return [rawSize, gzipSize]
}