diff --git a/packages/next/build/webpack-config.js b/packages/next/build/webpack-config.js index 8bc71e45..15876147 100644 --- a/packages/next/build/webpack-config.js +++ b/packages/next/build/webpack-config.js @@ -312,7 +312,7 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer !isServer && new PagesPlugin(), isServer && new NextJsSsrImportPlugin(), target !== 'serverless' && isServer && new NextJsSSRModuleCachePlugin({outputPath}), - !isServer && !dev && new AssetsSizePlugin({buildId, distDir}) + !isServer && !dev && new AssetsSizePlugin(buildId, distDir) ].filter(Boolean) } diff --git a/packages/next/build/webpack/plugins/assets-size-plugin.js b/packages/next/build/webpack/plugins/assets-size-plugin.ts similarity index 60% rename from packages/next/build/webpack/plugins/assets-size-plugin.js rename to packages/next/build/webpack/plugins/assets-size-plugin.ts index 6087e178..e5aa786b 100644 --- a/packages/next/build/webpack/plugins/assets-size-plugin.js +++ b/packages/next/build/webpack/plugins/assets-size-plugin.ts @@ -13,12 +13,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI import { gzip as _gzip } from 'zlib' import { relative as pathRelative } from 'path' +import { Compiler } from 'webpack' import promisify from '../../../lib/promisify' -import { - IS_BUNDLED_PAGE_REGEX, - BUILD_MANIFEST, - REACT_LOADABLE_MANIFEST -} from 'next-server/constants' +import { IS_BUNDLED_PAGE_REGEX, ROUTE_NAME_REGEX } from 'next-server/constants' const gzip = promisify(_gzip) @@ -26,7 +23,7 @@ const gzip = promisify(_gzip) // It's been edited for the needs of this script // See the LICENSE at the top of the file const UNITS = ['B', 'kB', 'MB'] -const prettyBytes = number => { +function prettyBytes(number: number): string { const exponent = Math.min( Math.floor(Math.log10(number) / 3), UNITS.length - 1 @@ -37,77 +34,59 @@ const prettyBytes = number => { } export default class AssetsSizePlugin { - constructor ({ buildId, distDir }) { + buildId: string + distDir: string + + constructor(buildId: string, distDir: string) { this.buildId = buildId this.distDir = distDir ? pathRelative(process.cwd(), distDir) + '/' : '' } - formatFilename (rawFilename) { - // add distDir - let filename = this.distDir + rawFilename - - // shorten buildId - if (this.buildId) { - filename = filename.replace( - this.buildId + '/', - this.buildId.substring(0, 4) + '****/' - ) - } - - // shorten hashes - filename = filename.replace( - /(.*[-.])([0-9a-f]{8,})(\.js|\.css)/, - (_, c1, hash, c2) => c1 + hash.substring(0, 4) + '****' + c2 - ) - - return filename - } - - async printAssetsSize (assets) { + async printAssetsSize(assets: any) { const sizes = await Promise.all( Object.keys(assets) - .filter( - filename => - filename !== REACT_LOADABLE_MANIFEST && filename !== BUILD_MANIFEST - ) - .sort((a, b) => { - // put pages at the top, then the rest - const [pa, pb] = [a, b].map(x => IS_BUNDLED_PAGE_REGEX.exec(x)) - if (pa && !pb) return -1 - if (pb && !pa) return 1 - if (a > b) return 1 - return -1 - }) + .filter(filename => IS_BUNDLED_PAGE_REGEX.exec(filename)) .map(async filename => { + const search = filename.match(ROUTE_NAME_REGEX) + let page = search ? search[1] : filename + if (page.slice(-5) === 'index') { + page = page.slice(0, -5) + } const asset = assets[filename] const size = (await gzip(asset.source())).length return { filename, + page, prettySize: prettyBytes(size) } }) ) - // find longest prettySize string size - const longestPrettySize = Math.max( - ...sizes.map(({ prettySize }) => prettySize.length) - ) + sizes.sort((a, b) => { + if (a.page > b.page) return 1 + return -1 + }) - let message = '\nBrowser assets sizes after gzip:\n\n' + let message = '\nPages sizes after gzip:\n\n' - for (let { filename, prettySize } of sizes) { - const padding = ' '.repeat(longestPrettySize - prettySize.length) - const formattedSize = prettySize - const formattedFilename = this.formatFilename(filename) - - message += ` ${padding}${formattedSize} ${formattedFilename}\n` + for (let i = 0; i < sizes.length; i++) { + const size = sizes[i] + const corner = + i === 0 + ? sizes.length === 1 + ? '─' + : '┌' + : i === sizes.length - 1 + ? '└' + : '├' + message += `${corner} /${size.page} (${size.prettySize})\n` } console.log(message) } - async apply (compiler) { + async apply(compiler: Compiler) { compiler.hooks.afterEmit.tapPromise('AssetsSizePlugin', compilation => this.printAssetsSize(compilation.assets).catch(console.error) )