--footer esbuild & rollup style! (#14396)

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
versecafe
2024-10-08 02:32:37 -07:00
committed by GitHub
parent a234e067a5
commit 7996d06b8f
9 changed files with 93 additions and 9 deletions

View File

@@ -1092,7 +1092,7 @@ $ bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:file
### `banner`
A banner to be added to the final bundle, this can be a directive like "use client" for react or a comment block such as a license for the code.
A banner to be added to the final bundle, this can be a directive like "use client" for react or a comment block such as a license for the code.
{% codetabs %}
@@ -1108,11 +1108,29 @@ await Bun.build({
$ bun build ./index.tsx --outdir ./out --banner "\"use client\";"
```
### `footer`
A footer to be added to the final bundle, this can be something like a comment block for a license or just a fun easter egg.
{% codetabs %}
```ts#JavaScript
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
footer: '// built with love in SF'
})
```
```bash#CLI
$ bun build ./index.tsx --outdir ./out --footer="// built with love in SF"
```
{% /codetabs %}
### `experimentalCss`
Whether to enable *experimental* support for bundling CSS files. Defaults to `false`.
Whether to enable _experimental_ support for bundling CSS files. Defaults to `false`.
This supports bundling CSS files imported from JS, as well as CSS entrypoints.

View File

@@ -159,6 +159,12 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
---
- `--footer`
- `--footer`
- Only applies to js bundles
---
- `--certfile`
- n/a
- Not applicable
@@ -195,12 +201,6 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
---
- `--footer`
- n/a
- Not supported
---
- `--global-name`
- n/a
- Not applicable, Bun does not support `iife` output at this time

View File

@@ -1599,6 +1599,12 @@ declare module "bun" {
* Add a banner to the bundled code such as "use client";
*/
banner?: string;
/**
* Add a footer to the bundled code such as a comment block like
*
* `// made with bun!`
*/
footer?: string;
/**
* **Experimental**

View File

@@ -73,6 +73,7 @@ pub const JSBundler = struct {
format: options.Format = .esm,
bytecode: bool = false,
banner: OwnedString = OwnedString.initEmpty(bun.default_allocator),
footer: OwnedString = OwnedString.initEmpty(bun.default_allocator),
experimental_css: bool = false,
pub const List = bun.StringArrayHashMapUnmanaged(Config);
@@ -190,6 +191,12 @@ pub const JSBundler = struct {
try this.banner.appendSliceExact(slice.slice());
}
if (try config.getOptional(globalThis, "footer", ZigString.Slice)) |slice| {
defer slice.deinit();
try this.footer.appendSliceExact(slice.slice());
}
if (config.getTruthy(globalThis, "sourcemap")) |source_map_js| {
if (bun.FeatureFlags.breaking_changes_1_2 and config.isBoolean()) {
if (source_map_js == .true) {

View File

@@ -876,6 +876,7 @@ pub const BundleV2 = struct {
this.linker.options.ignore_dce_annotations = bundler.options.ignore_dce_annotations;
this.linker.options.banner = bundler.options.banner;
this.linker.options.footer = bundler.options.footer;
this.linker.options.experimental_css = bundler.options.experimental_css;
@@ -1478,6 +1479,7 @@ pub const BundleV2 = struct {
bundler.options.ignore_dce_annotations = config.ignore_dce_annotations;
bundler.options.experimental_css = config.experimental_css;
bundler.options.banner = config.banner.toOwnedSlice();
bundler.options.footer = config.footer.toOwnedSlice();
bundler.configureLinker();
try bundler.configureDefines();
@@ -4602,6 +4604,7 @@ pub const LinkerContext = struct {
minify_syntax: bool = false,
minify_identifiers: bool = false,
banner: []const u8 = "",
footer: []const u8 = "",
experimental_css: bool = false,
source_maps: options.SourceMapOption = .none,
target: options.Target = .browser,
@@ -8977,7 +8980,16 @@ pub const LinkerContext = struct {
j.ensureNewlineAtEnd();
// TODO: maybeAppendLegalComments
// TODO: footer
if (c.options.footer.len > 0) {
if (newline_before_comment) {
j.pushStatic("\n");
line_offset.advance("\n");
}
j.pushStatic(ctx.c.options.footer);
line_offset.advance(ctx.c.options.footer);
j.pushStatic("\n");
line_offset.advance("\n");
}
chunk.intermediate_output = c.breakOutputIntoPieces(
worker.allocator,

View File

@@ -263,6 +263,7 @@ pub const Arguments = struct {
clap.parseParam("--outfile <STR> Write to a file") catch unreachable,
clap.parseParam("--sourcemap <STR>? Build with sourcemaps - 'linked', 'inline', 'external', or 'none'") catch unreachable,
clap.parseParam("--banner <STR> Add a banner to the bundled output such as \"use client\"; for a bundle being used with RSCs") catch unreachable,
clap.parseParam("--footer <STR> Add a footer to the bundled output such as // built with bun!") catch unreachable,
clap.parseParam("--format <STR> Specifies the module format to build to. Only \"esm\" is supported.") catch unreachable,
clap.parseParam("--root <STR> Root directory used for multiple entry points") catch unreachable,
clap.parseParam("--splitting Enable code splitting") catch unreachable,
@@ -783,6 +784,10 @@ pub const Arguments = struct {
ctx.bundler_options.banner = banner;
}
if (args.option("--footer")) |footer| {
ctx.bundler_options.footer = footer;
}
const experimental_css = args.flag("--experimental-css");
ctx.bundler_options.experimental_css = experimental_css;
@@ -1408,6 +1413,7 @@ pub const Command = struct {
output_format: options.Format = .esm,
bytecode: bool = false,
banner: []const u8 = "",
footer: []const u8 = "",
experimental_css: bool = false,
};

View File

@@ -98,6 +98,8 @@ pub const BuildCommand = struct {
this_bundler.options.ignore_dce_annotations = ctx.bundler_options.ignore_dce_annotations;
this_bundler.options.banner = ctx.bundler_options.banner;
this_bundler.options.footer = ctx.bundler_options.footer;
this_bundler.options.experimental_css = ctx.bundler_options.experimental_css;
this_bundler.options.output_dir = ctx.bundler_options.outdir;

View File

@@ -0,0 +1,29 @@
import { describe } from "bun:test";
import { itBundled } from "./expectBundled";
describe("bundler", () => {
itBundled("footer/CommentFooter", {
footer: "// developed with love in SF",
files: {
"/a.js": `console.log("Hello, world!")`,
},
onAfterBundle(api) {
api.expectFile("out.js").toEndWith('// developed with love in SF"\n');
},
});
itBundled("footer/MultilineFooter", {
footer: `/**
* This is copyright of [...] ${new Date().getFullYear()}
* do not redistribute without consent of [...]
*/`,
files: {
"index.js": `console.log("Hello, world!")`,
},
onAfterBundle(api) {
api.expectFile("out.js").toEndWith(`/**
* This is copyright of [...] ${new Date().getFullYear()}
* do not redistribute without consent of [...]
*/\"\n`);
},
});
});

View File

@@ -146,6 +146,7 @@ export interface BundlerTestInput {
alias?: Record<string, string>;
assetNaming?: string;
banner?: string;
footer?: string;
define?: Record<string, string | number>;
/** Use for resolve custom conditions */
@@ -416,6 +417,7 @@ function expectBundled(
external,
packages,
files,
footer,
format,
globalName,
inject,
@@ -666,6 +668,7 @@ function expectBundled(
serverComponents && "--server-components",
outbase && `--root=${outbase}`,
banner && `--banner="${banner}"`, // TODO: --banner-css=*
footer && `--footer="${footer}"`,
ignoreDCEAnnotations && `--ignore-dce-annotations`,
emitDCEAnnotations && `--emit-dce-annotations`,
// inject && inject.map(x => ["--inject", path.join(root, x)]),
@@ -710,6 +713,7 @@ function expectBundled(
metafile && `--metafile=${metafile}`,
sourceMap && `--sourcemap=${sourceMap}`,
banner && `--banner:js=${banner}`,
footer && `--footer:js=${footer}`,
legalComments && `--legal-comments=${legalComments}`,
ignoreDCEAnnotations && `--ignore-annotations`,
splitting && `--splitting`,