diff --git a/examples/custom-esbuild/sanity-esbuild-app-esm/angular.json b/examples/custom-esbuild/sanity-esbuild-app-esm/angular.json
index 7ed10f251f..36b479d109 100644
--- a/examples/custom-esbuild/sanity-esbuild-app-esm/angular.json
+++ b/examples/custom-esbuild/sanity-esbuild-app-esm/angular.json
@@ -17,7 +17,7 @@
"build": {
"builder": "@angular-builders/custom-esbuild:application",
"options": {
- "plugins": ["esbuild/define-text-plugin.js"],
+ "plugins": ["esbuild/define-text-plugin.js", {"path": "esbuild/define-text-by-option-plugin.js", "options": {"title": "sanity-esbuild-app-esm optionTitle (compilation provided)"} }],
"outputPath": "dist/sanity-esbuild-app-esm",
"index": "src/index.html",
"browser": "src/main.ts",
diff --git a/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.cjs b/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.cjs
new file mode 100644
index 0000000000..c3d072e5f1
--- /dev/null
+++ b/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.cjs
@@ -0,0 +1,11 @@
+function defineTitleByOptionPlugin(pluginOptions) {
+ return {
+ name: 'define-title',
+ setup(build) {
+ const options = build.initialOptions;
+ options.define.titleByOption = JSON.stringify(pluginOptions.title);
+ },
+ };
+};
+
+module.exports = defineTitleByOptionPlugin;
diff --git a/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.js b/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.js
new file mode 100644
index 0000000000..7c6cf02b65
--- /dev/null
+++ b/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.js
@@ -0,0 +1,11 @@
+function defineTitleByOptionPlugin(pluginOptions) {
+ return {
+ name: 'define-title',
+ setup(build) {
+ const options = build.initialOptions;
+ options.define.titleByOption = JSON.stringify(pluginOptions.title);
+ },
+ };
+};
+
+export default defineTitleByOptionPlugin;
diff --git a/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.ts b/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.ts
new file mode 100644
index 0000000000..2e32da11d8
--- /dev/null
+++ b/examples/custom-esbuild/sanity-esbuild-app-esm/esbuild/define-text-by-option-plugin.ts
@@ -0,0 +1,13 @@
+import type { Plugin, PluginBuild } from 'esbuild';
+
+function defineTitleByOptionPlugin(pluginOptions: {title: string}): Plugin {
+ return {
+ name: 'define-title',
+ setup(build: PluginBuild) {
+ const options = build.initialOptions;
+ options.define!['titleByOption'] = JSON.stringify(pluginOptions.title);
+ },
+ };
+};
+
+export default defineTitleByOptionPlugin;
diff --git a/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.html b/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.html
index d7f6fe5790..6b3672d038 100644
--- a/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.html
+++ b/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.html
@@ -1,2 +1,4 @@
{{ title }}
{{ subtitle }}
+{{ optionTitle }}
+```
diff --git a/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.ts b/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.ts
index 13530b4526..90418811bd 100644
--- a/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.ts
+++ b/examples/custom-esbuild/sanity-esbuild-app-esm/src/app/app.component.ts
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
declare const title: string;
declare const subtitle: string;
+declare const optionTitle: string;
@Component({
selector: 'app-root',
@@ -12,9 +13,11 @@ declare const subtitle: string;
export class AppComponent {
title: string;
subtitle: string;
+ optionTitle: string;
constructor() {
this.title = typeof title !== 'undefined' ? title : 'sanity-esbuild-app-esm';
this.subtitle = typeof subtitle !== 'undefined' ? subtitle : 'sanity-esbuild-app-esm subtitle';
+ this.optionTitle = typeof optionTitle !== 'undefined' ? optionTitle : 'sanity-esbuild-app-esm optionTitle';
}
}
diff --git a/examples/custom-esbuild/sanity-esbuild-app/angular.json b/examples/custom-esbuild/sanity-esbuild-app/angular.json
index 9d5f0c0b25..e639d8d2b8 100644
--- a/examples/custom-esbuild/sanity-esbuild-app/angular.json
+++ b/examples/custom-esbuild/sanity-esbuild-app/angular.json
@@ -17,7 +17,7 @@
"build": {
"builder": "@angular-builders/custom-esbuild:application",
"options": {
- "plugins": ["esbuild/define-text-plugin.js"],
+ "plugins": ["esbuild/define-text-plugin.js", {"path": "esbuild/define-text-by-option-plugin.js", "options": {"title": "sanity-esbuild-app optionTitle (compilation provided)"} }],
"outputPath": "dist/sanity-esbuild-app",
"index": "src/index.html",
"browser": "src/main.ts",
diff --git a/examples/custom-esbuild/sanity-esbuild-app/esbuild/define-text-by-option-plugin.js b/examples/custom-esbuild/sanity-esbuild-app/esbuild/define-text-by-option-plugin.js
new file mode 100644
index 0000000000..c3d072e5f1
--- /dev/null
+++ b/examples/custom-esbuild/sanity-esbuild-app/esbuild/define-text-by-option-plugin.js
@@ -0,0 +1,11 @@
+function defineTitleByOptionPlugin(pluginOptions) {
+ return {
+ name: 'define-title',
+ setup(build) {
+ const options = build.initialOptions;
+ options.define.titleByOption = JSON.stringify(pluginOptions.title);
+ },
+ };
+};
+
+module.exports = defineTitleByOptionPlugin;
diff --git a/examples/custom-esbuild/sanity-esbuild-app/esbuild/define-text-by-option-plugin.mjs b/examples/custom-esbuild/sanity-esbuild-app/esbuild/define-text-by-option-plugin.mjs
new file mode 100644
index 0000000000..7c6cf02b65
--- /dev/null
+++ b/examples/custom-esbuild/sanity-esbuild-app/esbuild/define-text-by-option-plugin.mjs
@@ -0,0 +1,11 @@
+function defineTitleByOptionPlugin(pluginOptions) {
+ return {
+ name: 'define-title',
+ setup(build) {
+ const options = build.initialOptions;
+ options.define.titleByOption = JSON.stringify(pluginOptions.title);
+ },
+ };
+};
+
+export default defineTitleByOptionPlugin;
diff --git a/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.html b/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.html
index d7f6fe5790..6b3672d038 100644
--- a/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.html
+++ b/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.html
@@ -1,2 +1,4 @@
{{ title }}
{{ subtitle }}
+{{ optionTitle }}
+```
diff --git a/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.ts b/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.ts
index f8ae812e3e..4519515d66 100644
--- a/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.ts
+++ b/examples/custom-esbuild/sanity-esbuild-app/src/app/app.component.ts
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
declare const title: string;
declare const subtitle: string;
+declare const optionTitle: string;
@Component({
selector: 'app-root',
@@ -12,9 +13,11 @@ declare const subtitle: string;
export class AppComponent {
title: string;
subtitle: string;
+ optionTitle: string;
constructor() {
this.title = typeof title !== 'undefined' ? title : 'sanity-esbuild-app';
this.subtitle = typeof subtitle !== 'undefined' ? subtitle : 'sanity-esbuild-app subtitle';
+ this.optionTitle = typeof optionTitle !== 'undefined' ? optionTitle : 'sanity-esbuild-app optionTitle';
}
}
diff --git a/packages/custom-esbuild/README.md b/packages/custom-esbuild/README.md
index 878e2570da..9c96140b20 100644
--- a/packages/custom-esbuild/README.md
+++ b/packages/custom-esbuild/README.md
@@ -100,7 +100,7 @@ Builder options:
"build": {
"builder": "@angular-builders/custom-esbuild:application",
"options": {
- "plugins": ["./esbuild/plugins.ts", "./esbuild/plugin-2.js"],
+ "plugins": ["./esbuild/plugins.ts", { "path": "./esbuild/plugin-2.js", "options": { "key": "value" } }],
"indexHtmlTransformer": "./esbuild/index-html-transformer.js",
"outputPath": "dist/my-cool-client",
"index": "src/index.html",
@@ -112,7 +112,7 @@ Builder options:
In the above example, we specify the list of `plugins` that should implement the ESBuild plugin schema. These plugins are custom user plugins and are added to the original ESBuild Angular configuration. Additionally, the `indexHtmlTransformer` property is used to specify the path to the file that exports the function used to modify the `index.html`.
-The plugin file can export either a single plugin or a list of plugins:
+The plugin file can export either a single plugin, a single plugin with configuration or a list of plugins:
```ts
// esbuild/plugins.ts
@@ -129,6 +129,25 @@ const defineTextPlugin: Plugin = {
export default defineTextPlugin;
```
+OR:
+
+```ts
+// esbuild/plugins.ts
+import type { Plugin, PluginBuild } from 'esbuild';
+
+function defineRewritePathPlugin(options: { text: string }): Plugin {
+ return {
+ name: 'define-text',
+ setup(build: PluginBuild) {
+ const options = build.initialOptions;
+ options.define.buildText = JSON.stringify(options.text);
+ },
+ };
+};
+
+export default defineTextPlugin;
+```
+
Or:
```ts
diff --git a/packages/custom-esbuild/src/application/schema.ext.json b/packages/custom-esbuild/src/application/schema.ext.json
index 01e7e7dd8f..f3ab84900b 100644
--- a/packages/custom-esbuild/src/application/schema.ext.json
+++ b/packages/custom-esbuild/src/application/schema.ext.json
@@ -7,7 +7,25 @@
"description": "A list of paths to ESBuild plugins",
"default": [],
"items": {
- "type": "string",
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "options": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "path"
+ ]
+ }
+ ],
"uniqueItems": true
}
},
diff --git a/packages/custom-esbuild/src/custom-esbuild-schema.ts b/packages/custom-esbuild/src/custom-esbuild-schema.ts
index eac9dc1e86..59c07d6e3e 100644
--- a/packages/custom-esbuild/src/custom-esbuild-schema.ts
+++ b/packages/custom-esbuild/src/custom-esbuild-schema.ts
@@ -1,5 +1,7 @@
import { ApplicationBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
+export type PluginConfig = string | { path: string; options?: Record };
+
export type CustomEsbuildApplicationSchema = ApplicationBuilderOptions & {
plugins?: string[];
indexHtmlTransformer?: string;
diff --git a/packages/custom-esbuild/src/load-plugins.ts b/packages/custom-esbuild/src/load-plugins.ts
index f0e154943b..f31a0adb97 100644
--- a/packages/custom-esbuild/src/load-plugins.ts
+++ b/packages/custom-esbuild/src/load-plugins.ts
@@ -2,17 +2,25 @@ import * as path from 'node:path';
import type { Plugin } from 'esbuild';
import type { logging } from '@angular-devkit/core';
import { loadModule } from '@angular-builders/common';
+import { PluginConfig } from './custom-esbuild-schema';
export async function loadPlugins(
- paths: string[] | undefined,
+ pluginConfig: PluginConfig[] | undefined,
workspaceRoot: string,
tsConfig: string,
- logger: logging.LoggerApi
+ logger: logging.LoggerApi,
): Promise {
const plugins = await Promise.all(
- (paths || []).map(pluginPath =>
- loadModule(path.join(workspaceRoot, pluginPath), tsConfig, logger)
- )
+ (pluginConfig || []).map(async pluginConfig => {
+ if (typeof pluginConfig === 'string') {
+ return loadModule(path.join(workspaceRoot, pluginConfig), tsConfig, logger);
+ } else {
+ const pluginFactory = await loadModule(path.join(workspaceRoot, pluginConfig.path), tsConfig, logger);
+ return pluginFactory(pluginConfig.options);
+ }
+
+ },
+ ),
);
return plugins.flat();