feat(esbuild): add support for plugins via supplying a configuration file (#2840)

diff --git a/docs/esbuild.md b/docs/esbuild.md
index e1809c5..68b95b9 100755
--- a/docs/esbuild.md
+++ b/docs/esbuild.md
@@ -99,9 +99,9 @@
 **USAGE**
 
 <pre>
-esbuild(<a href="#esbuild-name">name</a>, <a href="#esbuild-args">args</a>, <a href="#esbuild-args_file">args_file</a>, <a href="#esbuild-define">define</a>, <a href="#esbuild-deps">deps</a>, <a href="#esbuild-entry_point">entry_point</a>, <a href="#esbuild-entry_points">entry_points</a>, <a href="#esbuild-external">external</a>, <a href="#esbuild-format">format</a>, <a href="#esbuild-launcher">launcher</a>,
-        <a href="#esbuild-link_workspace_root">link_workspace_root</a>, <a href="#esbuild-max_threads">max_threads</a>, <a href="#esbuild-minify">minify</a>, <a href="#esbuild-output">output</a>, <a href="#esbuild-output_css">output_css</a>, <a href="#esbuild-output_dir">output_dir</a>, <a href="#esbuild-output_map">output_map</a>,
-        <a href="#esbuild-platform">platform</a>, <a href="#esbuild-sourcemap">sourcemap</a>, <a href="#esbuild-sources_content">sources_content</a>, <a href="#esbuild-splitting">splitting</a>, <a href="#esbuild-srcs">srcs</a>, <a href="#esbuild-target">target</a>)
+esbuild(<a href="#esbuild-name">name</a>, <a href="#esbuild-args">args</a>, <a href="#esbuild-args_file">args_file</a>, <a href="#esbuild-config">config</a>, <a href="#esbuild-define">define</a>, <a href="#esbuild-deps">deps</a>, <a href="#esbuild-entry_point">entry_point</a>, <a href="#esbuild-entry_points">entry_points</a>, <a href="#esbuild-external">external</a>, <a href="#esbuild-format">format</a>,
+        <a href="#esbuild-launcher">launcher</a>, <a href="#esbuild-link_workspace_root">link_workspace_root</a>, <a href="#esbuild-max_threads">max_threads</a>, <a href="#esbuild-minify">minify</a>, <a href="#esbuild-output">output</a>, <a href="#esbuild-output_css">output_css</a>, <a href="#esbuild-output_dir">output_dir</a>,
+        <a href="#esbuild-output_map">output_map</a>, <a href="#esbuild-platform">platform</a>, <a href="#esbuild-sourcemap">sourcemap</a>, <a href="#esbuild-sources_content">sources_content</a>, <a href="#esbuild-splitting">splitting</a>, <a href="#esbuild-srcs">srcs</a>, <a href="#esbuild-target">target</a>)
 </pre>
 
 Runs the esbuild bundler under Bazel
@@ -126,7 +126,15 @@
 
 <h4 id="esbuild-args_file">args_file</h4>
 
-(*<a href="https://bazel.build/docs/build-ref.html#labels">Label</a>*): A JSON file containing additional arguments that are passed to esbuild. Note: only one of args or args_file may be set
+(*<a href="https://bazel.build/docs/build-ref.html#labels">Label</a>*): Internal use only
+
+Defaults to `None`
+
+<h4 id="esbuild-config">config</h4>
+
+(*<a href="https://bazel.build/docs/build-ref.html#labels">Label</a>*): Configuration file used for esbuild, from the esbuild_config macro. Note that options set in this file may get overwritten.
+See https://github.com/bazelbuild/rules_nodejs/tree/stable/packages/esbuild/test/plugins/BUILD.bazel for examples of using esbuild_config and plugins.  The dependencies of this attribute must provide: Unknown Provider
+
 
 Defaults to `None`
 
@@ -323,6 +331,50 @@
 
 
 
+## esbuild_config
+
+**USAGE**
+
+<pre>
+esbuild_config(<a href="#esbuild_config-name">name</a>, <a href="#esbuild_config-config_file">config_file</a>, <a href="#esbuild_config-srcs">srcs</a>, <a href="#esbuild_config-deps">deps</a>, <a href="#esbuild_config-kwargs">kwargs</a>)
+</pre>
+
+Macro for an esbuild configuration file and its assoicated dependencies
+
+**PARAMETERS**
+
+
+<h4 id="esbuild_config-name">name</h4>
+
+Unique name for this rule
+
+
+
+<h4 id="esbuild_config-config_file">config_file</h4>
+
+The configuration file / entrypoint
+
+
+
+<h4 id="esbuild_config-srcs">srcs</h4>
+
+List of source files referenced by the configuration
+
+Defaults to `[]`
+
+<h4 id="esbuild_config-deps">deps</h4>
+
+List of dependencies required for this configuration
+
+Defaults to `[]`
+
+<h4 id="esbuild_config-kwargs">kwargs</h4>
+
+Any other common attributes
+
+
+
+
 ## esbuild_repositories
 
 **USAGE**
diff --git a/package.json b/package.json
index b144fa8..0a40b1d 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
         "conventional-changelog-cli": "^2.0.21",
         "core-util-is": "^1.0.2",
         "date-fns": "1.30.1",
+        "esbuild-plugin-svg": "0.1.0",
         "google-protobuf": "^3.6.1",
         "grpc-web": "1.1.0",
         "hello": "file:./tools/npm_packages/hello",
diff --git a/packages/esbuild/BUILD.bazel b/packages/esbuild/BUILD.bazel
index 0eefa11..10be250 100644
--- a/packages/esbuild/BUILD.bazel
+++ b/packages/esbuild/BUILD.bazel
@@ -58,6 +58,7 @@
     name = "srcs",
     srcs = [
         "esbuild.bzl",
+        "esbuild_config.bzl",
         "esbuild_packages.bzl",
         "esbuild_repositories.bzl",
         "helpers.bzl",
diff --git a/packages/esbuild/esbuild.bzl b/packages/esbuild/esbuild.bzl
index c71bafd..3017923 100644
--- a/packages/esbuild/esbuild.bzl
+++ b/packages/esbuild/esbuild.bzl
@@ -152,6 +152,14 @@
         inputs.append(ctx.file.args_file)
         launcher_args.add("--user_args=%s" % ctx.file.args_file.path)
 
+    if ctx.attr.config:
+        configs = ctx.attr.config[JSEcmaScriptModuleInfo].sources.to_list()
+        if len(configs) != 1:
+            fail("Expected only one source file: the configuration entrypoint")
+
+        inputs.append(configs[0])
+        launcher_args.add("--config_file=%s" % configs[0].path)
+
     run_node(
         ctx = ctx,
         inputs = depset(inputs),
@@ -188,7 +196,7 @@
         "args_file": attr.label(
             allow_single_file = True,
             mandatory = False,
-            doc = "A JSON file containing additional arguments that are passed to esbuild. Note: only one of args or args_file may be set",
+            doc = "Internal use only",
         ),
         "define": attr.string_dict(
             default = {},
@@ -333,6 +341,13 @@
 See https://esbuild.github.io/api/#target for more details
             """,
         ),
+        "config": attr.label(
+            providers = [JSEcmaScriptModuleInfo],
+            mandatory = False,
+            doc = """Configuration file used for esbuild, from the esbuild_config macro. Note that options set in this file may get overwritten.
+See https://github.com/bazelbuild/rules_nodejs/tree/stable/packages/esbuild/test/plugins/BUILD.bazel for examples of using esbuild_config and plugins.
+            """,
+        ),
     },
     implementation = _esbuild_impl,
     toolchains = [
@@ -367,12 +382,12 @@
     deps = kwargs.pop("deps", []) + ["@esbuild_npm//esbuild"]
     entry_points = kwargs.get("entry_points", None)
 
-    args = kwargs.pop("args", {})
+    # TODO(mattem): remove `args` and `args_file` in 5.x and everything can go via `config`
     args_file = kwargs.pop("args_file", None)
+    if args_file:
+        fail("Setting 'args_file' is not supported, set 'config' instead")
 
-    if args and args_file:
-        fail("Both 'args' and 'args_file' attributes set, these are mutually exclusive")
-
+    args = kwargs.pop("args", {})
     if args:
         if type(args) != type(dict()):
             fail("Expected 'args' to be of type dict")
@@ -385,6 +400,11 @@
             data = deps + srcs,
         )
 
+    config = kwargs.pop("config", None)
+    if config:
+        kwargs.setdefault("config", config)
+        deps.append("%s_deps" % config)
+
     if output_dir == True or entry_points or splitting == True:
         esbuild(
             name = name,
diff --git a/packages/esbuild/esbuild_config.bzl b/packages/esbuild/esbuild_config.bzl
new file mode 100644
index 0000000..a19948e
--- /dev/null
+++ b/packages/esbuild/esbuild_config.bzl
@@ -0,0 +1,27 @@
+"esbuild configuration file helper macro"
+
+load("@build_bazel_rules_nodejs//:index.bzl", _js_library = "js_library")
+
+def esbuild_config(name, config_file, srcs = [], deps = [], **kwargs):
+    """Macro for an esbuild configuration file and its assoicated dependencies
+
+    Args:
+        name: Unique name for this rule
+        config_file: The configuration file / entrypoint
+        srcs: List of source files referenced by the configuration
+        deps: List of dependencies required for this configuration
+        **kwargs: Any other common attributes
+    """
+
+    _js_library(
+        name = name,
+        srcs = [config_file],
+        **kwargs
+    )
+
+    _js_library(
+        name = "%s_deps" % name,
+        srcs = srcs,
+        deps = deps,
+        **kwargs
+    )
diff --git a/packages/esbuild/index.bzl b/packages/esbuild/index.bzl
index 298d89d..6b8ba85 100644
--- a/packages/esbuild/index.bzl
+++ b/packages/esbuild/index.bzl
@@ -20,9 +20,14 @@
     _esbuild_macro = "esbuild_macro",
 )
 load(
+    "@build_bazel_rules_nodejs//packages/esbuild:esbuild_config.bzl",
+    _esbuild_config = "esbuild_config",
+)
+load(
     "@build_bazel_rules_nodejs//packages/esbuild/toolchain:toolchain.bzl",
     _configure_esbuild_toolchain = "configure_esbuild_toolchain",
 )
 
 esbuild = _esbuild_macro
+esbuild_config = _esbuild_config
 configure_esbuild_toolchain = _configure_esbuild_toolchain
diff --git a/packages/esbuild/index.docs.bzl b/packages/esbuild/index.docs.bzl
index 0a47606..1d514cf 100644
--- a/packages/esbuild/index.docs.bzl
+++ b/packages/esbuild/index.docs.bzl
@@ -93,6 +93,10 @@
     _esbuild = "esbuild",
 )
 load(
+    "@build_bazel_rules_nodejs//packages/esbuild:esbuild_config.bzl",
+    _esbuild_config = "esbuild_config",
+)
+load(
     "@build_bazel_rules_nodejs//packages/esbuild:esbuild_repositories.bzl",
     _esbuild_repositories = "esbuild_repositories",
 )
@@ -102,5 +106,6 @@
 )
 
 esbuild = _esbuild
+esbuild_config = _esbuild_config
 esbuild_repositories = _esbuild_repositories
 configure_esbuild_toolchain = _configure_esbuild_toolchain
diff --git a/packages/esbuild/launcher.js b/packages/esbuild/launcher.js
index 2bc0386..bb3dd79 100755
--- a/packages/esbuild/launcher.js
+++ b/packages/esbuild/launcher.js
@@ -1,4 +1,6 @@
 const {readFileSync, writeFileSync} = require('fs');
+const {pathToFileURL} = require('url');
+const {join} = require('path');
 const esbuild = require('esbuild');
 
 function getFlag(flag, required = true) {
@@ -22,22 +24,82 @@
   }
 }
 
+async function processConfigFile(configFilePath) {
+  const fullConfigFileUrl = pathToFileURL(join(process.cwd(), configFilePath));
+  let config;
+  try {
+    config = await import(fullConfigFileUrl);
+  } catch (e) {
+    console.error(`Error while loading configuration '${fullConfigFileUrl}':\n`, e);
+    process.exit(1);
+  }
+
+  if (!config.default) {
+    console.error(`Config file '${configFilePath}' was loaded, but did not export a configuration object as default`);
+    process.exit(1);
+  }
+
+  config = config.default;
+
+  // These keys of the config can not be overriden
+  const IGNORED_CONFIG_KEYS = [
+    'bundle',
+    'define',
+    'entryPoints',
+    'external',
+    'metafile',
+    'outdir',
+    'outfile',
+    'preserveSymlinks',
+    'sourcemap',
+    'splitting',
+    'tsconfig',
+  ];
+
+  return Object.entries(config).reduce((prev, [key, value]) => {
+    if (IGNORED_CONFIG_KEYS.includes(key)) {
+      console.error(`[WARNING] esbuild configuration property '${key}' from '${configFilePath}' will be ignored and overriden`);
+    } else {
+      prev[key] = value;
+    }
+    return prev;
+  }, {});
+}
+
 if (!process.env.ESBUILD_BINARY_PATH) {
   console.error('Expected enviournment variable ESBUILD_BINARY_PATH to be set', e);
   process.exit(1);
 }
 
-let args = getEsbuildArgs(getFlag('--esbuild_args'));
-
-const userArgsFile = getFlag("--user_args", false);
-if (userArgsFile) {
-  args = {
-    ...args,
-    ...getEsbuildArgs(userArgsFile)
-  };
+async function runOneBuild(args, userArgsFilePath, configFilePath) {
+  if (userArgsFilePath) {
+    args = {
+      ...args,
+      ...getEsbuildArgs(userArgsFilePath)
+    }
+  }
+  
+  if (configFilePath) {
+    const config = await processConfigFile(configFilePath);
+    args = {
+      ...args,
+      ...config
+    };
+  }
+  
+  const metafile = getFlag('--metafile');
+  
+  try {
+    const result = await esbuild.build(args);
+    writeFileSync(metafile, JSON.stringify(result.metafile));
+  } catch (e) {
+    console.error(e);
+    process.exit(1);
+  }
 }
 
-const metafile = getFlag('--metafile');
-
-const result = esbuild.buildSync(args);
-writeFileSync(metafile, JSON.stringify(result.metafile));
+runOneBuild(
+  getEsbuildArgs(getFlag("--esbuild_args")),
+  getFlag("--user_args", false),
+  getFlag("--config_file", false)
+);
diff --git a/packages/esbuild/test/plugins/BUILD.bazel b/packages/esbuild/test/plugins/BUILD.bazel
new file mode 100644
index 0000000..d2d8b16
--- /dev/null
+++ b/packages/esbuild/test/plugins/BUILD.bazel
@@ -0,0 +1,57 @@
+load("//:index.bzl", "generated_file_test", "js_library", "nodejs_binary", "npm_package_bin")
+load("//packages/esbuild:index.bzl", "esbuild")
+load("//packages/esbuild:esbuild_config.bzl", "esbuild_config")
+
+js_library(
+    name = "main",
+    srcs = [
+        "logo.svg",
+        "main.js",
+        "words.txt",
+    ],
+)
+
+js_library(
+    name = "txt_array_plugin",
+    srcs = [
+        "txt-array-plugin.js",
+    ],
+)
+
+esbuild_config(
+    name = "esbuild_config",
+    config_file = "esbuild.config.mjs",
+    deps = [
+        ":txt_array_plugin",
+        "@npm//esbuild-plugin-svg",
+    ],
+)
+
+esbuild(
+    name = "bundle",
+    config = ":esbuild_config",
+    entry_point = "main.js",
+    deps = [
+        ":main",
+    ],
+)
+
+nodejs_binary(
+    name = "bin",
+    data = [
+        ":bundle",
+    ],
+    entry_point = "bundle.js",
+)
+
+npm_package_bin(
+    name = "runner",
+    stdout = "out.txt",
+    tool = ":bin",
+)
+
+generated_file_test(
+    name = "test",
+    src = "out.golden.txt",
+    generated = "out.txt",
+)
diff --git a/packages/esbuild/test/plugins/esbuild.config.mjs b/packages/esbuild/test/plugins/esbuild.config.mjs
new file mode 100644
index 0000000..7284434
--- /dev/null
+++ b/packages/esbuild/test/plugins/esbuild.config.mjs
@@ -0,0 +1,9 @@
+import { default as txtArrayPlugin } from './txt-array-plugin.js';
+import { default as svgPlugin } from 'esbuild-plugin-svg';
+
+export default {
+    plugins: [
+        txtArrayPlugin,
+        svgPlugin(),
+    ],
+}
diff --git a/packages/esbuild/test/plugins/logo.svg b/packages/esbuild/test/plugins/logo.svg
new file mode 100644
index 0000000..2f64936
--- /dev/null
+++ b/packages/esbuild/test/plugins/logo.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
+    <g>
+        <circle fill="#FFCF00" cx="128" cy="128" r="128"></circle>
+        <path d="M69.2852814,58.7147186 L138.570563,128 L69.2852814,197.285281 L52.3147186,180.314719 L104.629,128 L52.3147186,75.6852814 L69.2852814,58.7147186 Z M146.085281,58.7147186 L215.370563,128 L146.085281,197.285281 L129.114719,180.314719 L181.429,128 L129.114719,75.6852814 L146.085281,58.7147186 Z" fill="#191919"></path>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/packages/esbuild/test/plugins/main.js b/packages/esbuild/test/plugins/main.js
new file mode 100644
index 0000000..a2f858e
--- /dev/null
+++ b/packages/esbuild/test/plugins/main.js
@@ -0,0 +1,10 @@
+// The example esbuild plugin loads the txt file and splits on each word.
+// 'words' results in an array of the words from the txt file.
+import { default as words } from './words.txt';
+
+// The SVG plugin loads the svg and sets the file contents to the 'logo' symbol
+import logo from './logo.svg';
+
+console.log(words);
+
+console.log(logo);
diff --git a/packages/esbuild/test/plugins/out.golden.txt b/packages/esbuild/test/plugins/out.golden.txt
new file mode 100644
index 0000000..bc45595
--- /dev/null
+++ b/packages/esbuild/test/plugins/out.golden.txt
@@ -0,0 +1,8 @@
+[ 'foo', 'bar', 'rules_nodejs' ]
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
+    <g>
+        <circle fill="#FFCF00" cx="128" cy="128" r="128"></circle>
+        <path d="M69.2852814,58.7147186 L138.570563,128 L69.2852814,197.285281 L52.3147186,180.314719 L104.629,128 L52.3147186,75.6852814 L69.2852814,58.7147186 Z M146.085281,58.7147186 L215.370563,128 L146.085281,197.285281 L129.114719,180.314719 L181.429,128 L129.114719,75.6852814 L146.085281,58.7147186 Z" fill="#191919"></path>
+    </g>
+</svg>
diff --git a/packages/esbuild/test/plugins/txt-array-plugin.js b/packages/esbuild/test/plugins/txt-array-plugin.js
new file mode 100644
index 0000000..3bd85a8
--- /dev/null
+++ b/packages/esbuild/test/plugins/txt-array-plugin.js
@@ -0,0 +1,15 @@
+const fs = require('fs');
+
+module.exports = {
+    name: 'txt',
+    setup(build) {
+        // Load ".txt" files and return an array of words
+        build.onLoad({ filter: /\.txt$/ }, async (args) => {
+            const text = await fs.promises.readFile(args.path, 'utf8');
+            return {
+                contents: JSON.stringify(text.split(/\s+/)),
+                loader: 'json',
+            }
+        });
+    },
+};
diff --git a/packages/esbuild/test/plugins/words.txt b/packages/esbuild/test/plugins/words.txt
new file mode 100644
index 0000000..969afa9
--- /dev/null
+++ b/packages/esbuild/test/plugins/words.txt
@@ -0,0 +1 @@
+foo bar rules_nodejs
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 9afcfd2..c87295e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1707,6 +1707,11 @@
   resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
   integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
 
+"@trysound/sax@0.1.1":
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
+  integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==
+
 "@types/babel__core@^7.1.7":
   version "7.1.7"
   resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89"
@@ -2453,6 +2458,11 @@
     raw-body "2.4.0"
     type-is "~1.6.17"
 
+boolbase@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
+
 boxen@^1.2.1:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
@@ -2792,6 +2802,14 @@
     ansi-styles "^4.1.0"
     supports-color "^7.1.0"
 
+chalk@^4.1.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
 cherow@^1.6.8:
   version "1.6.9"
   resolved "https://registry.yarnpkg.com/cherow/-/cherow-1.6.9.tgz#7c5e34fce297f152a6f7853dcc9fe2f9e1b36ab8"
@@ -3062,6 +3080,11 @@
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.1.tgz#3863ce3ca92d0831dcf2a102f5fb4b5926afd0f9"
   integrity sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==
 
+commander@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+  integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
 commondir@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -3451,6 +3474,37 @@
   resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
   integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
 
+css-select@^4.1.3:
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067"
+  integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==
+  dependencies:
+    boolbase "^1.0.0"
+    css-what "^5.0.0"
+    domhandler "^4.2.0"
+    domutils "^2.6.0"
+    nth-check "^2.0.0"
+
+css-tree@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+  integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+  dependencies:
+    mdn-data "2.0.14"
+    source-map "^0.6.1"
+
+css-what@^5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad"
+  integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==
+
+csso@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
+  integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
+  dependencies:
+    css-tree "^1.1.2"
+
 cssom@^0.4.1:
   version "0.4.4"
   resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
@@ -3747,6 +3801,20 @@
     extend "^3.0.0"
     void-elements "^2.0.0"
 
+dom-serializer@^1.0.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
+  integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
+  dependencies:
+    domelementtype "^2.0.1"
+    domhandler "^4.2.0"
+    entities "^2.0.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
+  integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
+
 domexception@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
@@ -3754,6 +3822,22 @@
   dependencies:
     webidl-conversions "^4.0.2"
 
+domhandler@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
+  integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
+  dependencies:
+    domelementtype "^2.2.0"
+
+domutils@^2.6.0:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442"
+  integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==
+  dependencies:
+    dom-serializer "^1.0.1"
+    domelementtype "^2.2.0"
+    domhandler "^4.2.0"
+
 dot-prop@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
@@ -3885,6 +3969,11 @@
   resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
   integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0=
 
+entities@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+  integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
 env-paths@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43"
@@ -3947,6 +4036,13 @@
   dependencies:
     es6-promise "^4.0.3"
 
+esbuild-plugin-svg@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/esbuild-plugin-svg/-/esbuild-plugin-svg-0.1.0.tgz#6c6e52abe08ae1714d236125b3e9c1572408d324"
+  integrity sha512-/9ZhvIpl+Ovl6glVK3BedvIwrOwSQnECw4Fy6ZwysWib3Ns7UkX6WNGjMOWtvQ1Cnm0uc7sptiKGm0BthKCAJA==
+  dependencies:
+    svgo "^2.2.2"
+
 escalade@^3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -6797,6 +6893,11 @@
   dependencies:
     object-visit "^1.0.0"
 
+mdn-data@2.0.14:
+  version "2.0.14"
+  resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+  integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
 meant@~1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d"
@@ -7525,6 +7626,13 @@
     gauge "~2.7.3"
     set-blocking "~2.0.0"
 
+nth-check@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
+  integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
+  dependencies:
+    boolbase "^1.0.0"
+
 number-is-nan@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
@@ -9341,6 +9449,11 @@
   dependencies:
     figgy-pudding "^3.5.1"
 
+stable@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
 stack-utils@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8"
@@ -9581,6 +9694,19 @@
     has-flag "^4.0.0"
     supports-color "^7.0.0"
 
+svgo@^2.2.2:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.1.tgz#603a69ce50311c0e36791528f549644ec1b3f4bc"
+  integrity sha512-riDDIQgXpEnn0BEl9Gvhh1LNLIyiusSpt64IR8upJu7MwxnzetmF/Y57pXQD2NMX2lVyMRzXt5f2M5rO4wG7Dw==
+  dependencies:
+    "@trysound/sax" "0.1.1"
+    chalk "^4.1.0"
+    commander "^7.1.0"
+    css-select "^4.1.3"
+    css-tree "^1.1.2"
+    csso "^4.2.0"
+    stable "^0.1.8"
+
 symbol-tree@^3.2.2:
   version "3.2.4"
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"