feat: make bundle analysis work with app dir
This commit is contained in:
parent
38fc128d62
commit
c7165fa2dc
4 changed files with 142 additions and 2 deletions
2
.github/workflows/nextjs_bundle_analysis.yml
vendored
2
.github/workflows/nextjs_bundle_analysis.yml
vendored
|
|
@ -51,7 +51,7 @@ jobs:
|
|||
# Here's the first place where next-bundle-analysis' own script is used
|
||||
# This step pulls the raw bundle stats for the current bundle
|
||||
- name: Analyze bundle
|
||||
run: npx -p nextjs-bundle-analysis report
|
||||
run: node report-bundle-size.js
|
||||
|
||||
- name: Upload bundle
|
||||
uses: actions/upload-artifact@v3
|
||||
|
|
|
|||
|
|
@ -97,8 +97,10 @@
|
|||
"eslint-plugin-storybook": "^0.6.15",
|
||||
"eslint-plugin-tailwindcss": "^3.13.0",
|
||||
"fetch-mock": "^9.11.0",
|
||||
"gzip-size": "6",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"mkdirp": "^3.0.1",
|
||||
"npm-only-allow": "^1.2.6",
|
||||
"patch-package": "^8.0.0",
|
||||
"postcss": "^8.4.31",
|
||||
|
|
|
|||
133
report-bundle-size.js
Normal file
133
report-bundle-size.js
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#!/usr/bin/env node
|
||||
/* eslint-disable no-console */
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
// edited to work with the appdir by @raphaelbadia
|
||||
|
||||
const gzSize = require("gzip-size")
|
||||
const mkdirp = require("mkdirp")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
// 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"))
|
||||
const appDirMeta = require(path.join(nextMetaRoot, "app-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
|
||||
}, {})
|
||||
|
||||
const globalAppDirBundle = buildMeta.rootMainFiles
|
||||
const globalAppDirBundleSizes = getScriptSizes(globalAppDirBundle)
|
||||
|
||||
const allAppDirSizes = Object.values(appDirMeta.pages).reduce((acc, scriptPaths, i) => {
|
||||
const pagePath = Object.keys(appDirMeta.pages)[i]
|
||||
const scriptSizes = getScriptSizes(scriptPaths.filter((scriptPath) => !globalAppDirBundle.includes(scriptPath)))
|
||||
acc[pagePath] = scriptSizes
|
||||
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
// format and write the output
|
||||
const rawData = JSON.stringify({
|
||||
...allAppDirSizes,
|
||||
__global: globalAppDirBundleSizes,
|
||||
})
|
||||
|
||||
// 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]
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads options from `package.json`
|
||||
*/
|
||||
function getOptions(pathPrefix = process.cwd()) {
|
||||
const pkg = require(path.join(pathPrefix, "package.json"))
|
||||
|
||||
return { ...pkg.nextBundleAnalysis, name: pkg.name }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output build directory, defaults to `.next`
|
||||
*
|
||||
* @param {object} options the options parsed from package.json.nextBundleAnalysis using `getOptions`
|
||||
* @returns {string}
|
||||
*/
|
||||
function getBuildOutputDirectory(options) {
|
||||
return options.buildOutputDirectory || ".next"
|
||||
}
|
||||
|
|
@ -9419,7 +9419,7 @@ gunzip-maybe@^1.4.2:
|
|||
pumpify "^1.3.3"
|
||||
through2 "^2.0.3"
|
||||
|
||||
gzip-size@^6.0.0:
|
||||
gzip-size@6, gzip-size@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
|
||||
integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
|
||||
|
|
@ -11813,6 +11813,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
|
|||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
mkdirp@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50"
|
||||
integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==
|
||||
|
||||
module-details-from-path@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue