@devvit/build-pack 0.11.1 → 0.11.2-next-2024-10-21-e213fb2ae.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import type { Metadata } from '@devvit/protos';
2
2
  import { type CompileParams, CompileResponse } from '@devvit/protos/types/devvit/plugin/buildpack/buildpack_common.js';
3
- import type { ActorSpec } from '@devvit/protos/types/devvit/runtime/bundle.js';
3
+ import { type ActorSpec, TargetRuntime } from '@devvit/protos/types/devvit/runtime/bundle.js';
4
4
  import type { Namespace } from '@devvit/shared-types/Namespace.js';
5
5
  import { Observable } from 'rxjs';
6
6
  import type { BuildPack, ProjectRootDir } from '../lib/BuildPack.js';
@@ -21,6 +21,7 @@ type ESBuildPackOptions = {
21
21
  readonly typeChecker?: TypeChecker | undefined;
22
22
  /** @deprecated use the type checker where possible. */
23
23
  readonly disableTypeCheckerWarning?: boolean | undefined;
24
+ readonly targetRuntimes?: TargetRuntime[] | undefined;
24
25
  };
25
26
  export declare class ESBuildPack implements BuildPack {
26
27
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"ESBuildPack.d.ts","sourceRoot":"","sources":["../../src/esbuild/ESBuildPack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAEL,KAAK,aAAa,EAClB,eAAe,EAEhB,MAAM,kEAAkE,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,+CAA+C,CAAC;AAG/F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAKnE,OAAO,EAAmB,UAAU,EAAW,MAAM,MAAM,CAAC;AAI5D,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAS5D,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEhD,qBAAa,OAAO;;IAqBlB;;;OAGG;gBAED,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC9B,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;IAuBpC,aAAa,IAAI,UAAU,CAAC,eAAe,CAAC;IAItC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA2E/B;AAED,KAAK,kBAAkB,GAAG;IACxB,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/C,uDAAuD;IACvD,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1D,CAAC;AAEF,qBAAa,WAAY,YAAW,SAAS;;IAiB3C;;;OAGG;gBACS,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC;IAO5E,OAAO,CACX,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,aAAa,EACzC,SAAS,EAAE,QAAQ,GAAG,SAAS,GAC9B,OAAO,CAAC,eAAe,CAAC;IAoDrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,KAAK,CACH,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,aAAa,EACjC,SAAS,EAAE,QAAQ,GAAG,SAAS,GAC9B,UAAU,CAAC,eAAe,CAAC;CAe/B"}
1
+ {"version":3,"file":"ESBuildPack.d.ts","sourceRoot":"","sources":["../../src/esbuild/ESBuildPack.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAGL,KAAK,aAAa,EAClB,eAAe,EAEhB,MAAM,kEAAkE,CAAC;AAC1E,OAAO,EACL,KAAK,SAAS,EAEd,aAAa,EACd,MAAM,+CAA+C,CAAC;AAIvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAKnE,OAAO,EAAmB,UAAU,EAAW,MAAM,MAAM,CAAC;AAI5D,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAgB5D,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEhD,qBAAa,OAAO;;IA0BlB;;;OAGG;gBAED,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC9B,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;IAwBpC,aAAa,IAAI,UAAU,CAAC,eAAe,CAAC;IAItC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA2G/B;AAED,KAAK,kBAAkB,GAAG;IACxB,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/C,uDAAuD;IACvD,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;CACvD,CAAC;AAEF,qBAAa,WAAY,YAAW,SAAS;;IAiB3C;;;OAGG;gBACS,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC;IAO5E,OAAO,CACX,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,aAAa,EACzC,SAAS,EAAE,QAAQ,GAAG,SAAS,GAC9B,OAAO,CAAC,eAAe,CAAC;IA8DrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,KAAK,CACH,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,aAAa,EACjC,SAAS,EAAE,QAAQ,GAAG,SAAS,GAC9B,UAAU,CAAC,eAAe,CAAC;CAe/B"}
@@ -9,9 +9,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _Watcher_instances, _Watcher_disableExternDevvitProtos, _Watcher_typeChecker, _Watcher_root, _Watcher_observable, _Watcher_disposedNotifier, _Watcher_disposeWatcher, _Watcher_namespace, _Watcher_init, _Watcher_onBuildEnd, _ESBuildPack_bundleWatchers, _ESBuildPack_namespace, _ESBuildPack_disableExternDevvitProtos, _ESBuildPack_typeChecker, _ESBuildPack_disableTypeCheckerWarning;
12
+ var _Watcher_instances, _Watcher_disableExternDevvitProtos, _Watcher_typeChecker, _Watcher_targetRuntimes, _Watcher_root, _Watcher_observable, _Watcher_disposedNotifier, _Watcher_disposeWatcher, _Watcher_namespace, _Watcher_buildTargets, _Watcher_ready, _Watcher_init, _Watcher_makeEsbuildContext, _Watcher_onBuildEnd, _ESBuildPack_bundleWatchers, _ESBuildPack_namespace, _ESBuildPack_disableExternDevvitProtos, _ESBuildPack_typeChecker, _ESBuildPack_disableTypeCheckerWarning;
13
+ import crypto from 'node:crypto';
13
14
  import fs from 'node:fs';
14
- import { CompileLog, CompileResponse, Minify, } from '@devvit/protos/types/devvit/plugin/buildpack/buildpack_common.js';
15
+ import { Bundle, CompileLog, CompileResponse, Minify, } from '@devvit/protos/types/devvit/plugin/buildpack/buildpack_common.js';
16
+ import { TargetRuntime, } from '@devvit/protos/types/devvit/runtime/bundle.js';
17
+ import { CircuitBreak } from '@devvit/shared-types/CircuitBreaker.js';
15
18
  import { ConfigImpl as Config } from '@devvit/shared-types/ConfigImpl.js';
16
19
  import { assertNonNull, NonNull } from '@devvit/shared-types/NonNull.js';
17
20
  import { StringUtil } from '@devvit/shared-types/StringUtil.js';
@@ -28,6 +31,7 @@ const FAKE_FACTORY = {
28
31
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
32
  Build() { },
30
33
  };
34
+ const BUILD_TARGETS = [TargetRuntime.UNIVERSAL, TargetRuntime.CLIENT];
31
35
  export class Watcher {
32
36
  /**
33
37
  * The default behavior is to externalize @devvit/protos. Set
@@ -37,6 +41,7 @@ export class Watcher {
37
41
  _Watcher_instances.add(this);
38
42
  _Watcher_disableExternDevvitProtos.set(this, void 0);
39
43
  _Watcher_typeChecker.set(this, void 0);
44
+ _Watcher_targetRuntimes.set(this, void 0);
40
45
  _Watcher_root.set(this, void 0);
41
46
  /**
42
47
  * the actual emitter of updates
@@ -51,10 +56,13 @@ export class Watcher {
51
56
  */
52
57
  _Watcher_disposeWatcher.set(this, void 0);
53
58
  _Watcher_namespace.set(this, void 0);
59
+ _Watcher_buildTargets.set(this, new Map());
60
+ _Watcher_ready.set(this, void 0);
54
61
  __classPrivateFieldSet(this, _Watcher_namespace, namespace, "f");
55
62
  __classPrivateFieldSet(this, _Watcher_root, root, "f");
56
63
  __classPrivateFieldSet(this, _Watcher_disableExternDevvitProtos, options?.disableExternDevvitProtos ?? false, "f");
57
64
  __classPrivateFieldSet(this, _Watcher_typeChecker, options?.typeChecker, "f");
65
+ __classPrivateFieldSet(this, _Watcher_targetRuntimes, options?.targetRuntimes ?? BUILD_TARGETS, "f");
58
66
  // observers of this will be subscribed until this.disposedNotifier emits a value
59
67
  const sourceObservable = new Observable().pipe(takeUntil(__classPrivateFieldGet(this, _Watcher_disposedNotifier, "f")));
60
68
  // our observable is a BehaviorSubject used to multicast the source observer
@@ -62,7 +70,7 @@ export class Watcher {
62
70
  // multi-casts (shares) here
63
71
  sourceObservable.subscribe(__classPrivateFieldGet(this, _Watcher_observable, "f"));
64
72
  // #init handles errors.
65
- void __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_init).call(this, actorSpec);
73
+ __classPrivateFieldSet(this, _Watcher_ready, __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_init).call(this, actorSpec), "f");
66
74
  }
67
75
  getObservable() {
68
76
  return __classPrivateFieldGet(this, _Watcher_observable, "f");
@@ -75,22 +83,44 @@ export class Watcher {
75
83
  __classPrivateFieldGet(this, _Watcher_disposedNotifier, "f").complete();
76
84
  }
77
85
  }
78
- _Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_typeChecker = new WeakMap(), _Watcher_root = new WeakMap(), _Watcher_observable = new WeakMap(), _Watcher_disposedNotifier = new WeakMap(), _Watcher_disposeWatcher = new WeakMap(), _Watcher_namespace = new WeakMap(), _Watcher_instances = new WeakSet(), _Watcher_init = async function _Watcher_init(actorSpec) {
86
+ _Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_typeChecker = new WeakMap(), _Watcher_targetRuntimes = new WeakMap(), _Watcher_root = new WeakMap(), _Watcher_observable = new WeakMap(), _Watcher_disposedNotifier = new WeakMap(), _Watcher_disposeWatcher = new WeakMap(), _Watcher_namespace = new WeakMap(), _Watcher_buildTargets = new WeakMap(), _Watcher_ready = new WeakMap(), _Watcher_instances = new WeakSet(), _Watcher_init = async function _Watcher_init(actorSpec) {
87
+ // Building for Universal and Client targets. May include Server in the future.
88
+ for (const target of __classPrivateFieldGet(this, _Watcher_targetRuntimes, "f")) {
89
+ __classPrivateFieldGet(this, _Watcher_buildTargets, "f").set(target, {
90
+ ctx: await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_makeEsbuildContext).call(this, actorSpec, target),
91
+ });
92
+ }
93
+ __classPrivateFieldSet(this, _Watcher_disposeWatcher, async () => {
94
+ for (const [_, target] of __classPrivateFieldGet(this, _Watcher_buildTargets, "f")) {
95
+ await target.ctx.dispose();
96
+ }
97
+ }, "f");
98
+ if (__classPrivateFieldGet(this, _Watcher_observable, "f").isStopped) {
99
+ // Disposed while await-ing and prior to setting disposeWatcher.
100
+ await __classPrivateFieldGet(this, _Watcher_disposeWatcher, "f").call(this);
101
+ return;
102
+ }
103
+ const watchers = [];
104
+ for (const [_, target] of __classPrivateFieldGet(this, _Watcher_buildTargets, "f")) {
105
+ watchers.push(target.ctx.watch());
106
+ }
107
+ await Promise.all(watchers);
108
+ }, _Watcher_makeEsbuildContext = async function _Watcher_makeEsbuildContext(actorSpec, targetRuntime) {
79
109
  const entryPoint = getModuleEntrypoint(__classPrivateFieldGet(this, _Watcher_root, "f"));
80
- const cfg = esbuildConfig(__classPrivateFieldGet(this, _Watcher_disableExternDevvitProtos, "f"));
81
- const esbuildCtx = await esbuild.context({
110
+ const cfg = esbuildConfig(__classPrivateFieldGet(this, _Watcher_disableExternDevvitProtos, "f"), targetRuntime);
111
+ return await esbuild.context({
82
112
  ...cfg,
83
113
  entryPoints: [entryPoint],
84
114
  minify: false,
85
- outfile: 'main.js',
86
115
  sourcemap: 'external',
116
+ outfile: 'main.js',
87
117
  // esbuild now supports hooks through the onEnd callback in the build API.
88
118
  plugins: [
89
119
  {
90
120
  name: 'optionally-type-check-and-publish-compile-result-on-build-end',
91
121
  setup: (build) => {
92
122
  build.onEnd(async (result) => {
93
- await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_onBuildEnd).call(this, actorSpec, result, entryPoint);
123
+ await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_onBuildEnd).call(this, actorSpec, result, entryPoint, targetRuntime);
94
124
  });
95
125
  },
96
126
  },
@@ -98,21 +128,21 @@ _Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_typeChecker = new W
98
128
  ...(cfg.plugins || []),
99
129
  ],
100
130
  });
101
- if (__classPrivateFieldGet(this, _Watcher_observable, "f").isStopped) {
102
- // Disposed while await-ing and prior to setting disposeWatcher.
103
- await esbuildCtx.dispose();
104
- return;
105
- }
106
- __classPrivateFieldSet(this, _Watcher_disposeWatcher, async () => {
107
- await esbuildCtx.dispose();
108
- }, "f");
109
- await esbuildCtx.watch();
110
131
  }, _Watcher_onBuildEnd =
111
132
  /**
112
133
  * @description The callback function for esbuild's onEnd hook. This is called after esbuild has finished building.
113
134
  */
114
- async function _Watcher_onBuildEnd(actorSpec, esbuildResult, entryPoint) {
115
- const esbuildCompileRes = await newCompileResponse(__classPrivateFieldGet(this, _Watcher_namespace, "f"), actorSpec, esbuildResult, entryPoint);
135
+ async function _Watcher_onBuildEnd(actorSpec, esbuildResult, entryPoint, targetRuntime) {
136
+ await __classPrivateFieldGet(this, _Watcher_ready, "f");
137
+ __classPrivateFieldGet(this, _Watcher_buildTargets, "f").get(targetRuntime).result = esbuildResult;
138
+ const results = new Map();
139
+ // bail early if any builds are incomplete
140
+ for (const [targetRuntime, target] of __classPrivateFieldGet(this, _Watcher_buildTargets, "f")) {
141
+ if (!target.result)
142
+ return;
143
+ results.set(targetRuntime, target.result);
144
+ }
145
+ const esbuildCompileRes = await newCompileResponse(__classPrivateFieldGet(this, _Watcher_namespace, "f"), actorSpec, results, entryPoint);
116
146
  // to-do: why is type-checking disabled for projects with tsx files (nearly
117
147
  // all projects).
118
148
  if (!__classPrivateFieldGet(this, _Watcher_typeChecker, "f") || (await hasTsxFiles(__classPrivateFieldGet(this, _Watcher_root, "f")))) {
@@ -149,35 +179,39 @@ export class ESBuildPack {
149
179
  __classPrivateFieldSet(this, _ESBuildPack_disableTypeCheckerWarning, options?.disableTypeCheckerWarning ?? false, "f");
150
180
  }
151
181
  async Compile({ filename, minify, info }, _metadata) {
182
+ // TODO: add flag to conditionally compile stripped bundle
152
183
  if (filename == null) {
153
184
  // TODO: implement virtualFileSystem
154
185
  throw new Error('Bundling virtual file system not implemented yet');
155
186
  }
156
187
  assertNonNull(info, "Expected 'info' of CompileParams to be non-null");
157
188
  const entrypoint = getModuleEntrypoint(filename);
158
- let bundleResult;
159
- try {
160
- const cfg = esbuildConfig(__classPrivateFieldGet(this, _ESBuildPack_disableExternDevvitProtos, "f"));
161
- bundleResult = await esbuild.build({
162
- ...cfg,
163
- entryPoints: [entrypoint],
164
- metafile: true,
165
- sourcemap: 'external',
166
- outfile: 'main.js',
167
- plugins: [excludeNodeModulesFromSourceMapsPlugin(), ...(cfg.plugins || [])],
168
- sourcesContent: false,
169
- minify: minify === Minify.ALL,
170
- treeShaking: true,
171
- });
172
- }
173
- catch (err) {
174
- return isEsbuildResult(err)
175
- ? await newCompileResponse(__classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, err, entrypoint)
176
- : unknownToErrorCompileResponse('Compilation', err);
189
+ const buildResults = new Map();
190
+ for (const targetRuntime of BUILD_TARGETS) {
191
+ const cfg = esbuildConfig(__classPrivateFieldGet(this, _ESBuildPack_disableExternDevvitProtos, "f"), targetRuntime);
192
+ try {
193
+ const buildResult = await esbuild.build({
194
+ ...cfg,
195
+ entryPoints: [entrypoint],
196
+ metafile: true,
197
+ sourcemap: 'external',
198
+ plugins: [excludeNodeModulesFromSourceMapsPlugin(), ...(cfg.plugins || [])],
199
+ sourcesContent: false,
200
+ minify: minify === Minify.ALL,
201
+ outfile: 'main.js',
202
+ treeShaking: true,
203
+ });
204
+ buildResults.set(targetRuntime, buildResult);
205
+ }
206
+ catch (err) {
207
+ return isEsbuildResult(err)
208
+ ? await newCompileResponse(__classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, new Map([[targetRuntime, err]]), entrypoint)
209
+ : unknownToErrorCompileResponse('Compilation', err);
210
+ }
177
211
  }
178
- const esbuildCompileResult = await newCompileResponse(__classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, bundleResult, entrypoint);
179
- if (esbuildCompileResult.bundle == null) {
180
- throw new Error(esbuildCompileResult.errors?.[0].text ?? 'Missing bundle');
212
+ const esbuildCompileResult = await newCompileResponse(__classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, buildResults, entrypoint);
213
+ if (esbuildCompileResult.bundles.length === 0) {
214
+ throw new Error(esbuildCompileResult.errors?.[0]?.text ?? 'Missing bundle');
181
215
  }
182
216
  // to-do: why is type-checking disabled for projects with tsx files (nearly
183
217
  // all projects).
@@ -209,47 +243,77 @@ export class ESBuildPack {
209
243
  _ESBuildPack_bundleWatchers = new WeakMap(), _ESBuildPack_namespace = new WeakMap(), _ESBuildPack_disableExternDevvitProtos = new WeakMap(), _ESBuildPack_typeChecker = new WeakMap(), _ESBuildPack_disableTypeCheckerWarning = new WeakMap();
210
244
  // TODO: Complete way to determine dependencies from module's config.ts or config.yaml. See DX-61
211
245
  // TODO: Owner should come from project root's config file
212
- async function newCompileResponse(namespace, actorSpec, buildResult, entryPoint) {
213
- prefixBuildResultLogs(buildResult, 'esbuild');
246
+ async function newCompileResponse(namespace, actorSpec, buildResults, entryPoint) {
214
247
  assertNonNull(actorSpec, 'Expected actorSpec to be non-null');
215
- const errors = buildResult.errors.map(esbuildMessageToBuildLog);
216
- const warnings = buildResult.warnings.map(esbuildMessageToBuildLog);
217
- let code = '';
218
- let sourceMap = '';
219
- for (const outputFile of buildResult.outputFiles || []) {
220
- if (outputFile.path?.endsWith('.js')) {
221
- if (code) {
222
- throw new Error('There should only be one bundle after build');
248
+ const errors = [];
249
+ const warnings = [];
250
+ const bundles = [];
251
+ for (const [targetRuntime, buildResult] of buildResults) {
252
+ if (!buildResult)
253
+ continue;
254
+ prefixBuildResultLogs(buildResult, 'esbuild');
255
+ errors.push(...buildResult.errors.map(esbuildMessageToBuildLog));
256
+ warnings.push(...buildResult.warnings.map(esbuildMessageToBuildLog));
257
+ let code = '';
258
+ let sourceMap = '';
259
+ for (const outputFile of buildResult.outputFiles || []) {
260
+ if (outputFile.path?.endsWith('.js')) {
261
+ if (code) {
262
+ throw new Error('There should only be one bundle after build');
263
+ }
264
+ code = outputFile.text;
265
+ }
266
+ else if (outputFile.path?.endsWith('.js.map')) {
267
+ sourceMap = outputFile.text;
268
+ }
269
+ else {
270
+ throw new Error('Unexpected output file: ' + outputFile.path);
223
271
  }
224
- code = outputFile.text;
225
272
  }
226
- else if (outputFile.path?.endsWith('.js.map')) {
227
- sourceMap = outputFile.text;
273
+ if (!code) {
274
+ const errors = buildResult.errors.map(esbuildMessageToBuildLog);
275
+ const warnings = buildResult.warnings.map(esbuildMessageToBuildLog);
276
+ return CompileResponse.fromPartial({
277
+ errors,
278
+ warnings,
279
+ });
228
280
  }
229
- else {
230
- throw new Error('Unexpected output file: ' + outputFile.path);
281
+ let dependencies;
282
+ try {
283
+ const ActorClass = await dangerouslyGetBundleActor(code);
284
+ dependencies = await makeDependencySpec(namespace, actorSpec, ActorClass);
231
285
  }
232
- }
233
- if (!code)
234
- return CompileResponse.fromPartial({ errors, warnings });
235
- let dependencies;
236
- try {
237
- const ActorClass = await dangerouslyGetBundleActor(code);
238
- dependencies = await makeDependencySpec(namespace, actorSpec, ActorClass);
239
- }
240
- catch (err) {
241
- return unknownToErrorCompileResponse('Evaluation', err);
242
- }
243
- return CompileResponse.fromPartial({
244
- bundle: {
286
+ catch (err) {
287
+ return unknownToErrorCompileResponse('Evaluation', err);
288
+ }
289
+ bundles.push(Bundle.fromPartial({
245
290
  code,
246
291
  sourceMap,
247
292
  dependencies,
248
293
  buildInfo: {
249
294
  created: new Date(),
250
295
  dependencies: newBuildInfoDependencies(entryPoint),
296
+ targetRuntime,
251
297
  },
252
- },
298
+ }));
299
+ }
300
+ // remove duplicate bundles
301
+ const filteredBundles = [];
302
+ const bundleHashes = new Set();
303
+ bundles.forEach((bundle) => {
304
+ const algo = crypto.createHash('sha256');
305
+ algo.update(bundle.code);
306
+ const hash = algo.digest('hex');
307
+ if (!bundleHashes.has(hash)) {
308
+ bundleHashes.add(hash);
309
+ filteredBundles.push(bundle);
310
+ }
311
+ });
312
+ if (filteredBundles.length === 1) {
313
+ filteredBundles[0].buildInfo.targetRuntime = TargetRuntime.UNIVERSAL;
314
+ }
315
+ return CompileResponse.fromPartial({
316
+ bundles: filteredBundles,
253
317
  errors,
254
318
  warnings,
255
319
  });
@@ -290,13 +354,16 @@ function esbuildMessageToBuildLog(msg) {
290
354
  function isEsbuildResult(err) {
291
355
  return err instanceof Object && 'errors' in err && 'warnings' in err;
292
356
  }
293
- function esbuildConfig(disableExternDevvitProtos) {
357
+ function esbuildConfig(disableExternDevvitProtos, targetRuntime) {
294
358
  return {
295
359
  // Recursively inline any imported dependencies.
296
360
  bundle: true,
297
361
  // Split the @devvit/protos from the LinkedBundle. This means apps assume
298
362
  // @devvit/protos is available for import at execution time.
299
- plugins: [externalizeDevvitProtosPlugin(disableExternDevvitProtos)],
363
+ plugins: [
364
+ externalizeDevvitProtosPlugin(disableExternDevvitProtos),
365
+ ...getTargetPlugins(targetRuntime),
366
+ ],
300
367
  // to-do: uncomment once runtime is split aware and deployed everywhere.
301
368
  // external: ['@devvit/protos'],
302
369
  // Both format and target are intended to align to
@@ -340,6 +407,38 @@ function externalizeDevvitProtosPlugin(disableExternDevvitProtos) {
340
407
  },
341
408
  };
342
409
  }
410
+ function getTargetPlugins(targetRuntime) {
411
+ if (targetRuntime === TargetRuntime.CLIENT) {
412
+ return clientBundlePlugins();
413
+ }
414
+ return [];
415
+ }
416
+ function clientBundlePlugins() {
417
+ return [
418
+ {
419
+ name: 'removeServerCode',
420
+ setup(build) {
421
+ build.onResolve({ filter: /(\/server\/)|(\.server\.(js|ts)x?$)/ }, () => {
422
+ return {
423
+ path: 'server-stub.js',
424
+ namespace: 'server-only',
425
+ };
426
+ });
427
+ build.onLoad({ filter: /.*/, namespace: 'server-only' }, async () => {
428
+ const contents = `
429
+ ${CircuitBreak}
430
+ module.exports = new Proxy({}, {
431
+ has: () => true,
432
+ get: () => { throw CircuitBreak() },
433
+ apply: () => { throw CircuitBreak() },
434
+ });
435
+ `;
436
+ return { contents, loader: 'js' };
437
+ });
438
+ },
439
+ },
440
+ ];
441
+ }
343
442
  /**
344
443
  * Plugin for excluding code from inclusion in the source map by filename. This helps keep bundle size manageable.
345
444
  * @arg {RegExp} config.filter - A filter for what paths to exclude, if they match.
@@ -1 +1 @@
1
- {"version":3,"file":"TscTypeChecker.d.ts","sourceRoot":"","sources":["../../../src/esbuild/type-checkers/TscTypeChecker.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,kEAAkE,CAAC;AAC1E,OAAO,GAAG,MAAM,YAAY,CAAC;AAI7B,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqC/D;;;;GAIG;AACH,qBAAa,cAAe,YAAW,WAAW;IAC1C,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;CAehE;AAMD,wBAAgB,mCAAmC,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,GAAG,eAAe,CAyC/F"}
1
+ {"version":3,"file":"TscTypeChecker.d.ts","sourceRoot":"","sources":["../../../src/esbuild/type-checkers/TscTypeChecker.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,kEAAkE,CAAC;AAC1E,OAAO,GAAG,MAAM,YAAY,CAAC;AAI7B,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqC/D;;;;GAIG;AACH,qBAAa,cAAe,YAAW,WAAW;IAC1C,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;CAehE;AAMD,wBAAgB,mCAAmC,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,GAAG,eAAe,CA0C/F"}
@@ -84,6 +84,7 @@ export function tscTypeCheckResultToCompileResponse(emitResult) {
84
84
  }
85
85
  });
86
86
  return prefixBuildResultLogs({
87
+ bundles: [],
87
88
  errors,
88
89
  warnings,
89
90
  }, 'tsc');
package/esbuild/utils.js CHANGED
@@ -10,21 +10,21 @@ export function prefixBuildResultLogs(buildResult, prefix) {
10
10
  }
11
11
  export function mergeCompileRes(...compileRes) {
12
12
  const mergedCompileRes = CompileResponse.fromPartial({});
13
- let bundle = null;
13
+ let bundles = null;
14
14
  for (const res of compileRes) {
15
- if (res.bundle != null) {
16
- if (bundle != null) {
17
- throw new Error('Cannot merge two compile responses both with a bundle');
15
+ if (res.bundles.length > 0) {
16
+ if (bundles != null) {
17
+ throw new Error('Cannot merge two compile responses both with bundles');
18
18
  }
19
19
  else {
20
- bundle = res.bundle;
20
+ bundles = res.bundles;
21
21
  }
22
22
  }
23
23
  mergedCompileRes.errors.push(...res.errors);
24
24
  mergedCompileRes.warnings.push(...res.warnings);
25
25
  }
26
- if (bundle != null) {
27
- mergedCompileRes.bundle = bundle;
26
+ if (bundles != null) {
27
+ mergedCompileRes.bundles = bundles;
28
28
  }
29
29
  return mergedCompileRes;
30
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devvit/build-pack",
3
- "version": "0.11.1",
3
+ "version": "0.11.2-next-2024-10-21-e213fb2ae.0",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,8 +23,8 @@
23
23
  },
24
24
  "types": "./index.d.ts",
25
25
  "dependencies": {
26
- "@devvit/protos": "0.11.1",
27
- "@devvit/shared-types": "0.11.1",
26
+ "@devvit/protos": "0.11.2-next-2024-10-21-e213fb2ae.0",
27
+ "@devvit/shared-types": "0.11.2-next-2024-10-21-e213fb2ae.0",
28
28
  "esbuild": "0.23.0",
29
29
  "rxjs": "7.8.1",
30
30
  "tiny-glob": "0.2.9",
@@ -32,9 +32,9 @@
32
32
  "typescript": "5.3.2"
33
33
  },
34
34
  "devDependencies": {
35
- "@devvit/public-api": "0.11.1",
36
- "@devvit/repo-tools": "0.11.1",
37
- "@devvit/tsconfig": "0.11.1",
35
+ "@devvit/public-api": "0.11.2-next-2024-10-21-e213fb2ae.0",
36
+ "@devvit/repo-tools": "0.11.2-next-2024-10-21-e213fb2ae.0",
37
+ "@devvit/tsconfig": "0.11.2-next-2024-10-21-e213fb2ae.0",
38
38
  "@types/tsv": "0.2.1",
39
39
  "eslint": "9.11.1",
40
40
  "typescript": "5.3.2",
@@ -44,5 +44,5 @@
44
44
  "directory": "dist"
45
45
  },
46
46
  "source": "./src/index.ts",
47
- "gitHead": "b7e0214655df6dcdd70c7944b9a14b0d752577ae"
47
+ "gitHead": "50c424e97fe6c1dc8012a59acab9c76c67342a98"
48
48
  }