aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar dave caruso <me@paperdave.net> 2023-05-11 22:58:41 -0400
committerGravatar GitHub <noreply@github.com> 2023-05-11 22:58:41 -0400
commitdfd0f3e2527daffa06da791ccaed7dfe3240963e (patch)
tree535d9c676190d50e04194d78d2efba98ee9317cb /src
parent136b50c74639cb1f583435a318d283028ee57dc5 (diff)
downloadbun-dfd0f3e2527daffa06da791ccaed7dfe3240963e.tar.gz
bun-dfd0f3e2527daffa06da791ccaed7dfe3240963e.tar.zst
bun-dfd0f3e2527daffa06da791ccaed7dfe3240963e.zip
Allow reading config from within plugins, and partially implement esbuild `initialOptions` (#2861)
* Implement plugin build.config and initialOptions * update types * default initialoptions entrypoints
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/api/JSBundler.zig207
-rw-r--r--src/bun.js/bindings/JSBundlerPlugin.cpp4
-rw-r--r--src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp24
-rw-r--r--src/bun.js/builtins/cpp/BundlerPluginBuiltins.h2
-rw-r--r--src/bun.js/builtins/js/BundlerPlugin.js22
5 files changed, 152 insertions, 107 deletions
diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig
index 04ca81a8c..f17fe99d1 100644
--- a/src/bun.js/api/JSBundler.zig
+++ b/src/bun.js/api/JSBundler.zig
@@ -83,6 +83,108 @@ pub const JSBundler = struct {
errdefer this.deinit(allocator);
errdefer if (plugins.*) |plugin| plugin.deinit();
+ // Plugins must be resolved first as they are allowed to mutate the config JSValue
+ if (try config.getArray(globalThis, "plugins")) |array| {
+ var iter = array.arrayIterator(globalThis);
+ while (iter.next()) |plugin| {
+ if (try plugin.getObject(globalThis, "SECRET_SERVER_COMPONENTS_INTERNALS")) |internals| {
+ if (internals.get(globalThis, "router")) |router_value| {
+ if (router_value.as(JSC.API.FileSystemRouter) != null) {
+ this.server_components.router.set(globalThis, router_value);
+ } else {
+ globalThis.throwInvalidArguments("Expected router to be a Bun.FileSystemRouter", .{});
+ return error.JSError;
+ }
+ }
+
+ const directive_object = (try internals.getObject(globalThis, "directive")) orelse {
+ globalThis.throwInvalidArguments("Expected directive to be an object", .{});
+ return error.JSError;
+ };
+
+ if (try directive_object.getArray(globalThis, "client")) |client_names_array| {
+ var array_iter = client_names_array.arrayIterator(globalThis);
+ while (array_iter.next()) |client_name| {
+ var slice = client_name.toSliceOrNull(globalThis) orelse {
+ globalThis.throwInvalidArguments("Expected directive.client to be an array of strings", .{});
+ return error.JSException;
+ };
+ defer slice.deinit();
+ try this.server_components.client.append(allocator, OwnedString.initCopy(allocator, slice.slice()) catch unreachable);
+ }
+ } else {
+ globalThis.throwInvalidArguments("Expected directive.client to be an array of strings", .{});
+ return error.JSException;
+ }
+
+ if (try directive_object.getArray(globalThis, "server")) |server_names_array| {
+ var array_iter = server_names_array.arrayIterator(globalThis);
+ while (array_iter.next()) |server_name| {
+ var slice = server_name.toSliceOrNull(globalThis) orelse {
+ globalThis.throwInvalidArguments("Expected directive.server to be an array of strings", .{});
+ return error.JSException;
+ };
+ defer slice.deinit();
+ try this.server_components.server.append(allocator, OwnedString.initCopy(allocator, slice.slice()) catch unreachable);
+ }
+ } else {
+ globalThis.throwInvalidArguments("Expected directive.server to be an array of strings", .{});
+ return error.JSException;
+ }
+
+ continue;
+ }
+
+ // var decl = PluginDeclaration{
+ // .name = OwnedString.initEmpty(allocator),
+ // .setup = .{},
+ // };
+ // defer decl.deinit();
+
+ if (plugin.getOptional(globalThis, "name", ZigString.Slice) catch null) |slice| {
+ defer slice.deinit();
+ if (slice.len == 0) {
+ globalThis.throwInvalidArguments("Expected plugin to have a non-empty name", .{});
+ return error.JSError;
+ }
+ } else {
+ globalThis.throwInvalidArguments("Expected plugin to have a name", .{});
+ return error.JSError;
+ }
+
+ const function = (plugin.getFunction(globalThis, "setup") catch null) orelse {
+ globalThis.throwInvalidArguments("Expected plugin to have a setup() function", .{});
+ return error.JSError;
+ };
+
+ var bun_plugins: *Plugin = plugins.* orelse brk: {
+ plugins.* = Plugin.create(
+ globalThis,
+ switch (this.target) {
+ .bun, .bun_macro => JSC.JSGlobalObject.BunPluginTarget.bun,
+ .node => JSC.JSGlobalObject.BunPluginTarget.node,
+ else => .browser,
+ },
+ );
+ break :brk plugins.*.?;
+ };
+
+ var plugin_result = bun_plugins.addPlugin(function, config);
+
+ if (!plugin_result.isEmptyOrUndefinedOrNull()) {
+ if (plugin_result.asAnyPromise()) |promise| {
+ globalThis.bunVM().waitForPromise(promise);
+ plugin_result = promise.result(globalThis.vm());
+ }
+ }
+
+ if (plugin_result.toError()) |err| {
+ globalThis.throwValue(err);
+ return error.JSError;
+ }
+ }
+ }
+
if (try config.getOptionalEnum(globalThis, "target", options.Target)) |target| {
this.target = target;
}
@@ -289,107 +391,6 @@ pub const JSBundler = struct {
};
}
- if (try config.getArray(globalThis, "plugins")) |array| {
- var iter = array.arrayIterator(globalThis);
- while (iter.next()) |plugin| {
- if (try plugin.getObject(globalThis, "SECRET_SERVER_COMPONENTS_INTERNALS")) |internals| {
- if (internals.get(globalThis, "router")) |router_value| {
- if (router_value.as(JSC.API.FileSystemRouter) != null) {
- this.server_components.router.set(globalThis, router_value);
- } else {
- globalThis.throwInvalidArguments("Expected router to be a Bun.FileSystemRouter", .{});
- return error.JSError;
- }
- }
-
- const directive_object = (try internals.getObject(globalThis, "directive")) orelse {
- globalThis.throwInvalidArguments("Expected directive to be an object", .{});
- return error.JSError;
- };
-
- if (try directive_object.getArray(globalThis, "client")) |client_names_array| {
- var array_iter = client_names_array.arrayIterator(globalThis);
- while (array_iter.next()) |client_name| {
- var slice = client_name.toSliceOrNull(globalThis) orelse {
- globalThis.throwInvalidArguments("Expected directive.client to be an array of strings", .{});
- return error.JSException;
- };
- defer slice.deinit();
- try this.server_components.client.append(allocator, OwnedString.initCopy(allocator, slice.slice()) catch unreachable);
- }
- } else {
- globalThis.throwInvalidArguments("Expected directive.client to be an array of strings", .{});
- return error.JSException;
- }
-
- if (try directive_object.getArray(globalThis, "server")) |server_names_array| {
- var array_iter = server_names_array.arrayIterator(globalThis);
- while (array_iter.next()) |server_name| {
- var slice = server_name.toSliceOrNull(globalThis) orelse {
- globalThis.throwInvalidArguments("Expected directive.server to be an array of strings", .{});
- return error.JSException;
- };
- defer slice.deinit();
- try this.server_components.server.append(allocator, OwnedString.initCopy(allocator, slice.slice()) catch unreachable);
- }
- } else {
- globalThis.throwInvalidArguments("Expected directive.server to be an array of strings", .{});
- return error.JSException;
- }
-
- continue;
- }
-
- // var decl = PluginDeclaration{
- // .name = OwnedString.initEmpty(allocator),
- // .setup = .{},
- // };
- // defer decl.deinit();
-
- if (plugin.getOptional(globalThis, "name", ZigString.Slice) catch null) |slice| {
- defer slice.deinit();
- if (slice.len == 0) {
- globalThis.throwInvalidArguments("Expected plugin to have a non-empty name", .{});
- return error.JSError;
- }
- } else {
- globalThis.throwInvalidArguments("Expected plugin to have a name", .{});
- return error.JSError;
- }
-
- const function = (plugin.getFunction(globalThis, "setup") catch null) orelse {
- globalThis.throwInvalidArguments("Expected plugin to have a setup() function", .{});
- return error.JSError;
- };
-
- var bun_plugins: *Plugin = plugins.* orelse brk: {
- plugins.* = Plugin.create(
- globalThis,
- switch (this.target) {
- .bun, .bun_macro => JSC.JSGlobalObject.BunPluginTarget.bun,
- .node => JSC.JSGlobalObject.BunPluginTarget.node,
- else => .browser,
- },
- );
- break :brk plugins.*.?;
- };
-
- var plugin_result = bun_plugins.addPlugin(function);
-
- if (!plugin_result.isEmptyOrUndefinedOrNull()) {
- if (plugin_result.asAnyPromise()) |promise| {
- globalThis.bunVM().waitForPromise(promise);
- plugin_result = promise.result(globalThis.vm());
- }
- }
-
- if (plugin_result.toError()) |err| {
- globalThis.throwValue(err);
- return error.JSError;
- }
- }
- }
-
return this;
}
@@ -911,11 +912,12 @@ pub const JSBundler = struct {
pub fn addPlugin(
this: *Plugin,
object: JSC.JSValue,
+ config: JSC.JSValue,
) JSValue {
JSC.markBinding(@src());
const tracer = bun.tracy.traceNamed(@src(), "JSBundler.addPlugin");
defer tracer.end();
- return JSBundlerPlugin__runSetupFunction(this, object);
+ return JSBundlerPlugin__runSetupFunction(this, object, config);
}
pub fn deinit(this: *Plugin) void {
@@ -934,6 +936,7 @@ pub const JSBundler = struct {
extern fn JSBundlerPlugin__runSetupFunction(
*Plugin,
JSC.JSValue,
+ JSC.JSValue,
) JSValue;
pub export fn JSBundlerPlugin__addError(
diff --git a/src/bun.js/bindings/JSBundlerPlugin.cpp b/src/bun.js/bindings/JSBundlerPlugin.cpp
index 5f1d5c96b..279673afb 100644
--- a/src/bun.js/bindings/JSBundlerPlugin.cpp
+++ b/src/bun.js/bindings/JSBundlerPlugin.cpp
@@ -375,7 +375,8 @@ extern "C" Bun::JSBundlerPlugin* JSBundlerPlugin__create(Zig::GlobalObject* glob
extern "C" EncodedJSValue JSBundlerPlugin__runSetupFunction(
Bun::JSBundlerPlugin* plugin,
- EncodedJSValue encodedSetupFunction)
+ EncodedJSValue encodedSetupFunction,
+ EncodedJSValue encodedConfig)
{
auto& vm = plugin->vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
@@ -390,6 +391,7 @@ extern "C" EncodedJSValue JSBundlerPlugin__runSetupFunction(
MarkedArgumentBuffer arguments;
arguments.append(JSValue::decode(encodedSetupFunction));
+ arguments.append(JSValue::decode(encodedConfig));
auto* lexicalGlobalObject = jsCast<JSFunction*>(JSValue::decode(encodedSetupFunction))->globalObject();
auto result = JSC::call(lexicalGlobalObject, setupFunction, callData, plugin, arguments);
diff --git a/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp b/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp
index be049ae13..f66e568a3 100644
--- a/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp
+++ b/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp
@@ -202,10 +202,10 @@ const char* const s_bundlerPluginRunOnResolvePluginsCode =
const JSC::ConstructAbility s_bundlerPluginRunSetupFunctionCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_bundlerPluginRunSetupFunctionCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_bundlerPluginRunSetupFunctionCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_bundlerPluginRunSetupFunctionCodeLength = 3794;
+const int s_bundlerPluginRunSetupFunctionCodeLength = 4551;
static const JSC::Intrinsic s_bundlerPluginRunSetupFunctionCodeIntrinsic = JSC::NoIntrinsic;
const char* const s_bundlerPluginRunSetupFunctionCode =
- "(function (setup) {\n" \
+ "(function (setup, config) {\n" \
" \"use strict\";\n" \
" var onLoadPlugins = new Map(),\n" \
" onResolvePlugins = new Map();\n" \
@@ -271,6 +271,10 @@ const char* const s_bundlerPluginRunSetupFunctionCode =
" @throwTypeError(\"On-dispose callbacks are not implemented yet. See https:/\\/github.com/oven-sh/bun/issues/2771\");\n" \
" }\n" \
"\n" \
+ " function onDispose(callback) {\n" \
+ " @throwTypeError(\"build.resolve() is not implemented yet. See https:/\\/github.com/oven-sh/bun/issues/2771\");\n" \
+ " }\n" \
+ "\n" \
" const processSetupResult = () => {\n" \
" var anyOnLoad = false,\n" \
" anyOnResolve = false;\n" \
@@ -327,11 +331,27 @@ const char* const s_bundlerPluginRunSetupFunctionCode =
" };\n" \
"\n" \
" var setupResult = setup({\n" \
+ " config,\n" \
" onDispose,\n" \
" onEnd,\n" \
" onLoad,\n" \
" onResolve,\n" \
" onStart,\n" \
+ " resolve,\n" \
+ " //\n" \
+ " initialOptions: {\n" \
+ " ...config,\n" \
+ " bundle: true,\n" \
+ " entryPoints: config.entrypoints ?? config.entryPoints ?? [],\n" \
+ " minify: typeof config.minify === 'boolean' ? config.minify : false,\n" \
+ " minifyIdentifiers: config.minify === true || config.minify?.identifiers,\n" \
+ " minifyWhitespace: config.minify === true || config.minify?.whitespace,\n" \
+ " minifySyntax: config.minify === true || config.minify?.syntax,\n" \
+ " outbase: config.root,\n" \
+ " platform: config.target === 'bun' ? 'node' : config.target,\n" \
+ " root: undefined,\n" \
+ " },\n" \
+ " esbuild: {},\n" \
" });\n" \
"\n" \
" if (setupResult && @isPromise(setupResult)) {\n" \
diff --git a/src/bun.js/builtins/cpp/BundlerPluginBuiltins.h b/src/bun.js/builtins/cpp/BundlerPluginBuiltins.h
index 91b3233f2..d1fdaf4ec 100644
--- a/src/bun.js/builtins/cpp/BundlerPluginBuiltins.h
+++ b/src/bun.js/builtins/cpp/BundlerPluginBuiltins.h
@@ -65,7 +65,7 @@ extern const JSC::ImplementationVisibility s_bundlerPluginRunOnLoadPluginsCodeIm
#define WEBCORE_FOREACH_BUNDLERPLUGIN_BUILTIN_DATA(macro) \
macro(runOnResolvePlugins, bundlerPluginRunOnResolvePlugins, 5) \
- macro(runSetupFunction, bundlerPluginRunSetupFunction, 1) \
+ macro(runSetupFunction, bundlerPluginRunSetupFunction, 2) \
macro(runOnLoadPlugins, bundlerPluginRunOnLoadPlugins, 4) \
#define WEBCORE_BUILTIN_BUNDLERPLUGIN_RUNONRESOLVEPLUGINS 1
diff --git a/src/bun.js/builtins/js/BundlerPlugin.js b/src/bun.js/builtins/js/BundlerPlugin.js
index ec8fee397..43f6e889a 100644
--- a/src/bun.js/builtins/js/BundlerPlugin.js
+++ b/src/bun.js/builtins/js/BundlerPlugin.js
@@ -178,7 +178,7 @@ function runOnResolvePlugins(
}
}
-function runSetupFunction(setup) {
+function runSetupFunction(setup, config) {
"use strict";
var onLoadPlugins = new Map(),
onResolvePlugins = new Map();
@@ -244,6 +244,10 @@ function runSetupFunction(setup) {
@throwTypeError("On-dispose callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771");
}
+ function onDispose(callback) {
+ @throwTypeError("build.resolve() is not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771");
+ }
+
const processSetupResult = () => {
var anyOnLoad = false,
anyOnResolve = false;
@@ -300,11 +304,27 @@ function runSetupFunction(setup) {
};
var setupResult = setup({
+ config,
onDispose,
onEnd,
onLoad,
onResolve,
onStart,
+ resolve,
+ // esbuild's options argument is different, we provide some interop
+ initialOptions: {
+ ...config,
+ bundle: true,
+ entryPoints: config.entrypoints ?? config.entryPoints ?? [],
+ minify: typeof config.minify === 'boolean' ? config.minify : false,
+ minifyIdentifiers: config.minify === true || config.minify?.identifiers,
+ minifyWhitespace: config.minify === true || config.minify?.whitespace,
+ minifySyntax: config.minify === true || config.minify?.syntax,
+ outbase: config.root,
+ platform: config.target === 'bun' ? 'node' : config.target,
+ root: undefined,
+ },
+ esbuild: {},
});
if (setupResult && @isPromise(setupResult)) {