1
0
Fork 0
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:
Luc 2019-01-06 23:42:09 +08:00 committed by Tim Neutkens
parent 7e12997af6
commit ba95f7541c
2 changed files with 33 additions and 54 deletions

View file

@ -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)
}

View file

@ -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)
)