Skip to content

Fix resolving external packages that are ESM only #1346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 23, 2024

Conversation

ericallam
Copy link
Member

@ericallam ericallam commented Sep 23, 2024

This fixes an issue where adding an ESM only package to build.external would fail to make the dependency external and would instead bundle the import. For example, mupdf:

import { defineConfig } from "@trigger.dev/sdk/v3";

export default defineConfig({
  project: "proj_493k6ybgs5eighq72452z",
  build: {
    external: ["mupdf"],
  },
});

This is because internally we were only using the resolve package to resolve the import, which is needed to grab the version of the dependency. I've added a fallback to resolve with mlly, which handles will correctly resolve the ESM only package.

Summary by CodeRabbit

  • New Features

    • Introduced a fallback mechanism for resolving ESM-only packages, enhancing compatibility.
    • Added a new test case to validate external dependencies.
    • Created a new task that logs "Hello, World!" and integrates with the mupdf library.
  • Bug Fixes

    • Resolved issues with the mupdf package to improve functionality.
  • Documentation

    • Added configuration files for Yarn and pnpm to streamline dependency management.
  • Chores

    • Updated scripts to ensure a clean repository state upon command cancellation.

Copy link

changeset-bot bot commented Sep 23, 2024

🦋 Changeset detected

Latest commit: 3c540a9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
trigger.dev Patch
@trigger.dev/build Patch
@trigger.dev/core Patch
@trigger.dev/sdk Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

coderabbitai bot commented Sep 23, 2024

Walkthrough

The changes introduce a new mechanism for resolving external ECMAScript Module (ESM) packages, specifically addressing issues with the mupdf package. A new function, resolveSync, has been implemented to streamline dependency resolution. Additionally, several configuration and test files have been added to support ESM-only external dependencies, including a new directory structure for testing. The script for publishing has also been modified to ensure a clean state upon cancellation.

Changes

File Path Change Summary
.changeset/heavy-jobs-push.md Introduced a fallback mechanism for ESM package resolution and added the resolveSync function.
packages/cli-v3/e2e/fixtures.ts Added a new test case "esm-only-external" to validate external dependencies.
packages/cli-v3/e2e/fixtures/esm-only-external/.yarnrc.yml Added Yarn configuration to specify nodeLinker: node-modules.
packages/cli-v3/e2e/fixtures/esm-only-external/package.json Created a new package.json for the "esm-only-external" project, defining dependencies and module type.
packages/cli-v3/e2e/fixtures/esm-only-external/pnpm-workspace.yaml Added workspace configuration for pnpm to manage packages.
packages/cli-v3/e2e/fixtures/esm-only-external/src/trigger/helloWorld.ts Introduced a new task helloWorld that logs a message and integrates with mupdf.
packages/cli-v3/e2e/fixtures/esm-only-external/trigger.config.ts Added a configuration file specifying project details and marking mupdf as an external dependency.
packages/cli-v3/e2e/fixtures/esm-only-external/tsconfig.json Created a TypeScript configuration file with specific compiler options.
scripts/publish-prerelease.sh Modified the script to reset the repository state if the publish command is aborted.

Possibly related PRs

🐰 In the land of code, where rabbits play,
New paths for packages have come our way.
With resolveSync to guide us right,
ESM dependencies shine so bright!
A hop, a skip, a test or two,
Clean states await, as we code anew! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    -- I pushed a fix in commit <commit_id>, please review it.
    -- Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    -- @coderabbitai generate unit testing code for this file.
    -- @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    -- @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    -- @coderabbitai read src/utils.ts and generate unit testing code.
    -- @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    -- @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Outside diff range and nitpick comments (7)
.changeset/heavy-jobs-push.md (1)

1-5: LGTM! Consider adding more implementation details.

The changeset file correctly describes the purpose of the patch and aligns with the PR objectives. The patch version bump is appropriate for this type of fix.

Consider expanding the description to include more implementation details. For example:

