Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/warn-createrequire-deploy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"trigger.dev": patch
"@trigger.dev/build": patch
"@trigger.dev/core": patch
---

The `trigger.dev deploy` and `trigger.dev dev` commands now warn (with the suggested fix) when your code loads a package through `createRequire()` that won't be available in the deployed image. Previously it would fail at runtime in production to load the package. Deploys also now show bundler warnings for your code instead of discarding them.
15 changes: 14 additions & 1 deletion docs/config/extensions/custom.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default defineConfig({
extensions: [
{
name: "my-extension",
externalsForTarget: async (target) => {
externalsForTarget: (target) => {
return ["my-dependency"];
},
},
Expand All @@ -89,6 +89,19 @@ export default defineConfig({
});
```

### installedPackagesForTarget

This tells build diagnostics which packages your extension installs into the deployed image for a given target, so warnings (like the one for packages loaded via `createRequire()`) don't fire for packages that will actually be available at runtime. The bundler ignores this hook, so declaring it never changes the build output. Only implement it if your extension installs packages; extensions without it are assumed to install none.

```ts
{
name: "my-extension",
installedPackagesForTarget: (target) => {
return target === "deploy" ? ["my-dependency"] : [];
},
}
```

### onBuildStart

This hook runs before the build starts. It receives the `BuildContext` object as an argument.
Expand Down
17 changes: 17 additions & 0 deletions packages/build/src/extensions/core/additionalPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ export type AdditionalPackagesOptions = {
export function additionalPackages(options: AdditionalPackagesOptions): BuildExtension {
return {
name: "additionalPackages",
installedPackagesForTarget(target) {
if (target !== "deploy") {
return [];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · HIGH

The 'installedPackagesForTarget' hook is documented as diagnostics-only and ignored by the bundler, but the implementation in 'additionalPackages' silently swallows parse errors wi

Impact: The 'installedPackagesForTarget' hook is documented as diagnostics-only and ignored by the bundler, but the implementation in 'additionalPackages' silently swallows parse errors with 'catch { continue; }'. A typo in a package specifier (e.g. 'npm:@scope/pkg@1.0.0' malformed) will silently drop the package from diagnostics, producing a false warning with no indication of why. The user has no way to know their extensi…

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.


const names: string[] = [];

for (const pkg of options.packages) {
try {
names.push(parsePackageName(pkg).name);
} catch {
continue;
}
}

return names;
},
async onBuildStart(context) {
if (context.target !== "deploy") {
return;
Expand Down
8 changes: 8 additions & 0 deletions packages/build/src/extensions/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,14 @@ export class PrismaEngineOnlyModeExtension implements BuildExtension {
this._binaryTarget = options.binaryTarget ?? "debian-openssl-3.0.x";
}

installedPackagesForTarget(target: BuildTarget) {
if (target !== "deploy") {
return [];
}

return ["@prisma/engines"];
}

async onBuildComplete(context: BuildContext, manifest: BuildManifest) {
if (context.target === "dev") {
return;
Expand Down
1 change: 1 addition & 0 deletions packages/cli-v3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
"ini": "^5.0.0",
"json-stable-stringify": "^1.3.0",
"jsonc-parser": "3.2.1",
"@babel/parser": "^7.29.7",
"magicast": "^0.3.4",
"minimatch": "^10.0.1",
"mlly": "^1.7.1",
Expand Down
39 changes: 37 additions & 2 deletions packages/cli-v3/src/build/buildWorker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { ResolvedConfig } from "@trigger.dev/core/v3/build";
import { BuildManifest, BuildTarget } from "@trigger.dev/core/v3/schemas";
import { BundleResult, bundleWorker, createBuildManifestFromBundle } from "./bundle.js";
import {
BundleResult,
bundleWorker,
createBuildManifestFromBundle,
logBuildWarnings,
} from "./bundle.js";
import {
collectCreateRequireWarningMessages,
CreateRequireCollector,
extensionInstalledPackageMatchers,
NODE_MODULES_SEGMENT_REGEX,
} from "./createRequireWarnings.js";
import { bundleSkills } from "./bundleSkills.js";
import {
createBuildContext,
Expand Down Expand Up @@ -47,6 +58,8 @@ export async function buildWorker(options: BuildWorkerOptions) {

const resolvedConfig = options.resolvedConfig;

const extensionPackages = extensionInstalledPackageMatchers(resolvedConfig);

const externalsExtension = createExternalsBuildExtension(
options.target,
resolvedConfig,
Expand All @@ -72,6 +85,7 @@ export async function buildWorker(options: BuildWorkerOptions) {
const pluginsFromExtensions = resolvePluginsForContext(buildContext);

const sdkVersionExtractor = new SdkVersionExtractor();
const createRequireCollector = new CreateRequireCollector(resolvedConfig.workingDir);

options.listener?.onBundleStart?.();

Expand All @@ -81,7 +95,11 @@ export async function buildWorker(options: BuildWorkerOptions) {
destination: options.destination,
watch: false,
resolvedConfig,
plugins: [sdkVersionExtractor.plugin, ...pluginsFromExtensions],
plugins: [
sdkVersionExtractor.plugin,
...(options.target === "dev" ? [] : [createRequireCollector.plugin]),
...pluginsFromExtensions,
],
jsxFactory: resolvedConfig.build.jsx.factory,
jsxFragment: resolvedConfig.build.jsx.fragment,
jsxAutomatic: resolvedConfig.build.jsx.automatic,
Expand Down Expand Up @@ -127,6 +145,23 @@ export async function buildWorker(options: BuildWorkerOptions) {
buildManifest = await notifyExtensionOnBuildComplete(buildContext, buildManifest);

if (options.target !== "dev") {
const buildWarnings = [
...bundleResult.warnings.filter(
(warning) =>
!warning.location?.file || !NODE_MODULES_SEGMENT_REGEX.test(warning.location.file)
),
...collectCreateRequireWarningMessages({
usages: createRequireCollector.usages,
buildManifest,
extensionPackages,
target: options.target,
}),
];

if (buildWarnings.length > 0) {
logBuildWarnings(buildWarnings, { color: !options.plain });
}

buildManifest = options.rewritePaths
? rewriteBuildManifestPaths(buildManifest, options.destination)
: buildManifest;
Expand Down
12 changes: 10 additions & 2 deletions packages/cli-v3/src/build/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type BundleResult = {
stop: (() => Promise<void>) | undefined;
/** Maps output file paths to their content hashes for deduplication */
outputHashes: Record<string, string>;
warnings: esbuild.Message[];
};

export class BundleError extends Error {
Expand Down Expand Up @@ -323,6 +324,7 @@ export async function getBundleResultFromBuild(
contentHash: hasher.digest("hex"),
metafile: result.metafile,
outputHashes,
warnings: result.warnings,
};
}

Expand All @@ -340,8 +342,14 @@ function dirToEntryPointGlob(dir: string): string[] {
];
}

export function logBuildWarnings(warnings: esbuild.Message[]) {
const logs = esbuild.formatMessagesSync(warnings, { kind: "warning", color: true });
export function logBuildWarnings(
warnings: esbuild.PartialMessage[],
options: { color?: boolean } = {}
) {
const logs = esbuild.formatMessagesSync(warnings, {
kind: "warning",
color: options.color ?? true,
});
for (const log of logs) {
console.warn(log);
}
Expand Down
Loading