Skip to content

Commit

Permalink
feat(custom-esbuild): add support for plugin configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
spike-rabbit committed Feb 16, 2024
1 parent a64a028 commit 81890a5
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
<h1>{{ title }}</h1>
<h2>{{ subtitle }}</h2>
<h3>{{ optionTitle }}</h3>
```
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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';
}
}
2 changes: 1 addition & 1 deletion examples/custom-esbuild/sanity-esbuild-app/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
<h1>{{ title }}</h1>
<h2>{{ subtitle }}</h2>
<h3>{{ optionTitle }}</h3>
```
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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';
}
}
23 changes: 21 additions & 2 deletions packages/custom-esbuild/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
Expand All @@ -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
Expand Down
20 changes: 19 additions & 1 deletion packages/custom-esbuild/src/application/schema.ext.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
},
Expand Down
2 changes: 2 additions & 0 deletions packages/custom-esbuild/src/custom-esbuild-schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ApplicationBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';

export type PluginConfig = string | { path: string; options?: Record<string, unknown> };

export type CustomEsbuildApplicationSchema = ApplicationBuilderOptions & {
plugins?: string[];
indexHtmlTransformer?: string;
Expand Down
18 changes: 13 additions & 5 deletions packages/custom-esbuild/src/load-plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Plugin[]> {
const plugins = await Promise.all(
(paths || []).map(pluginPath =>
loadModule<Plugin | Plugin[]>(path.join(workspaceRoot, pluginPath), tsConfig, logger)
)
(pluginConfig || []).map(async pluginConfig => {
if (typeof pluginConfig === 'string') {
return loadModule<Plugin | Plugin[]>(path.join(workspaceRoot, pluginConfig), tsConfig, logger);
} else {
const pluginFactory = await loadModule<Plugin>(path.join(workspaceRoot, pluginConfig.path), tsConfig, logger);
return pluginFactory(pluginConfig.options);
}

},
),
);

return plugins.flat();
Expand Down

0 comments on commit 81890a5

Please sign in to comment.