-Fix resolving external packages that are ESM only by falling back to mlly resolvePathSync. This will fix mupdf
+Fix resolving external packages that are ESM only by implementing a fallback mechanism using mlly resolvePathSync. This addresses issues with packages like mupdf and improves overall compatibility with ESM-only dependencies.

This provides more context about the change and its broader impact.

packages/cli-v3/e2e/fixtures/esm-only-external/trigger.config.ts (1)

6-8: LGTM: Build configuration correctly specifies external dependency.

The build configuration properly marks "mupdf" as an external dependency, which aligns with the PR objective of fixing issues with ESM-only external packages.

Consider adding a brief comment explaining why "mupdf" is marked as external, for better maintainability. For example:

 build: {
+  // Mark "mupdf" as external to properly handle this ESM-only package
   external: ["mupdf"],
 },
packages/cli-v3/e2e/fixtures/esm-only-external/package.json (3)

5-5: LGTM: Package manager is well-specified.

The package manager specification is excellent:

  • It pins to a specific version of Yarn (4.2.2).
  • The inclusion of a SHA256 checksum enhances security and ensures consistency.

Consider adding a comment explaining the importance of the SHA256 checksum for future maintainers. For example:

"packageManager": "[email protected]+sha256.1aa43a5304405be7a7cb9cb5de7b97de9c4e8ddd3273e4dad00d6ae3eb39f0ef",
// The SHA256 checksum ensures the integrity and consistency of the Yarn version across different environments

10-12: LGTM: Workspace configuration is appropriate.

The workspace configuration is suitable for a monorepo structure:

  • It includes all directories under "packages/", which is a common pattern for organizing multiple packages.

Consider adding a README.md file in the root directory explaining the monorepo structure and the purpose of the workspaces. This would help new contributors understand the project organization quickly.


13-16: LGTM: Dependencies are well-specified and align with PR objectives.

The dependencies section is well-configured:

  • "@trigger.dev/sdk" is pinned to a specific version, ensuring consistency.
  • The inclusion of "mupdf" aligns with the PR objectives of handling ESM-only external packages.

Consider pinning the "mupdf" package to a specific version (e.g., "0.3.0" instead of "^0.3.0") to ensure consistent behavior across all environments. This is especially important for test fixtures. You can always update the version manually when needed.

packages/cli-v3/e2e/fixtures/esm-only-external/tsconfig.json (1)

4-10: ECMAScript and module settings look good, with a minor consideration.

The configuration uses modern settings appropriate for a Node.js environment with potential browser-like contexts. The use of "NodeNext" for module-related options is suitable for leveraging the latest Node.js features.

Consider enabling "verbatimModuleSyntax": true for more precise import/export syntax checking, which can help catch potential issues early in the development process.

packages/cli-v3/e2e/fixtures.ts (1)

182-215: LGTM! New test case for ESM-only external package added.

The new test case "esm-only-external" has been successfully added and aligns well with the PR objective of handling ESM-only packages. It follows the established structure of existing test cases, which is good for consistency.

Consider adding a comment above this test case to explain its specific purpose of testing ESM-only external packages. This would improve the readability and maintainability of the test suite.

+  // Test case for handling ESM-only external packages
   {
     id: "esm-only-external",
     buildManifestMatcher: {
       // ... (rest of the test case)
     },
   },
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 5cb59d8 and 3c540a9.

Files ignored due to path filters (3)
  • packages/cli-v3/e2e/fixtures/esm-only-external/package-lock.json is excluded by !**/package-lock.json
  • packages/cli-v3/e2e/fixtures/esm-only-external/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • packages/cli-v3/e2e/fixtures/esm-only-external/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
