# Copyright Google LLC All Rights Reserved. # # Use of this source code is governed by an MIT-style license that can be # found in the LICENSE file at https://angular.io/license """Rollup with Build Optimizer This provides a variant of the [rollup_bundle] rule that works better for Angular apps. It registers `@angular-devkit/build-optimizer` as a rollup plugin, to get better optimization. It also uses ESM5 format inputs, as this is what build-optimizer is hard-coded to look for and transform. [rollup_bundle]: https://bazelbuild.github.io/rules_nodejs/rollup/rollup_bundle.html """ load("@build_bazel_rules_nodejs//:index.bzl", "npm_package_bin") load("@build_bazel_rules_nodejs//:providers.bzl", "JSEcmaScriptModuleInfo", "NpmPackageInfo", "node_modules_aspect") load("//packages/bazel/src:esm5.bzl", "esm5_outputs_aspect", "esm5_root_dir", "flatten_esm5") load("@npm_bazel_terser//:index.bzl", "terser_minified") _NG_ROLLUP_BUNDLE_OUTPUTS = { "bundle": "%{name}.js", "sourcemap": "%{name}.js.map", } _NG_ROLLUP_MODULE_MAPPINGS_ATTR = "ng_rollup_module_mappings" def _ng_rollup_module_mappings_aspect_impl(target, ctx): mappings = dict() for dep in ctx.rule.attr.deps: if hasattr(dep, _NG_ROLLUP_MODULE_MAPPINGS_ATTR): for k, v in getattr(dep, _NG_ROLLUP_MODULE_MAPPINGS_ATTR).items(): if k in mappings and mappings[k] != v: fail(("duplicate module mapping at %s: %s maps to both %s and %s" % (target.label, k, mappings[k], v)), "deps") mappings[k] = v if ((hasattr(ctx.rule.attr, "module_name") and ctx.rule.attr.module_name) or (hasattr(ctx.rule.attr, "module_root") and ctx.rule.attr.module_root)): mn = ctx.rule.attr.module_name if not mn: mn = target.label.name mr = target.label.package if target.label.workspace_root: mr = "%s/%s" % (target.label.workspace_root, mr) if ctx.rule.attr.module_root and ctx.rule.attr.module_root != ".": if ctx.rule.attr.module_root.endswith(".ts"): # This is the type-checking module mapping. Strip the trailing .d.ts # as it doesn't belong in TypeScript's path mapping. mr = "%s/%s" % (mr, ctx.rule.attr.module_root.replace(".d.ts", "")) else: mr = "%s/%s" % (mr, ctx.rule.attr.module_root) if mn in mappings and mappings[mn] != mr: fail(("duplicate module mapping at %s: %s maps to both %s and %s" % (target.label, mn, mappings[mn], mr)), "deps") mappings[mn] = mr return struct(ng_rollup_module_mappings = mappings) ng_rollup_module_mappings_aspect = aspect( _ng_rollup_module_mappings_aspect_impl, attr_aspects = ["deps"], ) _NG_ROLLUP_BUNDLE_DEPS_ASPECTS = [esm5_outputs_aspect, ng_rollup_module_mappings_aspect, node_modules_aspect] _NG_ROLLUP_BUNDLE_ATTRS = { "build_optimizer": attr.bool( doc = """Use build optimizer plugin Only used if sources are esm5 which depends on value of esm5_sources.""", default = True, ), "esm5_sources": attr.bool( doc = """Use esm5 input sources""", default = True, ), "srcs": attr.label_list( doc = """JavaScript source files from the workspace. These can use ES2015 syntax and ES Modules (import/export)""", allow_files = True, ), "entry_point": attr.label( doc = """The starting point of the application, passed as the `--input` flag to rollup. If the entry JavaScript file belongs to the same package (as the BUILD file), you can simply reference it by its relative name to the package directory: ``` ng_rollup_bundle( name = "bundle", entry_point = ":main.js", ) ``` You can specify the entry point as a typescript file so long as you also include the ts_library target in deps: ``` ts_library( name = "main", srcs = ["main.ts"], ) ng_rollup_bundle( name = "bundle", deps = [":main"] entry_point = ":main.ts", ) ``` The rule will use the corresponding `.js` output of the ts_library rule as the entry point. If the entry point target is a rule, it should produce a single JavaScript entry file that will be passed to the nodejs_binary rule. For example: ``` filegroup( name = "entry_file", srcs = ["main.js"], ) ng_rollup_bundle( name = "bundle", entry_point = ":entry_file", ) ``` """, mandatory = True, allow_single_file = True, ), "deps": attr.label_list( doc = """Other targets that provide JavaScript files. Typically this will be `ts_library` or `ng_module` targets.""", aspects = _NG_ROLLUP_BUNDLE_DEPS_ASPECTS, ), "format": attr.string( doc = """"Specifies the format of the generated bundle. One of the following: - `amd`: Asynchronous Module Definition, used with module loaders like RequireJS - `cjs`: CommonJS, suitable for Node and other bundlers - `esm`: Keep the bundle as an ES module file, suitable for other bundlers and inclusion as a `