Skip to content
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

Experimental esm support #14

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

fullkomnun
Copy link

Followed this migration guide by Hardhat to try leverage the experimental support for ESM typescript hardhat projects using hardhat-deploy plugin.

  • Updated hardhat to v2.19.4 that has required ESM support for TS projects
  • Updated package.json and tsconfig.json according to the guide with some extras for ts-config
  • hardhat.config (and any related setup utils) must remain CJS but tests and scripts could be either CJS or ESM
  • 'typechain' gets treated as CJS as suggested in the guide and Ethers related types are preferablty imported via some common CJS module to avoid type-check chaos
  • Unfortunately, you have to define NODE_OPTIONS='--loader ts-node/esm/transpile-only --no-warnings=ExperimentalWarning' but at least when using mocha directly (via .'mocharc') or the wrapper script you can hide this verbosity and apply type checking conditionally based on HARDHAT_TYPECHECK env var

I monkey-patched hardhat-deploy so it can support loading of CJS modules as it previously did using 'require' or when consuming project is configured to use expermiental ESM support - it can load either CJS/ESM scripts using dynamic import (withg some workaround to mitigate default exports). All use-cases work!
I looked into creating a PR in hardhat-deploy repo but had some issues since AFAIK hardhat and its plugins themselves currently must remain CJS. Here's the patched loading raw JS:

async function dynamicImportModule(path) {
  // Adjust the function to handle both ESM and CJS modules uniformly
  let module;
  try {
    module = await import(path);
  } catch (error) {
    if (error.code === 'ERR_REQUIRE_ESM') {
        // The error indicates that the module is an ESM
        throw error;
    } else {
        // Fallback to CommonJS require
        module = require(path);
    }
  }
  // Check if the module has a 'default' property and if it looks like a wrapped CJS module
  if (module.default && typeof module.default === 'object' && 'default' in module.default) {
      // This is a workaround for the double 'default' wrapping issue
      return module.default.default;
  } else if (module.default) {
      // Handle normal ESM default export
      return module.default;
  } else {
      // Return the module directly if it's not using ESM default export
      return module;
  }
}

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