Files selected for processing (10)
  • .changeset/heavy-jobs-push.md (1 hunks)
  • packages/cli-v3/e2e/fixtures.ts (1 hunks)
  • packages/cli-v3/e2e/fixtures/esm-only-external/.yarnrc.yml (1 hunks)
  • packages/cli-v3/e2e/fixtures/esm-only-external/package.json (1 hunks)
  • packages/cli-v3/e2e/fixtures/esm-only-external/pnpm-workspace.yaml (1 hunks)
  • packages/cli-v3/e2e/fixtures/esm-only-external/src/trigger/helloWorld.ts (1 hunks)
  • packages/cli-v3/e2e/fixtures/esm-only-external/trigger.config.ts (1 hunks)
  • packages/cli-v3/e2e/fixtures/esm-only-external/tsconfig.json (1 hunks)
  • packages/cli-v3/src/build/externals.ts (4 hunks)
  • scripts/publish-prerelease.sh (1 hunks)
Additional comments not posted (18)
packages/cli-v3/e2e/fixtures/esm-only-external/.yarnrc.yml (1)

1-1: LGTM! Configuration aligns with PR objectives.

The addition of this .yarnrc.yml file with the nodeLinker: node-modules configuration is appropriate for the PR's goal of improving handling of ESM-only external packages. This setting ensures that Yarn uses the node-modules linker, which is compatible with ESM packages and should work well for the test fixtures in this directory.

packages/cli-v3/e2e/fixtures/esm-only-external/pnpm-workspace.yaml (2)

1-1: Good practice: Including reference to related issue

The comment provides a link to a GitHub issue, which is a good practice for maintaining context and traceability.


2-3: LGTM: Proper workspace configuration

The workspace configuration is correctly set up to include all immediate subdirectories of the packages directory. This is a standard practice for monorepo setups using pnpm.

packages/cli-v3/e2e/fixtures/esm-only-external/trigger.config.ts (4)

1-1: LGTM: Import statement is correct.

The import statement is properly structured, using a named import for defineConfig from the Trigger.dev SDK v3. This approach is good for maintainability and potential tree-shaking optimizations.


3-9: LGTM: Configuration object structure is correct.

The configuration object is properly exported as default and uses the defineConfig function as expected. The structure includes the necessary properties for a Trigger.dev configuration.


4-4: Verify: Is "" the intended project name?

The project name is currently set to "", which appears to be a placeholder. Please confirm if this is intentional for testing purposes, or if it should be replaced with an actual project name for production use.


5-5: LGTM: Source directory configuration is appropriate.

The dirs property is correctly set to ["./src/trigger"], which follows common conventions for organizing source files. The use of an array allows for easy addition of multiple directories in the future if needed.

packages/cli-v3/e2e/fixtures/esm-only-external/src/trigger/helloWorld.ts (2)

1-2: LGTM: Imports are correctly defined.

The imports are appropriately structured for the task requirements. The mupdf import aligns with the PR objective of handling ESM-only packages.


1-11: Overall implementation successfully meets PR objectives.

This file effectively demonstrates the integration of the ESM-only mupdf package within a Trigger.dev task. The simple nature of the helloWorld task makes it an excellent test case for verifying the new external package resolution mechanism. The implementation aligns well with the PR objectives and provides a clear example of how ESM-only packages can be utilized in the project.

packages/cli-v3/e2e/fixtures/esm-only-external/package.json (3)

1-4: LGTM: Project metadata is well-configured.

The project metadata is correctly set up:

  • The name "esm-only-external" clearly indicates its purpose.
  • It's appropriately marked as private to prevent accidental publication.
  • The "type": "module" setting is crucial for enabling ECMAScript module behavior, which aligns with the PR objectives.

17-19: Verify TypeScript version.

The TypeScript version specified (5.5.4) appears to be incorrect or not yet released. This could lead to installation issues or unexpected behavior.

Please verify the correct TypeScript version and update accordingly. You can check the latest stable version of TypeScript using the following command:

#!/bin/bash
# Description: Check the latest stable version of TypeScript

npm view typescript version

After running this command, update the TypeScript version in the package.json file to match the latest stable version or the specific version required for your project.


6-9: LGTM: Engine requirements are well-defined, but clarification needed.

The engine requirements are well-specified:

  • Yarn version matches the packageManager field, ensuring consistency.
  • Including specific versions helps maintain a consistent development environment.

Could you clarify the inclusion of pnpm in the engines field? Since Yarn is specified as the packageManager, it's unclear why pnpm is also listed. If pnpm is not actively used in the project, consider removing it to avoid confusion.

To verify pnpm usage in the project, you can run the following script:

Verification successful

LGTM: pnpm is correctly specified as the package manager.

  • The project uses pnpm as indicated by the packageManager field and the presence of pnpm-lock.yaml.
  • Yarn is listed in the engines field but does not appear to be actively used.

Consider removing Yarn from the engines field to avoid confusion.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for pnpm-related files and configurations

# Test 1: Check for pnpm-lock.yaml
if [ -f pnpm-lock.yaml ]; then
    echo "pnpm-lock.yaml found, indicating pnpm usage."
else
    echo "pnpm-lock.yaml not found."
fi

# Test 2: Check for pnpm in scripts
grep -n "pnpm" package.json

# Test 3: Check for .pnpmrc file
if [ -f .pnpmrc ]; then
    echo ".pnpmrc found, indicating pnpm configuration."
else
    echo ".pnpmrc not found."
fi

Length of output: 583

packages/cli-v3/e2e/fixtures/esm-only-external/tsconfig.json (2)

1-2: LGTM: File inclusions are appropriate.

The file inclusions cover the typical TypeScript project structure and include a specific configuration file, which seems suitable for the project's needs.


1-32: Overall, the tsconfig.json is well-configured for the project's needs.

This configuration file is appropriately set up for a modern TypeScript project, particularly one dealing with ESM-only external dependencies. It aligns well with the PR objectives of addressing issues related to ESM-only packages. The use of "NodeNext" for module-related options and the inclusion of DOM libraries suggest a versatile setup capable of handling both Node.js and browser-like environments, which is beneficial for comprehensive testing and development.

While the configuration is solid, the suggested minor enhancements (enabling unused code checks and adding source map support) could further improve the development experience and code quality. These are optional improvements and do not detract from the overall effectiveness of the current configuration.

scripts/publish-prerelease.sh (1)

31-31: Excellent addition for maintaining a clean git state

The new line git reset --hard HEAD is a valuable safety measure. It ensures that if the user aborts the publish process, the repository is returned to its original state, discarding any changes made by the script up to that point.

This addition:

  1. Improves the script's robustness by preventing unintended changes from lingering in the working directory.
  2. Aligns with the script's overall approach to maintaining a clean git state, as seen in the initial status check and the final reset after successful execution.
  3. Provides consistency in behavior, regardless of whether the script completes or is aborted.
packages/cli-v3/src/build/externals.ts (3)

385-391: Check the parameters passed to esmResolveSync

In your resolveSync function, when falling back to esmResolveSync, you are passing { url: resolveDir } as options. Please verify that:

  • The url option is correctly used in esmResolveSync and expects a file path or URL string.
  • The resolveDir variable corresponds to a valid URL or directory path required by esmResolveSync.

You can test the fallback mechanism with the following script:

#!/bin/bash
# Description: Test 'esmResolveSync' fallback with an ESM-only package

node -e "
  import { resolvePathSync } from 'mlly';
  const resolved = resolvePathSync('mupdf', { url: 'file://$PWD' });
  console.log('Resolved path:', resolved);
"

Note: Adjust 'file://$PWD' if esmResolveSync requires a different format for the url option.


16-16: Confirm the correct import of resolvePathSync from mlly

You are importing resolvePathSync from the mlly package and aliasing it as esmResolveSync. Please verify that resolvePathSync is the appropriate function to use for your fallback mechanism and that it behaves as expected in your context.

Run the following script to list the available exports from mlly and confirm that resolvePathSync is indeed exported:


