mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Improve assets size (#5999)
It looks like : ``` Pages sizes after gzip: ┌ / (196 B) ├ /_app (11.5 kB) ├ /_error (4.44 kB) ├ /blog (196 B) └ /blog/page (195 B) ``` (style inspired from now-cli : https://github.com/zeit/now-cli/blob/canary/src/util/output/builds.js) I'll add dynamic chunks in a separate PR. @timneutkens Do you want to keep `_app` and `_error` or filter them out ? I think it's a good idea to keep them, because `_app` can get pretty large and it would encourage code splitting in that case.
This commit is contained in:
parent
7e12997af6
commit
ba95f7541c
|
@ -312,7 +312,7 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
||||||
!isServer && new PagesPlugin(),
|
!isServer && new PagesPlugin(),
|
||||||
isServer && new NextJsSsrImportPlugin(),
|
isServer && new NextJsSsrImportPlugin(),
|
||||||
target !== 'serverless' && isServer && new NextJsSSRModuleCachePlugin({outputPath}),
|
target !== 'serverless' && isServer && new NextJsSSRModuleCachePlugin({outputPath}),
|
||||||
!isServer && !dev && new AssetsSizePlugin({buildId, distDir})
|
!isServer && !dev && new AssetsSizePlugin(buildId, distDir)
|
||||||
].filter(Boolean)
|
].filter(Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 { gzip as _gzip } from 'zlib'
|
||||||
import { relative as pathRelative } from 'path'
|
import { relative as pathRelative } from 'path'
|
||||||
|
import { Compiler } from 'webpack'
|
||||||
import promisify from '../../../lib/promisify'
|
import promisify from '../../../lib/promisify'
|
||||||
import {
|
import { IS_BUNDLED_PAGE_REGEX, ROUTE_NAME_REGEX } from 'next-server/constants'
|
||||||
IS_BUNDLED_PAGE_REGEX,
|
|
||||||
BUILD_MANIFEST,
|
|
||||||
REACT_LOADABLE_MANIFEST
|
|
||||||
} from 'next-server/constants'
|
|
||||||
|
|
||||||
const gzip = promisify(_gzip)
|
const gzip = promisify(_gzip)
|
||||||
|
|
||||||
|
@ -26,7 +23,7 @@ const gzip = promisify(_gzip)
|
||||||
// It's been edited for the needs of this script
|
// It's been edited for the needs of this script
|
||||||
// See the LICENSE at the top of the file
|
// See the LICENSE at the top of the file
|
||||||
const UNITS = ['B', 'kB', 'MB']
|
const UNITS = ['B', 'kB', 'MB']
|
||||||
const prettyBytes = number => {
|
function prettyBytes(number: number): string {
|
||||||
const exponent = Math.min(
|
const exponent = Math.min(
|
||||||
Math.floor(Math.log10(number) / 3),
|
Math.floor(Math.log10(number) / 3),
|
||||||
UNITS.length - 1
|
UNITS.length - 1
|
||||||
|
@ -37,77 +34,59 @@ const prettyBytes = number => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AssetsSizePlugin {
|
export default class AssetsSizePlugin {
|
||||||
constructor ({ buildId, distDir }) {
|
buildId: string
|
||||||
|
distDir: string
|
||||||
|
|
||||||
|
constructor(buildId: string, distDir: string) {
|
||||||
this.buildId = buildId
|
this.buildId = buildId
|
||||||
this.distDir = distDir ? pathRelative(process.cwd(), distDir) + '/' : ''
|
this.distDir = distDir ? pathRelative(process.cwd(), distDir) + '/' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFilename (rawFilename) {
|
async printAssetsSize(assets: any) {
|
||||||
// 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) {
|
|
||||||
const sizes = await Promise.all(
|
const sizes = await Promise.all(
|
||||||
Object.keys(assets)
|
Object.keys(assets)
|
||||||
.filter(
|
.filter(filename => IS_BUNDLED_PAGE_REGEX.exec(filename))
|
||||||
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
|
|
||||||
})
|
|
||||||
.map(async 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 asset = assets[filename]
|
||||||
const size = (await gzip(asset.source())).length
|
const size = (await gzip(asset.source())).length
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filename,
|
filename,
|
||||||
|
page,
|
||||||
prettySize: prettyBytes(size)
|
prettySize: prettyBytes(size)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// find longest prettySize string size
|
sizes.sort((a, b) => {
|
||||||
const longestPrettySize = Math.max(
|
if (a.page > b.page) return 1
|
||||||
...sizes.map(({ prettySize }) => prettySize.length)
|
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) {
|
for (let i = 0; i < sizes.length; i++) {
|
||||||
const padding = ' '.repeat(longestPrettySize - prettySize.length)
|
const size = sizes[i]
|
||||||
const formattedSize = prettySize
|
const corner =
|
||||||
const formattedFilename = this.formatFilename(filename)
|
i === 0
|
||||||
|
? sizes.length === 1
|
||||||
message += ` ${padding}${formattedSize} ${formattedFilename}\n`
|
? '─'
|
||||||
|
: '┌'
|
||||||
|
: i === sizes.length - 1
|
||||||
|
? '└'
|
||||||
|
: '├'
|
||||||
|
message += `${corner} /${size.page} (${size.prettySize})\n`
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(message)
|
console.log(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
async apply (compiler) {
|
async apply(compiler: Compiler) {
|
||||||
compiler.hooks.afterEmit.tapPromise('AssetsSizePlugin', compilation =>
|
compiler.hooks.afterEmit.tapPromise('AssetsSizePlugin', compilation =>
|
||||||
this.printAssetsSize(compilation.assets).catch(console.error)
|
this.printAssetsSize(compilation.assets).catch(console.error)
|
||||||
)
|
)
|
Loading…
Reference in a new issue