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

Add ES Modules support to Parcel Plugins #7639

Closed
jeb5 opened this issue Feb 2, 2022 · 10 comments · Fixed by #8913
Closed

Add ES Modules support to Parcel Plugins #7639

jeb5 opened this issue Feb 2, 2022 · 10 comments · Fixed by #8913

Comments

@jeb5
Copy link

jeb5 commented Feb 2, 2022

🙋 Feature request

Add ES Modules support to Parcel Plugins

🤔 Expected Behavior

Parcel Plugins ought to be able to use es6 module syntax.
import, export, etc.

😯 Current Behavior

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: .../mymoduleplugin/transformer.js
   require() of ES modules is not supported.

🔦 Context

require() is currently used when loading plugins:

let plugin = await options.packageManager.require(pluginName, resolveFrom, {
shouldAutoInstall: options.shouldAutoInstall,
});

@devongovett
Copy link
Member

Unfortunately it's pretty much impossible to support if you also want caching. Parcel needs to hook into the module system to intercept all requests so that it can keep track of all of the files a module loads. That way it can invalidate the cache when a dev dependency changes. But with ESM, node doesn't offer a good way of doing this yet.

@Codezilluh
Copy link

Why does all the example plugin code on the docs use import if one cannot actually use import to write a plugin? As one cannot use import outside of a module. Is there something I am missing in the docs?

Example (taken from https://parceljs.org/plugin-system/namer/)
image

@theobaidur
Copy link

Any update on this?

@KewlKris
Copy link

Why does all the example plugin code on the docs use import if one cannot actually use import to write a plugin? As one cannot use import outside of a module. Is there something I am missing in the docs?

This confused me tremendously and was massive headache for me. Fixed it by using require.

I may be wrong, but I think the example plugin code is run through a bundler which converts import to require before being imported and used by parcel.

@richardkmichael
Copy link
Contributor

richardkmichael commented Dec 17, 2022

Indeed the documentation examples are very confusing if import cannot actually be used in a plugin. If there is additional config to setup a transformer for plugin code, it would be very helpful if the docs mentioned it as well. Happy to PR that to the docs if someone from Parcel can explain it.

@mischnic
Copy link
Member

I may be wrong, but I think the example plugin code is run through a bundler which converts import to require before being imported and used by parcel.

That was indeed the intended meaning (and how it works for the core plugins, which are transpiled with Babel) when writing the docs. But I see how it can be misleading.

@richardkmichael
Copy link
Contributor

richardkmichael commented Dec 17, 2022

Yes, I figured the examples were taken from the Parcel source itself, which of course is transpiled when Parcel is built. it is difficult to know this though.

I got the example Resolver plugin working just now by rewriting it with Node require().

const plugin = require('@parcel/plugin');
const Resolver = plugin.Resolver;

module.exports = new Resolver({ ... });

I'm not sure how I would set up Parcel to transpile my plugin when it is loaded. Babel is of course available (for Parcel to use when transpiling my app). From the above comment, I understand this wouldn't be a good idea anyway.

@juanmirocks
Copy link

juanmirocks commented Mar 14, 2023

Until parcel supports ES modules for parcel plugins, the docs must be fixed/updated.

At least, a warning note in the docs would help tremendously to avoid the confusion.

@richardkmichael
Copy link
Contributor

richardkmichael commented Apr 23, 2023

@Slevinski I've hacked together a few plugins. One was a rudimentary transformer to substitute environment variables (e.g., REACT_*) in HTML files.

I'm unsure how simple an example would help you-- but, I ripped the code out of my simple transformer to show you my setup below, in case it's helpful. For convenience, I put it in the project directly via an npm workspace but that would be fairly easy to change (i.e., if you want to ship an actual package). The parcel docs are quite good for the actual Parcel API.

packages/parcel-transformer-public-url/index.js:

const plugin = require('@parcel/plugin');
const Transformer = plugin.Transformer;

module.exports = new Transformer({
  async loadConfig({config}) {
    // If config is needed..
  },
  async transform(opts) {

    let asset = opts.asset;

    if (asset.type === 'html') {
      // Do something with an HTML asset..
    }

    return [asset];
  }
});

packages/parcel-transformer-public-url/package.json:

{
  "name": "parcel-transformer-public-url",
  "version": "1.0.0",
  "description": "",
  "engines": {
    "parcel": "^2.8.0"
  },
  "dependencies": {
    "@parcel/plugin": "^2.8.2"
  }
}

Main package.json:

  "devDependencies": {
    "parcel-transformer-public-url": "^1.0.0",
  },
  "workspaces": [
    "packages/parcel-transformer-public-url",
  ]

@Slevinski
Copy link

@richardkmichael Thanks for the example. I was able to coble something together and get it published. It's working with a mithril project. I tried a test project with static html files, but neither the parcel dev server nor the build would load. I'll investigate more later, but for now I'm able to move forward with my project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants