-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Unable to import from libs using ESM #109
Comments
There are ways to workaround this. I'll try to remember to come give an example later. But I wanted to say that this will become increasingly problematic over time. All that's needed is for remix to configure esbuild to not touch dynamic imports of node_modules. That's it. Then we could dynamically import all native ESM modules without trouble. |
Circling back around. I'm pretty sure this is a workaround that'll work for most folks (kinda depends on how you deploy and stuff). Basically it's important to know that:
So the solution is to create a CJS module that does the dynamic import and is not compiled by remix. One approach to this would be to create a CJS module (so it can be required by the compiled remix code) at the root of your repo (so it's not compiled by remix code) and put all the dynamic imports in there. Then your remix code can reference that module instead. So, for example: // esm-modules.js
module.exports = {
getUnistUtilVisit: async () => import('unist-util-visit'),
// other modules would be imported here.
} // app/utils/compile-mdx.server.ts
import {getUnistUtilVisit} from '../../esm-modules'
async function compileMdx() {
const {default: visit} = await getUnistUtilVisit()
// ... etc.
} I haven't tested that exactly, but I'm 99% that it'll work (perhaps with some small modifications). Note that If remix's compiler was configured to leave dynamic imports alone, then it would be much simpler. No middle-man // app/utils/compile-mdx.server.ts
async function compileMdx() {
const {default: visit} = await import('unist-util-visit')
// ... etc.
} If remix's compiler was configured to leave all imports alone (not sure what this would take), then we could set // app/utils/compile-mdx.server.ts
import {visit} from 'unist-util-visit'
async function compileMdx() {
// ... etc.
} For now, we're stuck with the Hope that helps! |
I just tried my workaround and it didn't work :( I got this error:
|
@kentcdodds That error cause by the dynamic import will be fixed soon, I have a PR out that will allow for dynamic imports to be processed correctly. Also been giving this some thought in general and one thing we could do is add some sort of "allowList" to the config that would bundle those node modules with the server build, removing the concern of cjs vs esm the same as a browser build for those specific modules. |
Love it! Thank you for working on this @jacob-ebey 👏 |
Just hit the same issue with react-markdown which is also developed by the same team. I was thinking about trying the solution from Kent like this:
module.exports = {
ReactMarkdown: () => import('react-markdown'),
};
import { ReactMarkdown as ReactMarkdownComponent } from '../../react-markdown.js';
const ReactMarkdown = React.lazy(ReactMarkdownComponent);
export default function Index() {
let data = useRouteData();
return (
<ReactMarkdown>{'# test'}</ReactMarkdown>
);
} And I end up seeing |
Hey, getting an error that looks kind of similar for some ReScript libraries (my knowledge on modules vs commonjs etc is somewhere between very patchy and nonexistent). Has this problem been addressed, and can anyone tell me if I'm facing the same problem as this issue? :)
Changing the Rescript build from
(amongst others) Thanks in advance! 😄 |
@Ferdzzzzzzzz try to move the ReScript module to a export async function someFunction() {
const {default} = await import(/* some_module */)
/**
* rest of the function
*/
} |
Hitting this same issue ... our internal UI library is ESM only, so no option to use the CJS version. Is there any kind of option available at the moment to allow certain dependencies in |
We have the same issue with our Google Analytics integration and UI libraries. |
@jacob-ebey Has this work been completed? |
Just to add a +1. I'm having the same issue as @edmundhung with react-markdown Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/niall.barber/Git/projects/react/ndb-remix/node_modules/react-markdown/index.js
require() of ES modules is not supported.
require() of /Users/niall.barber/Git/projects/react/ndb-remix/node_modules/react-markdown/index.js from /Users/niall.barber/Git/projects/react/ndb-remix/api/build/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename /Users/niall.barber/Git/projects/react/ndb-remix/node_modules/react-markdown/index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/niall.barber/Git/projects/react/ndb-remix/node_modules/react-markdown/package.json.
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1102:13)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Module.require (internal/modules/cjs/loader.js:974:19)
at require (internal/modules/cjs/helpers.js:92:18)
at Object.<anonymous> (/Users/niall.barber/Git/projects/react/ndb-remix/api/build/index.js:185:40)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Module.require (internal/modules/cjs/loader.js:974:19)
at require (internal/modules/cjs/helpers.js:92:18)
at /Users/niall.barber/Git/projects/react/ndb-remix/node_modules/@remix-run/serve/index.js:39:17
at Layer.handle [as handle_request] (/Users/niall.barber/Git/projects/react/ndb-remix/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/niall.barber/Git/projects/react/ndb-remix/node_modules/express/lib/router/route.js:137:13)
at next (/Users/niall.barber/Git/projects/react/ndb-remix/node_modules/express/lib/router/route.js:131:14) |
Looks like it's merged: #239 (review) My working setup // esm-modules.js
module.exports = {
importUnified: async () => import('unified'),
importParseMarkdown: async () => import('remark-parse'),
importGfm: async () => import('remark-gfm'),
importEmoji: async () => import('remark-emoji'),
importSlug: async () => import('remark-slug'),
importGithub: async () => import('remark-github'),
importRemarkToRehype: async () => import('remark-rehype'),
importRehypeStringify: async () => import('rehype-stringify'),
} import {
importUnified,
importParseMarkdown,
importGfm,
importEmoji,
importSlug,
importGithub,
importRemarkToRehype,
importRehypeStringify,
} from './esm-modules'
// in some async context
const { unified } = await importUnified()
const { default: parseMarkdown } = await importParseMarkdown()
const { default: gfm } = await importGfm()
const { default: emoji } = await importEmoji()
const { default: slug } = await importSlug()
const { default: github } = await importGithub()
const { default: remarkToRehype } = await importRemarkToRehype()
const { default: rehypeStringify } = await importRehypeStringify() it's not pretty, but it works |
I use But when I switched my deployment to Netlify I see my Some googling pointed me to the Netlify docs on [functions]
node_bundler = "esbuild"
external_node_modules = ["unified"] (I actually saw that the Remix Netlify template used to ship with something similar...) With that^ it looks like now Netlify does find Looks like the Unified ecosystem is firmly in the "only publish ESM" camp. The options suggested in that thread seem to rely on access to the compiler, which I know Remix doesn't want to open up too soon (which I agree with). Would love to see a tutorial where |
Probably unrelated, but I should mention that with the
But adding
|
Did some more digging. Getting mostly consistent results locally and in Netlify. When I try to hit a route that uses my
I then looked at
The Maybe the thing to try next is to use |
@edmundhung & @nialldbarber it worked for me after I downgraded react-markdown to v6.0.3 |
@Ferdzzzzzzzz I have ReScript working with Remix here: https://github.com/tom-sherman/remix-rescript-example but the solution was not pretty... It required a patch to Remix's esbuild config to exclude rescript from a specific transpilation step: https://github.com/tom-sherman/remix-rescript-example/blob/7625c5562b0bbe7a5cd435693ac2bb69c58b2b66/patches/@remix-run+dev+1.1.1.patch After applying this patch, you can set This is essentially a port of next-transpile-modules but for Remix. Judging by the number of downloads of that package (and my anecdotal experience) it's a very common requirement. @kentcdodds What are your thoughts on supporting something like a |
@tom-sherman appreciate it! Will give it a go to see just how ugly it is 😅 |
Finally got things working with Netlify deploy. See netlify/zip-it-and-ship-it#869 for the solution. One thing to note is that I did not need to use the |
@pcattori How were you able to workaround the dynamic imports error? |
I get an error that it can't get the remark modules after importing them |
@ShafSpecs I reproduced my issues/solution here: https://github.com/pcattori/remix-netlify-dynamic-imports . Specifically, I got everything working in my setup in the |
I also had the issue with |
Having the same issue with |
+1 I have the same issue with React-Flow. I've tried multiple workarounds but unsuccessful so far.. |
I created a workaround that uses @kentcdodds's method It works with a custom hook + a react context and does not need a lot of modification to the code ! |
Is there anything we can do as a community to help Remix have support for ESM modules? From a framework like this that advocates for using standards, the expectation from the community is for it to support ESM modules without any workarounds. We should be able to just do: import { somthing } from "an-esm-module"; And it should just work™. Maybe a first good step would be to make remix itself an ESM module ( |
@lukeshiru Remix already exports ESM modules for the browser bundle. The problem is with the server bundle. Still, Node's ESM vs CJS situation is a bit iffy, and some of the dependencies still don't support native ESM yet. Remix has a workaround, though; you can list the ESM only packages to be compiled to CJS during the build for the server bundle using serverdependenciestobundle. You can also take a look at importing ESM packages |
@Girish21 thanks a lot for that |
@Girish21 the thing is, that for some packages the |
@codejet yup, Remix does not know the dependency graph of modules included in |
@Girish21 thanks, but could you elaborate on that? what apart from adding the dep to |
Closing as we have guidance on dealing with ESM packages in our docs: https://remix.run/docs/en/v1/pages/gotchas#importing-esm-packages |
Do you have the code that work with react-markdown? I can't make it works |
Don't know about {
serverDependenciesToBundle: [
"character-entities",
"decode-named-character-reference",
"micromark",
"micromark-core-commonmark",
"micromark-extension-frontmatter",
"micromark-extension-gfm",
"micromark-extension-gfm-autolink-literal",
"micromark-extension-gfm-footnote",
"micromark-extension-gfm-strikethrough",
"micromark-extension-gfm-table",
"micromark-extension-gfm-tagfilter",
"micromark-extension-gfm-task-list-item",
"micromark-extension-mdx-expression",
"micromark-extension-mdx-jsx",
"micromark-extension-mdx-md",
"micromark-extension-mdxjs",
"micromark-extension-mdxjs-esm",
"micromark-factory-destination",
"micromark-factory-label",
"micromark-factory-mdx-expression",
"micromark-factory-space",
"micromark-factory-title",
"micromark-factory-whitespace",
"micromark-util-character",
"micromark-util-chunked",
"micromark-util-classify-character",
"micromark-util-combine-extensions",
"micromark-util-decode-numeric-character-reference",
"micromark-util-decode-string",
"micromark-util-encode",
"micromark-util-events-to-acorn",
"micromark-util-html-tag-name",
"micromark-util-normalize-identifier",
"micromark-util-resolve-all",
"micromark-util-sanitize-uri",
"micromark-util-subtokenize",
"micromark-util-symbol",
"micromark-util-types",
],
} And now it works like a charm both in the browser and on the server! |
@Chensokheng All I did was to stick to an older version of react-markdown (6.0.3) as suggested by another commenter (#109 (comment)) |
I have the same problem with But also other packages like |
I have tried react-markdown 6.0.3 but the issue persists. |
One of the libs I've added to |
Yeah I'm getting this too after adding it to |
this worked for me. I need to add all reps to the list, not just the parent one. Bravo! |
I'm getting the following error when trying to use
This My package.json: {
"dependencies": {
"jsdom": "^22.0.0",
"rehype-parse": "^8.0.4",
"rehype-remark": "^9.1.2",
"remark-stringify": "^10.0.3",
}
} My remix.config.js: {
"serverDependenciesToBundle": [
"bail",
"character-entities",
"comma-separated-tokens",
"decode-named-character-reference",
"hast-util-embedded",
"hast-util-from-parse5",
"hast-util-has-property",
"hast-util-is-body-ok-link",
"hast-util-is-element",
"hast-util-parse-selector",
"hast-util-phrasing",
"hast-util-to-mdast",
"hast-util-to-text",
"hast-util-whitespace",
"hastscript",
"is-plain-obj",
"longest-streak",
"mdast-util-phrasing",
"mdast-util-to-markdown",
"mdast-util-to-string",
"micromark-util-decode-numeric-character-reference",
"micromark-util-decode-string",
"property-information",
"rehype-minify-whitespace",
"rehype-parse",
"rehype-remark",
"remark-stringify",
"space-separated-tokens",
"trim-trailing-lines",
"trough",
"unified",
"unist-util-find-after",
"unist-util-is",
"unist-util-stringify-position",
"unist-util-visit-parents",
"unist-util-visit",
"vfile-location",
"vfile-message",
"vfile",
"web-namespaces",
"zwitch",
],
} I continue to get the same error even if I add "parse5" to "serverDependenciesToBundle". |
My work around for now is to downgrade jsdom to 19.0.0 and @types/jsdom to 16.2.15 in my package.json, before they upgraded to parse5 v7, and remove node_modules and package-lock.json before running This seemed to work. However, a bit later on I realized I needed to install But now I have a new problem, that "serverDependenciesToBundle" seems to ignore "mdast-util-to-markdown". I put it in {
serverDependenciesToBundle: [
"bail",
"ccount",
"character-entities",
"comma-separated-tokens",
"decode-named-character-reference",
"escape-string-regexp",
"hast-util-embedded",
"hast-util-from-parse5",
"hast-util-has-property",
"hast-util-is-body-ok-link",
"hast-util-is-element",
"hast-util-parse-selector",
"hast-util-phrasing",
"hast-util-to-mdast",
"hast-util-to-text",
"hast-util-whitespace",
"hastscript",
"is-plain-obj",
"longest-streak",
"markdown-table",
"mdast-util-find-and-replace",
"mdast-util-gfm-autolink-literal",
"mdast-util-gfm-footnote",
"mdast-util-gfm-strikethrough",
"mdast-util-gfm-table",
"mdast-util-gfm-task-list-item",
"mdast-util-gfm",
"mdast-util-phrasing",
"mdast-util-to-markdown", // <=====
"mdast-util-to-string",
"micromark-core-commonmark",
"micromark-extension-gfm-autolink-literal",
"micromark-extension-gfm-footnote",
"micromark-extension-gfm-strikethrough",
"micromark-extension-gfm-table",
"micromark-extension-gfm-tagfilter",
"micromark-extension-gfm-task-list-item",
"micromark-extension-gfm",
"micromark-factory-destination",
"micromark-factory-label",
"micromark-factory-space",
"micromark-factory-title",
"micromark-factory-whitespace",
"micromark-util-character",
"micromark-util-chunked",
"micromark-util-classify-character",
"micromark-util-combine-extensions",
"micromark-util-decode-numeric-character-reference",
"micromark-util-decode-string",
"micromark-util-encode",
"micromark-util-html-tag-name",
"micromark-util-normalize-identifier",
"micromark-util-resolve-all",
"micromark-util-sanitize-uri",
"micromark-util-subtokenize",
"parse5",
"property-information",
"rehype-minify-whitespace",
"rehype-parse",
"rehype-remark",
"remark-gfm",
"remark-stringify",
"space-separated-tokens",
"trim-trailing-lines",
"trough",
"unified",
"unist-util-find-after",
"unist-util-is",
"unist-util-stringify-position",
"unist-util-visit-parents",
"unist-util-visit",
"vfile-location",
"vfile-message",
"vfile",
"web-namespaces",
"zwitch",
],
} But even after
And the following on
Update: Bundling all packages using a blacklist instead of a whitelist fixed my issue. |
@ariofrio take a look at what I've done with Both these are deployed to here and here. I did try to go the I would have liked to call these ESM modules at compile time via |
@ariofrio thanks for posting that. Saved me a couple hours. I had the exact same issue, downgrading jsdom, sadly, was the fix. |
For anyone that is forced to stick with commonjs with remark-gfm I present an alternative dirty solution; |
The following error is thrown when trying to import from libs using ESM (like unist-util-visit):
Code which caused the error to be thrown:
The text was updated successfully, but these errors were encountered: