diff --git a/test/bundle.test.ts b/test/bundle.test.ts new file mode 100644 index 0000000000..fa515f9116 --- /dev/null +++ b/test/bundle.test.ts @@ -0,0 +1,98 @@ +import { fileURLToPath } from 'node:url' +import fsp from 'node:fs/promises' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' +import { execaCommand } from 'execa' +import { globby } from 'globby' +import { join } from 'pathe' +import { isWindows } from 'std-env' + +describe.skipIf(isWindows)('minimal nuxt application', () => { + const rootDir = fileURLToPath(new URL('./fixtures/minimal', import.meta.url)) + const publicDir = join(rootDir, '.output/public') + const serverDir = join(rootDir, '.output/server') + + const stats = { + client: { totalBytes: 0, files: [] as string[] }, + server: { totalBytes: 0, files: [] as string[] } + } + + beforeAll(async () => { + await execaCommand(`pnpm nuxi build ${rootDir}`) + }, 120 * 1000) + + afterAll(async () => { + await fsp.writeFile(join(rootDir, '.output/test-stats.json'), JSON.stringify(stats, null, 2)) + }) + + it('default client bundle size', async () => { + stats.client = await analyzeSizes('**/*.js', publicDir) + expect(stats.client.totalBytes).toBeLessThan(110000) + expect(stats.client.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(` + [ + "_nuxt/entry.js", + "_nuxt/error-404.js", + "_nuxt/error-500.js", + "_nuxt/error-component.js", + ] + `) + }) + + it('default server bundle size', async () => { + stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir) + expect(stats.server.totalBytes).toBeLessThan(120000) + + const modules = await analyzeSizes('node_modules/**/*', serverDir) + expect(modules.totalBytes).toBeLessThan(2700000) + + const packages = modules.files + .filter(m => m.endsWith('package.json')) + .map(m => m.replace('/package.json', '').replace('node_modules/', '')) + .sort() + expect(packages).toMatchInlineSnapshot(` + [ + "@babel/parser", + "@vue/compiler-core", + "@vue/compiler-dom", + "@vue/compiler-ssr", + "@vue/reactivity", + "@vue/runtime-core", + "@vue/runtime-dom", + "@vue/server-renderer", + "@vue/shared", + "@vueuse/shared", + "buffer-from", + "cookie-es", + "defu", + "destr", + "estree-walker", + "h3", + "hookable", + "node-fetch-native", + "ohash", + "ohmyfetch", + "pathe", + "radix3", + "scule", + "source-map", + "source-map-support", + "ufo", + "unctx", + "unenv", + "unstorage", + "vue", + "vue-bundle-renderer", + "vue-demi", + ] + `) + }) +}) + +async function analyzeSizes (pattern: string | string[], rootDir: string) { + const files: string[] = await globby(pattern, { cwd: rootDir }) + let totalBytes = 0 + for (const file of files) { + const bytes = Buffer.byteLength(await fsp.readFile(join(rootDir, file))) + totalBytes += bytes + } + return { files, totalBytes } +} diff --git a/test/fixtures/minimal/app.vue b/test/fixtures/minimal/app.vue new file mode 100644 index 0000000000..585f495151 --- /dev/null +++ b/test/fixtures/minimal/app.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/minimal/nuxt.config.ts b/test/fixtures/minimal/nuxt.config.ts new file mode 100644 index 0000000000..268da7f8c1 --- /dev/null +++ b/test/fixtures/minimal/nuxt.config.ts @@ -0,0 +1 @@ +export default defineNuxtConfig({}) diff --git a/test/fixtures/minimal/tsconfig.json b/test/fixtures/minimal/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/test/fixtures/minimal/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +}