Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for banner and footer #531

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/esbuild/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Options:
is browser and cjs when platform is node)
--splitting Enable code splitting (currently only for esm)
--global-name=... The name of the global for the IIFE format
--banner=... Text to be prepended to each output file
--footer=... Text to be appended to each output file

--minify Sets all --minify-* flags
--minify-whitespace Remove whitespace
Expand Down
12 changes: 12 additions & 0 deletions internal/bundler/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -3400,6 +3400,13 @@ func (repr *chunkReprJS) generate(c *linkerContext, chunk *chunkInfo) func([]ast
}
}

if len(c.options.Banner) > 0 {
prevOffset.advanceString(c.options.Banner)
prevOffset.advanceString("\n")
j.AddString(c.options.Banner)
j.AddString("\n")
}

// Optionally wrap with an IIFE
if c.options.OutputFormat == config.FormatIIFE {
var text string
Expand Down Expand Up @@ -3634,6 +3641,11 @@ func (repr *chunkReprJS) generate(c *linkerContext, chunk *chunkInfo) func([]ast
j.AddString("\n")
}

if len(c.options.Footer) > 0 {
j.AddString(c.options.Footer)
j.AddString("\n")
}

if c.options.SourceMap != config.SourceMapNone {
sourceMap := c.generateSourceMapForChunk(compileResultsForSourceMap)

Expand Down
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ type Options struct {
PublicPath string
InjectAbsPaths []string
InjectedFiles []InjectedFile
Banner string
Footer string

Plugins []Plugin

Expand Down
5 changes: 5 additions & 0 deletions lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ function pushCommonFlags(flags: string[], options: CommonOptions, keys: OptionKe
let pure = getFlag(options, keys, 'pure', mustBeArray);
let avoidTDZ = getFlag(options, keys, 'avoidTDZ', mustBeBoolean);
let keepNames = getFlag(options, keys, 'keepNames', mustBeBoolean);
let banner = getFlag(options, keys, 'banner', mustBeString);
let footer = getFlag(options, keys, 'footer', mustBeString);

if (target) {
if (Array.isArray(target)) flags.push(`--target=${Array.from(target).map(validateTarget).join(',')}`)
Expand All @@ -114,6 +116,9 @@ function pushCommonFlags(flags: string[], options: CommonOptions, keys: OptionKe
if (pure) for (let fn of pure) flags.push(`--pure:${fn}`);
if (avoidTDZ) flags.push(`--avoid-tdz`);
if (keepNames) flags.push(`--keep-names`);

if (banner) flags.push(`--banner=${banner}`);
if (footer) flags.push(`--footer=${footer}`);
}

function flagsForBuildOptions(options: types.BuildOptions, isTTY: boolean, logLevelDefault: types.LogLevel):
Expand Down
2 changes: 2 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ interface CommonOptions {
pure?: string[];
avoidTDZ?: boolean;
keepNames?: boolean;
banner?: string;
footer?: string;

color?: boolean;
logLevel?: LogLevel;
Expand Down
4 changes: 4 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ type BuildOptions struct {
OutExtensions map[string]string
PublicPath string
Inject []string
Banner string
Footer string

EntryPoints []string
Stdin *StdinOptions
Expand Down Expand Up @@ -282,6 +284,8 @@ type TransformOptions struct {
JSXFactory string
JSXFragment string
TsconfigRaw string
Footer string
Banner string

Define map[string]string
Pure []string
Expand Down
4 changes: 4 additions & 0 deletions pkg/api/api_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ func buildImpl(buildOpts BuildOptions) BuildResult {
AvoidTDZ: buildOpts.AvoidTDZ,
KeepNames: buildOpts.KeepNames,
InjectAbsPaths: make([]string, len(buildOpts.Inject)),
Banner: buildOpts.Banner,
Footer: buildOpts.Footer,
}
for i, path := range buildOpts.Inject {
options.InjectAbsPaths[i] = validatePath(log, realFS, path)
Expand Down Expand Up @@ -728,6 +730,8 @@ func transformImpl(input string, transformOpts TransformOptions) TransformResult
Contents: input,
SourceFile: transformOpts.Sourcefile,
},
Banner: transformOpts.Banner,
Footer: transformOpts.Footer,
}
if options.SourceMap == config.SourceMapLinkedWithComment {
// Linked source maps don't make sense because there's no output file name
Expand Down
16 changes: 16 additions & 0 deletions pkg/cli/cli_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,22 @@ func parseOptionsImpl(osArgs []string, buildOpts *api.BuildOptions, transformOpt
transformOpts.JSXFragment = value
}

case strings.HasPrefix(arg, "--banner="):
value := arg[len("--banner="):]
if buildOpts != nil {
buildOpts.Banner = value
} else {
transformOpts.Banner = value
}

case strings.HasPrefix(arg, "--footer="):
value := arg[len("--footer="):]
if buildOpts != nil {
buildOpts.Footer = value
} else {
transformOpts.Footer = value
}

case strings.HasPrefix(arg, "--error-limit="):
value := arg[len("--error-limit="):]
limit, err := strconv.Atoi(value)
Expand Down
26 changes: 26 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,32 @@
)
}

// Test injecting banner and footer
tests.push(
test(['in.js', '--outfile=node.js', '--banner=const bannerDefined = true;'], {
'in.js': `if (!bannerDefined) throw 'fail'`
}),
test(['in.js', '--outfile=node.js', '--footer=function footer() { }'], {
'in.js': `footer()`
}),
test(['a.js', 'b.js', '--outdir=out', '--bundle', '--format=cjs', '--banner=const bannerDefined = true;', '--footer=function footer() { }'], {
'a.js': `
module.exports = { banner: bannerDefined, footer };
`,
'b.js': `
module.exports = { banner: bannerDefined, footer };
`,
'node.js': `
const a = require('./out/a');
const b = require('./out/b');

if (!a.banner || !b.banner) throw 'fail';
a.footer();
b.footer();
`
}),
)

// Test writing to stdout
tests.push(
// These should succeed
Expand Down
5 changes: 5 additions & 0 deletions scripts/verify-source-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ async function main() {
entryPoints: ['entry.js'],
crlf,
}),
check('banner-footer' + suffix, testCaseES6, toSearchBundle, {
flags: flags.concat('--outfile=out.js', '--bundle', '--banner="/* LICENSE abc */"', '--footer="/* end of file banner */"'),
entryPoints: ['a.js'],
crlf,
}),
)
}
}
Expand Down