1414
1515"Rule to run the terser binary under bazel"
1616
17+ _DOC = """Run the terser minifier.
18+
19+ Typical example:
20+ ```python
21+ load("@npm_bazel_terser//:index.bzl", "terser_minified")
22+
23+ terser_minified(
24+ name = "out.min",
25+ src = "input.js",
26+ config_file = "terser_config.json",
27+ )
28+ ```
29+
30+ Note that the `name` attribute determines what the resulting files will be called.
31+ So the example above will output `out.min.js` and `out.min.js.map` (since `sourcemap` defaults to `true`).
32+ """
33+
1734_TERSER_ATTRS = {
1835 "src" : attr .label (
19- doc = """A JS file, or a rule producing .js as its default output
36+ doc = """A JS file, or a rule producing .js files as its default output
2037
2138Note that you can pass multiple files to terser, which it will bundle together.
2239If you want to do this, you can pass a filegroup here.""" ,
2340 allow_files = [".js" ],
24- mandatory = True ,
2541 ),
2642 "config_file" : attr .label (
2743 doc = """A JSON file containing Terser minify() options.
@@ -67,6 +83,14 @@ so that it only affects the current build.
6783 doc = "Whether to produce a .js.map output" ,
6884 default = True ,
6985 ),
86+ "src_dir" : attr .label (
87+ doc = """A directory containing some .js files.
88+
89+ Each `.js` file will be run through terser, and the rule will output a directory of minified files.
90+ The output will be a directory named the same as the "name" attribute.
91+ Any files not ending in `.js` will be ignored.
92+ """ ,
93+ ),
7094 "terser_bin" : attr .label (
7195 doc = "An executable target that runs Terser" ,
7296 default = Label ("@npm//@bazel/terser/bin:terser" ),
@@ -75,7 +99,10 @@ so that it only affects the current build.
7599 ),
76100}
77101
78- def _terser_outs (sourcemap ):
102+ def _terser_outs (src_dir , sourcemap ):
103+ if src_dir :
104+ # Tree artifact outputs must be declared with ctx.actions.declare_directory
105+ return {}
79106 result = {"minified" : "%{name}.js" }
80107 if sourcemap :
81108 result ["sourcemap" ] = "%{name}.js.map"
@@ -86,10 +113,28 @@ def _terser(ctx):
86113
87114 # CLI arguments; see https://www.npmjs.com/package/terser#command-line-usage
88115 args = ctx .actions .args ()
89- args .add_all ([src .path for src in ctx .files .src ])
90-
91- outputs = [ctx .outputs .minified ]
92- args .add_all (["--output" , ctx .outputs .minified .path ])
116+ inputs = []
117+ outputs = [getattr (ctx .outputs , o ) for o in dir (ctx .outputs )]
118+
119+ if ctx .attr .src and ctx .attr .src_dir :
120+ fail ("Only one of src and src_dir attributes should be specified" )
121+ if not ctx .attr .src and not ctx .attr .src_dir :
122+ fail ("Either src or src_dir is required" )
123+ if ctx .attr .src :
124+ for src in ctx .files .src :
125+ if src .is_directory :
126+ fail ("Directories should be specified in the src_dir attribute, not src" )
127+ args .add (src .path )
128+ inputs .extend (ctx .files .src )
129+ else :
130+ for src in ctx .files .src_dir :
131+ if not src .is_directory :
132+ fail ("Individual files should be specifed in the src attribute, not src_dir" )
133+ args .add (src .path )
134+ inputs .extend (ctx .files .src_dir )
135+ outputs .append (ctx .actions .declare_directory (ctx .label .name ))
136+
137+ args .add_all (["--output" , outputs [0 ].path ])
93138
94139 debug = ctx .attr .debug or "DEBUG" in ctx .var .keys ()
95140 if debug :
@@ -111,6 +156,7 @@ def _terser(ctx):
111156 args .add_all (["--source-map" , "," .join (source_map_opts )])
112157
113158 opts = ctx .actions .declare_file ("_%s.minify_options.json" % ctx .label .name )
159+ inputs .append (opts )
114160 ctx .actions .expand_template (
115161 template = ctx .file .config_file ,
116162 output = opts ,
@@ -123,30 +169,19 @@ def _terser(ctx):
123169 args .add_all (["--config-file" , opts .path ])
124170
125171 ctx .actions .run (
126- inputs = ctx . files . src + [ opts ] ,
172+ inputs = inputs ,
127173 outputs = outputs ,
128174 executable = ctx .executable .terser_bin ,
129175 arguments = [args ],
130- progress_message = "Minifying JavaScript %s [terser]" % (ctx . outputs . minified .short_path ),
176+ progress_message = "Minifying JavaScript %s [terser]" % (outputs [ 0 ] .short_path ),
131177 )
132178
133- terser_minified = rule (
134- doc = """Run the terser minifier.
135-
136- Typical example:
137- ```python
138- load("@npm_bazel_terser//:index.bzl", "terser_minified")
179+ return [
180+ DefaultInfo (files = depset (outputs )),
181+ ]
139182
140- terser_minified(
141- name = "out.min",
142- src = "input.js",
143- config_file = "terser_config.json",
144- )
145- ```
146-
147- Note that the `name` attribute determines what the resulting files will be called.
148- So the example above will output `out.min.js` and `out.min.js.map` (since `sourcemap` defaults to `true`).
149- """ ,
183+ terser_minified = rule (
184+ doc = _DOC ,
150185 implementation = _terser ,
151186 attrs = _TERSER_ATTRS ,
152187 outputs = _terser_outs ,
0 commit comments