diff --git a/README.md b/README.md index 8c32851..fafb0f2 100644 --- a/README.md +++ b/README.md @@ -991,6 +991,7 @@ export default config; | `sitemap` | `BunextSitemapConfig` | — | Options for `bunext sitemap` — see [Sitemap](#sitemap) | | `robots` | `BunextRobotsConfig \| false` | — | robots.txt options for `bunext sitemap`, or `false` to skip it — see [robots.txt](#robotstxt) | | `disable_seo` | `boolean` | `false` | Keep the whole site out of search engines (e.g. preview deployments) — see [Disabling SEO](#disabling-seo) | +| `minify_ssr_bundle` | `boolean` | `true` | Minify the SSR bundle. SSR output is served from local disk, not downloaded by browsers, so set `false` to cut build memory on constrained hosts. Never minified in dev | ### Middleware diff --git a/dist/functions/bundler/pages-ssr-context-bundler.js b/dist/functions/bundler/pages-ssr-context-bundler.js index f86c687..4bb431a 100644 --- a/dist/functions/bundler/pages-ssr-context-bundler.js +++ b/dist/functions/bundler/pages-ssr-context-bundler.js @@ -12,7 +12,8 @@ import { evictDeletedModules } from "../../utils/import-fresh"; import { writeFileSync } from "fs"; import path from "path"; import { log } from "../../utils/log"; -import { logBuildErrorsOnce, } from "../../utils/build-error-log"; +import { logBuildErrorsOnce } from "../../utils/build-error-log"; +import shouldMinifySSR from "../../utils/should-minify-ssr"; const { BUNX_CWD_MODULE_CACHE_DIR, BUNX_TMP_DIR } = grabDirNames(); // Current virtual entry contents. The SSR virtual plugin resolves its // onLoad contents lazily from this map on every rebuild, so edits to @@ -124,7 +125,9 @@ async function doSSRRebuild(params) { entryPoints, outdir: BUNX_CWD_MODULE_CACHE_DIR, bundle: true, - minify: !dev, + minify: shouldMinifySSR({ + minify_ssr_bundle: config.minify_ssr_bundle, + }), format: "esm", target: "esnext", platform: "node", diff --git a/dist/types/index.d.ts b/dist/types/index.d.ts index 075f831..e608343 100644 --- a/dist/types/index.d.ts +++ b/dist/types/index.d.ts @@ -114,6 +114,13 @@ export type BunextConfig = { * aborted and answered with a 500. Defaults to 30000. */ ssr_render_timeout_ms?: number; + /** + * Minify the SSR bundle. The SSR output is read off local disk by the + * server and is never downloaded by a browser, so minifying it only costs + * build memory. Set to `false` on memory-constrained hosts. Never minified + * in dev; defaults to `true` in production. + */ + minify_ssr_bundle?: boolean; }; export type BunextConfigMiddlewareParams = { req: Request; diff --git a/dist/utils/should-minify-ssr.d.ts b/dist/utils/should-minify-ssr.d.ts new file mode 100644 index 0000000..fa6b9c6 --- /dev/null +++ b/dist/utils/should-minify-ssr.d.ts @@ -0,0 +1,17 @@ +type Params = { + /** + * The value of `minify_ssr_bundle` in `bunext.config.ts` + * (`global.BUNEXT_CONFIG.minify_ssr_bundle`). + */ + minify_ssr_bundle?: boolean; +}; +/** + * Whether the SSR bundle should be minified. + * + * The SSR output is read off local disk by the server and is never downloaded + * by a browser, so minifying it only costs build memory. Dev is never minified. + * In production the bundle is minified unless `minify_ssr_bundle` is explicitly + * set to `false` in `bunext.config.ts`. + */ +export default function shouldMinifySSR(params?: Params): boolean; +export {}; diff --git a/dist/utils/should-minify-ssr.js b/dist/utils/should-minify-ssr.js new file mode 100644 index 0000000..59ee3c3 --- /dev/null +++ b/dist/utils/should-minify-ssr.js @@ -0,0 +1,14 @@ +import isDevelopment from "./is-development"; +/** + * Whether the SSR bundle should be minified. + * + * The SSR output is read off local disk by the server and is never downloaded + * by a browser, so minifying it only costs build memory. Dev is never minified. + * In production the bundle is minified unless `minify_ssr_bundle` is explicitly + * set to `false` in `bunext.config.ts`. + */ +export default function shouldMinifySSR(params = {}) { + if (isDevelopment()) + return false; + return params.minify_ssr_bundle !== false; +} diff --git a/package.json b/package.json index d907ca6..071cf6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@moduletrace/bunext", - "version": "1.3.3", + "version": "1.3.4", "main": "dist/index.js", "module": "index.ts", "dependencies": { diff --git a/src/__tests__/utils/should-minify-ssr.test.ts b/src/__tests__/utils/should-minify-ssr.test.ts new file mode 100644 index 0000000..752614c --- /dev/null +++ b/src/__tests__/utils/should-minify-ssr.test.ts @@ -0,0 +1,28 @@ +import { describe, it, expect, afterEach } from "bun:test"; +import shouldMinifySSR from "../../utils/should-minify-ssr"; + +const originalEnv = process.env.NODE_ENV; + +afterEach(() => { + process.env.NODE_ENV = originalEnv; +}); + +describe("shouldMinifySSR", () => { + it("never minifies in development", () => { + process.env.NODE_ENV = "development"; + expect(shouldMinifySSR()).toBe(false); + expect(shouldMinifySSR({ minify_ssr_bundle: true })).toBe(false); + expect(shouldMinifySSR({ minify_ssr_bundle: false })).toBe(false); + }); + + it("minifies in production by default", () => { + process.env.NODE_ENV = "production"; + expect(shouldMinifySSR()).toBe(true); + expect(shouldMinifySSR({ minify_ssr_bundle: true })).toBe(true); + }); + + it("skips minification when minify_ssr_bundle is false", () => { + process.env.NODE_ENV = "production"; + expect(shouldMinifySSR({ minify_ssr_bundle: false })).toBe(false); + }); +}); diff --git a/src/functions/bundler/pages-ssr-context-bundler.ts b/src/functions/bundler/pages-ssr-context-bundler.ts index f174308..532ce76 100644 --- a/src/functions/bundler/pages-ssr-context-bundler.ts +++ b/src/functions/bundler/pages-ssr-context-bundler.ts @@ -13,9 +13,8 @@ import { evictDeletedModules } from "../../utils/import-fresh"; import { writeFileSync } from "fs"; import path from "path"; import { log } from "../../utils/log"; -import { - logBuildErrorsOnce, -} from "../../utils/build-error-log"; +import { logBuildErrorsOnce } from "../../utils/build-error-log"; +import shouldMinifySSR from "../../utils/should-minify-ssr"; const { BUNX_CWD_MODULE_CACHE_DIR, BUNX_TMP_DIR } = grabDirNames(); @@ -174,7 +173,9 @@ async function doSSRRebuild(params?: RebuildParams) { entryPoints, outdir: BUNX_CWD_MODULE_CACHE_DIR, bundle: true, - minify: !dev, + minify: shouldMinifySSR({ + minify_ssr_bundle: config.minify_ssr_bundle, + }), format: "esm", target: "esnext", platform: "node", @@ -244,4 +245,4 @@ async function doSSRRebuild(params?: RebuildParams) { ); } } -} \ No newline at end of file +} diff --git a/src/types/index.ts b/src/types/index.ts index bb921d3..cb6b8b1 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -131,6 +131,13 @@ export type BunextConfig = { * aborted and answered with a 500. Defaults to 30000. */ ssr_render_timeout_ms?: number; + /** + * Minify the SSR bundle. The SSR output is read off local disk by the + * server and is never downloaded by a browser, so minifying it only costs + * build memory. Set to `false` on memory-constrained hosts. Never minified + * in dev; defaults to `true` in production. + */ + minify_ssr_bundle?: boolean; }; export type BunextConfigMiddlewareParams = { diff --git a/src/utils/should-minify-ssr.ts b/src/utils/should-minify-ssr.ts new file mode 100644 index 0000000..8c98c5a --- /dev/null +++ b/src/utils/should-minify-ssr.ts @@ -0,0 +1,22 @@ +import isDevelopment from "./is-development"; + +type Params = { + /** + * The value of `minify_ssr_bundle` in `bunext.config.ts` + * (`global.BUNEXT_CONFIG.minify_ssr_bundle`). + */ + minify_ssr_bundle?: boolean; +}; + +/** + * Whether the SSR bundle should be minified. + * + * The SSR output is read off local disk by the server and is never downloaded + * by a browser, so minifying it only costs build memory. Dev is never minified. + * In production the bundle is minified unless `minify_ssr_bundle` is explicitly + * set to `false` in `bunext.config.ts`. + */ +export default function shouldMinifySSR(params: Params = {}): boolean { + if (isDevelopment()) return false; + return params.minify_ssr_bundle !== false; +}