69-69: Ensure resolveSync handles both CommonJS and ESM modules correctly

In line 69, you are using resolveSync(external.name, resolveDir). Please confirm that the resolveSync function correctly resolves module paths for both CommonJS and ESM modules, especially in the context of external dependencies.

Consider testing the resolution with the following script:

Comment on lines +4 to +11
export const helloWorld = task({
id: "helloWorld",
run: async () => {
console.log("Hello, World!", {
metaformat: mupdf.PDFDocument.META_FORMAT,
});
},
});
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM: Task definition is correct and demonstrates ESM package integration.

The helloWorld task is well-structured and successfully demonstrates the integration of the ESM-only mupdf package. This serves as an excellent test case for the new external package resolution mechanism.

Consider adding error handling to make the task more robust:

 export const helloWorld = task({
   id: "helloWorld",
   run: async () => {
-    console.log("Hello, World!", {
-      metaformat: mupdf.PDFDocument.META_FORMAT,
-    });
+    try {
+      console.log("Hello, World!", {
+        metaformat: mupdf.PDFDocument.META_FORMAT,
+      });
+    } catch (error) {
+      console.error("Error accessing mupdf:", error);
+      throw error; // Re-throw to ensure task failure is properly handled
+    }
   },
 });

This change will provide better visibility into any potential issues with accessing the ESM-only package.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const helloWorld = task({
id: "helloWorld",
run: async () => {
console.log("Hello, World!", {
metaformat: mupdf.PDFDocument.META_FORMAT,
});
},
});
export const helloWorld = task({
id: "helloWorld",
run: async () => {
try {
console.log("Hello, World!", {
metaformat: mupdf.PDFDocument.META_FORMAT,
});
} catch (error) {
console.error("Error accessing mupdf:", error);
throw error; // Re-throw to ensure task failure is properly handled
}
},
});

Comment on lines +11 to +31
"strict": true,
"alwaysStrict": true,
"strictPropertyInitialization": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true,
"removeComments": false,
"esModuleInterop": true,
"emitDecoratorMetadata": false,
"experimentalDecorators": false,
"downlevelIteration": true,
"isolatedModules": true,
"noUncheckedIndexedAccess": true,
"pretty": true
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Type-checking rules and compiler behaviors are well-configured, with room for minor enhancements.

The strict type-checking rules are appropriately set to catch potential issues early in the development process. The configuration prioritizes correctness and modern JavaScript features, which is commendable.

Consider the following enhancements:

  1. Enable "noUnusedLocals": true and "noUnusedParameters": true to help identify and remove unused code, improving maintainability.
  2. Add source map configuration, e.g., "sourceMap": true, to aid in debugging.

Example:

{
  "compilerOptions": {
    // ... existing options ...
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "sourceMap": true
  }
}

These changes can further improve code quality and developer experience.

const resolvedPath = nodeResolve.sync(packageName, {
basedir: args.resolveDir,
});
const resolvedPath = resolveSync(packageName, args.resolveDir);
Copy link
Contributor

Choose a reason for hiding this comment

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

Verify consistent module resolution in createExternalsCollector

At line 147, the resolveSync function is used to resolve packageName. Ensure that this function provides consistent resolution results, and consider any differences in args.resolveDir that might affect the outcome.

If there are discrepancies in resolution paths, it might lead to improperly marked externals. Double-check that args.resolveDir is the correct directory for resolving the package.

Copy link

pkg-pr-new bot commented Sep 23, 2024

pnpm add https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/build@1346
pnpm add https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/core@1346
pnpm add https://pkg.pr.new/triggerdotdev/trigger.dev@1346
pnpm add https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/sdk@1346

commit: 3c540a9

@ericallam ericallam merged commit d7a65f3 into main Sep 23, 2024
9 checks passed
@ericallam ericallam deleted the v3/fix-esm-only-external-resolving branch September 23, 2024 15:21
@coderabbitai coderabbitai bot mentioned this pull request Oct 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant