From 1a83a7f139e2e54eb55af3f00b640fc9b505ab7d Mon Sep 17 00:00:00 2001 From: Greg Magolan Date: Thu, 26 Mar 2020 21:05:35 -0700 Subject: [PATCH] feat(typescript): add devmode_target, devmode_module, prodmode_target & prodmode_module attributes (#1687) This allows users control over the language level & module formats produced by both the dev and prod outputs of ts_library --- .../typescript/src/internal/build_defs.bzl | 48 +++++++++++++++++-- .../test/target_module_attributes/BUILD.bazel | 33 +++++++++++++ .../test/target_module_attributes/a.ts | 1 + .../override_output_test.js | 35 ++++++++++++++ .../tsconfig-override.json | 8 ++++ 5 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 packages/typescript/test/target_module_attributes/BUILD.bazel create mode 100644 packages/typescript/test/target_module_attributes/a.ts create mode 100644 packages/typescript/test/target_module_attributes/override_output_test.js create mode 100644 packages/typescript/test/target_module_attributes/tsconfig-override.json diff --git a/packages/typescript/src/internal/build_defs.bzl b/packages/typescript/src/internal/build_defs.bzl index 9854884b28..080691e159 100644 --- a/packages/typescript/src/internal/build_defs.bzl +++ b/packages/typescript/src/internal/build_defs.bzl @@ -25,6 +25,14 @@ load("//internal:ts_config.bzl", "TsConfigInfo") _DEFAULT_COMPILER = "@npm//@bazel/typescript/bin:tsc_wrapped" _DEFAULT_NODE_MODULES = Label("@npm//typescript:typescript__typings") +_TYPESCRIPT_SCRIPT_TARGETS = ["es3", "es5", "es2015", "es2016", "es2017", "es2018", "esnext"] +_TYPESCRIPT_MODULE_KINDS = ["none", "commonjs", "amd", "umd", "system", "es2015", "esnext"] + +_DEVMODE_TARGET_DEFAULT = "es2015" +_DEVMODE_MODULE_DEFAULT = "umd" +_PRODMODE_TARGET_DEFAULT = "es2015" +_PRODMODE_MODULE_DEFAULT = "esnext" + def _trim_package_node_modules(package_name): # trim a package name down to its path prior to a node_modules # segment. 'foo/node_modules/bar' would become 'foo' and @@ -219,9 +227,15 @@ def tsc_wrapped_tsconfig( ) config["bazelOptions"]["nodeModulesPrefix"] = node_modules_root - # Override the target so we use es2015 for devmode - # Since g3 isn't ready to do this yet - config["compilerOptions"]["target"] = "es2015" + # Control target & module via attributes + if devmode_manifest: + # NB: devmode target may still be overriden with a tsconfig bazelOpts.devmodeTargetOverride but that + # configuration settings will be removed in a future major release + config["compilerOptions"]["target"] = ctx.attr.devmode_target if hasattr(ctx.attr, "devmode_target") else _DEVMODE_TARGET_DEFAULT + config["compilerOptions"]["module"] = ctx.attr.devmode_module if hasattr(ctx.attr, "devmode_module") else _DEVMODE_MODULE_DEFAULT + else: + config["compilerOptions"]["target"] = ctx.attr.prodmode_target if hasattr(ctx.attr, "prodmode_target") else _PRODMODE_TARGET_DEFAULT + config["compilerOptions"]["module"] = ctx.attr.prodmode_module if hasattr(ctx.attr, "prodmode_module") else _PRODMODE_MODULE_DEFAULT # It's fine for users to have types[] in their tsconfig.json to help the editor # know which of the node_modules/@types/* entries to include in the program. @@ -318,6 +332,20 @@ the compiler attribute manually. executable = True, cfg = "host", ), + "devmode_module": attr.string( + doc = """Set the typescript `module` compiler option for devmode output. + +This value will override the `module` option in the user supplied tsconfig.""", + values = _TYPESCRIPT_MODULE_KINDS, + default = _DEVMODE_MODULE_DEFAULT, + ), + "devmode_target": attr.string( + doc = """Set the typescript `target` compiler option for devmode output. + +This value will override the `target` option in the user supplied tsconfig.""", + values = _TYPESCRIPT_SCRIPT_TARGETS, + default = _DEVMODE_TARGET_DEFAULT, + ), "internal_testing_type_check_dependencies": attr.bool(default = False, doc = "Testing only, whether to type check inputs that aren't srcs."), "node_modules": attr.label( doc = """The npm packages which should be available during the compile. @@ -384,6 +412,20 @@ yarn_install( """, default = _DEFAULT_NODE_MODULES, ), + "prodmode_module": attr.string( + doc = """Set the typescript `module` compiler option for prodmode output. + +This value will override the `module` option in the user supplied tsconfig.""", + values = _TYPESCRIPT_MODULE_KINDS, + default = _PRODMODE_MODULE_DEFAULT, + ), + "prodmode_target": attr.string( + doc = """Set the typescript `target` compiler option for prodmode output. + +This value will override the `target` option in the user supplied tsconfig.""", + values = _TYPESCRIPT_SCRIPT_TARGETS, + default = _PRODMODE_TARGET_DEFAULT, + ), "supports_workers": attr.bool( doc = """Intended for internal use only. diff --git a/packages/typescript/test/target_module_attributes/BUILD.bazel b/packages/typescript/test/target_module_attributes/BUILD.bazel new file mode 100644 index 0000000000..1ad9bfe2fd --- /dev/null +++ b/packages/typescript/test/target_module_attributes/BUILD.bazel @@ -0,0 +1,33 @@ +load("@npm_bazel_jasmine//:index.from_src.bzl", "jasmine_node_test") +load("@npm_bazel_typescript//:index.from_src.bzl", "ts_library") +load("//packages/typescript/test/devmode_consumer:devmode_consumer.bzl", "devmode_consumer") +load("//packages/typescript/test/es6_consumer:es6_consumer.bzl", "es6_consumer") + +ts_library( + name = "override", + srcs = ["a.ts"], + devmode_module = "amd", + devmode_target = "es5", + prodmode_module = "amd", + prodmode_target = "es5", + tsconfig = ":tsconfig-override.json", +) + +devmode_consumer( + name = "override_devmode_output", + deps = [":override"], +) + +es6_consumer( + name = "override_prodmode_output", + deps = [":override"], +) + +jasmine_node_test( + name = "override_output_test", + srcs = ["override_output_test.js"], + data = [ + ":override_devmode_output", + ":override_prodmode_output", + ], +) diff --git a/packages/typescript/test/target_module_attributes/a.ts b/packages/typescript/test/target_module_attributes/a.ts new file mode 100644 index 0000000000..d9ec9ebd86 --- /dev/null +++ b/packages/typescript/test/target_module_attributes/a.ts @@ -0,0 +1 @@ +export const a: any = () => 'hello world'; diff --git a/packages/typescript/test/target_module_attributes/override_output_test.js b/packages/typescript/test/target_module_attributes/override_output_test.js new file mode 100644 index 0000000000..7967ef5e17 --- /dev/null +++ b/packages/typescript/test/target_module_attributes/override_output_test.js @@ -0,0 +1,35 @@ +const fs = require('fs'); +const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']); + +describe('googmodule', () => { + let devmodeOutput; + let prodmodeOutput; + beforeAll(() => { + devmodeOutput = runfiles.resolvePackageRelative('a.js'); + prodmodeOutput = runfiles.resolvePackageRelative('a.mjs'); + }); + + it('should have amd module syntax in devmode', () => { + expect(fs.readFileSync(devmodeOutput, {encoding: 'utf-8'})) + .toContain( + `define("build_bazel_rules_nodejs/packages/typescript/test/target_module_attributes/a", ["require", "exports"], function (require, exports) {`); + }); + + it('should have es5 in devmode', () => { + expect(fs.readFileSync(devmodeOutput, { + encoding: 'utf-8' + })).toContain(`exports.a = function () { return 'hello world'; };`); + }); + + it('should have amd module syntax in prodmode', () => { + expect(fs.readFileSync(prodmodeOutput, {encoding: 'utf-8'})) + .toContain( + `define("build_bazel_rules_nodejs/packages/typescript/test/target_module_attributes/a", ["require", "exports"], function (require, exports) {`); + }); + + it('should have es5 in prodmode', () => { + expect(fs.readFileSync(prodmodeOutput, { + encoding: 'utf-8' + })).toContain(`exports.a = function () { return 'hello world'; };`); + }); +}); \ No newline at end of file diff --git a/packages/typescript/test/target_module_attributes/tsconfig-override.json b/packages/typescript/test/target_module_attributes/tsconfig-override.json new file mode 100644 index 0000000000..85ff8fb1dc --- /dev/null +++ b/packages/typescript/test/target_module_attributes/tsconfig-override.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + // Explicitly set types settings so typescript doesn't auto-discover types. + // If all types are discovered then all types need to be included as deps + // or typescript may error out with TS2688: Cannot find type definition file for 'foo'. + "types": [] + }, +} \ No newline at end of file