diff --git a/packages/esbuild/esbuild.bzl b/packages/esbuild/esbuild.bzl index f5d9aa5911..461c38f3a7 100644 --- a/packages/esbuild/esbuild.bzl +++ b/packages/esbuild/esbuild.bzl @@ -54,7 +54,12 @@ def _esbuild_impl(ctx): args = ctx.actions.args() args.add("--bundle", entry_point.path) - args.add("--sourcemap") + + if len(ctx.attr.sourcemap) > 0: + args.add_joined(["--sourcemap", ctx.attr.sourcemap], join_with = "=") + else: + args.add("--sourcemap") + args.add("--preserve-symlinks") args.add_joined(["--platform", ctx.attr.platform], join_with = "=") args.add_joined(["--target", ctx.attr.target], join_with = "=") @@ -87,8 +92,13 @@ def _esbuild_impl(ctx): args.add_joined(["--outdir", js_out.path], join_with = "=") else: js_out = ctx.outputs.output + outputs.append(js_out) + js_out_map = ctx.outputs.output_map - outputs.extend([js_out, js_out_map]) + if ctx.attr.sourcemap != "inline": + if js_out_map == None: + fail("output_map must be specified if sourcemap is not set to 'inline'") + outputs.append(js_out_map) if ctx.attr.format: args.add_joined(["--format", ctx.attr.format], join_with = "=") @@ -214,6 +224,14 @@ See https://esbuild.github.io/api/#splitting for more details See https://esbuild.github.io/api/#platform for more details """, ), + "sourcemap": attr.string( + values = ["external", "inline", "both"], + mandatory = False, + doc = """Defines where sourcemaps are output and how they are included in the bundle. By default, a separate `.js.map` file is generated and referenced by the bundle. If 'external', a separate `.js.map` file is generated but not referenced by the bundle. If 'inline', a sourcemap is generated and its contents are inlined into the bundle (and no external sourcemap file is created). If 'both', a sourcemap is inlined and a `.js.map` file is created. + +See https://esbuild.github.io/api/#sourcemap for more details + """, + ), "sources_content": attr.bool( mandatory = False, default = False, @@ -270,9 +288,13 @@ def esbuild_macro(name, output_dir = False, **kwargs): **kwargs ) else: + output_map = None + sourcemap = kwargs.get("sourcemap", None) + if sourcemap != "inline": + output_map = "%s.js.map" % name esbuild( name = name, output = "%s.js" % name, - output_map = "%s.js.map" % name, + output_map = output_map, **kwargs ) diff --git a/packages/esbuild/test/sourcemap/BUILD.bazel b/packages/esbuild/test/sourcemap/BUILD.bazel new file mode 100644 index 0000000000..7138fc8f27 --- /dev/null +++ b/packages/esbuild/test/sourcemap/BUILD.bazel @@ -0,0 +1,55 @@ +load("//packages/esbuild/test:tests.bzl", "esbuild") +load("//packages/jasmine:index.bzl", "jasmine_node_test") +load("//packages/typescript:index.bzl", "ts_library") + +ts_library( + name = "main", + srcs = [ + "main.ts", + ], + deps = [ + "@npm//@types/node", + ], +) + +esbuild( + name = "bundle_default", + args = ["--keep-names"], + entry_point = "main.ts", + deps = [":main"], +) + +esbuild( + name = "bundle_inline", + args = ["--keep-names"], + entry_point = "main.ts", + sourcemap = "inline", + deps = [":main"], +) + +esbuild( + name = "bundle_external", + args = ["--keep-names"], + entry_point = "main.ts", + sourcemap = "external", + deps = [":main"], +) + +esbuild( + name = "bundle_both", + args = ["--keep-names"], + entry_point = "main.ts", + sourcemap = "both", + deps = [":main"], +) + +jasmine_node_test( + name = "bundle_test", + srcs = ["bundle_test.js"], + data = [ + ":bundle_both", + ":bundle_default", + ":bundle_external", + ":bundle_inline", + ], +) diff --git a/packages/esbuild/test/sourcemap/bundle_test.js b/packages/esbuild/test/sourcemap/bundle_test.js new file mode 100644 index 0000000000..dd7ef34d5a --- /dev/null +++ b/packages/esbuild/test/sourcemap/bundle_test.js @@ -0,0 +1,62 @@ +const {readFileSync, exists} = require('fs'); +const path = require('path'); + +const helper = require(process.env.BAZEL_NODE_RUNFILES_HELPER); +const locationBase = 'build_bazel_rules_nodejs/packages/esbuild/test/sourcemap/'; + +// Location for :bundle_default +const bundleDefaultLocation = helper.resolve(path.join(locationBase, 'bundle_default.js')); +const bundleDefaultSourcemapLocation = + helper.resolve(path.join(locationBase, 'bundle_default.js.map')); + +// Location for :bundle_inline +const bundleInlineLocation = helper.resolve(path.join(locationBase, 'bundle_inline.js')); + +// Location for :bundle_external +const bundleExternalLocation = helper.resolve(path.join(locationBase, 'bundle_external.js')); +const bundleExternalSourcemapLocation = + helper.resolve(path.join(locationBase, 'bundle_external.js.map')); + +// Location for :bundle_both +const bundleBothLocation = helper.resolve(path.join(locationBase, 'bundle_both.js')); +const bundleBothSourcemapLocation = helper.resolve(path.join(locationBase, 'bundle_both.js.map')); + +describe('esbuild sourcemap', () => { + it('creates an external sourcemap by default', () => { + const sourcemap = readFileSync(bundleDefaultSourcemapLocation, {encoding: 'utf8'}); + expect(sourcemap).toContain( + '"sources": ["../../../../../../../packages/esbuild/test/sourcemap/main.ts"]'); + }); + + it('does not inline the sourcemap by default', () => { + const bundle = readFileSync(bundleDefaultLocation, {encoding: 'utf8'}); + expect(bundle).toContain('//# sourceMappingURL=bundle_default.js.map'); + }); + + it('inlines the sourcemap when set to \'inline\'', () => { + const bundle = readFileSync(bundleInlineLocation, {encoding: 'utf8'}); + expect(bundle).toContain('//# sourceMappingURL=data:application/json;base64'); + }); + + it('has no sourcemap comment when set to \'external\'', () => { + const bundle = readFileSync(bundleExternalLocation, {encoding: 'utf8'}); + expect(bundle).not.toContain('//# sourceMappingURL='); + }); + + it('creates an external sourcemap when set to \'external\'', () => { + const sourcemap = readFileSync(bundleExternalSourcemapLocation, {encoding: 'utf8'}); + expect(sourcemap).toContain( + '"sources": ["../../../../../../../packages/esbuild/test/sourcemap/main.ts"]'); + }); + + it('inlines the sourcemap when set to \'both\'', () => { + const bundle = readFileSync(bundleInlineLocation, {encoding: 'utf8'}); + expect(bundle).toContain('//# sourceMappingURL=data:application/json;base64'); + }); + + it('creates an external sourcemap when set to \'both\'', () => { + const sourcemap = readFileSync(bundleDefaultSourcemapLocation, {encoding: 'utf8'}); + expect(sourcemap).toContain( + '"sources": ["../../../../../../../packages/esbuild/test/sourcemap/main.ts"]'); + }); +}) diff --git a/packages/esbuild/test/sourcemap/main.ts b/packages/esbuild/test/sourcemap/main.ts new file mode 100644 index 0000000000..7dabd31053 --- /dev/null +++ b/packages/esbuild/test/sourcemap/main.ts @@ -0,0 +1,8 @@ +export interface Foo { + x: number, y: string, +} + +export const foo: Foo = { + x: 123, + y: 'hello', +}