markedjs / marked

A markdown parser and compiler. Built for speed.
https://marked.js.org
Other
33.01k stars 3.39k forks source link

module import/export issue #2265

Closed paddotk closed 2 years ago

paddotk commented 2 years ago

Marked version: 4.0.0

Describe the bug I updated marked in our project from ^3.0.2 to 4.0.0 (before it worked fine), and after the update I get an error marked__WEBPACK_IMPORTED_MODULE_5___default(...) is not a function when using it. It seems that the module is no longer exported properly, I tried to change the import import { marked } from 'marked' as well as using marked.parse() as shown in the readme, but that doesn't seem to help.

To Reproduce Steps to reproduce the behavior: Use a webpack/npm project, import by means of import marked from 'marked'. Use the marked() function.

UziTech commented 2 years ago

It looks like somewhere in your code you are trying to import the default export like import marked from 'marked'.

Make sure you replace all occurrences with import { marked } from 'marked'

AlanMorel commented 2 years ago

I'm using TypeScript and can also confirm that I am also experiencing the same issue on 4.0.0. I am importing it using import { marked } from "marked"; but getting 'marked' can only be imported using 'import marked = require("marked")' or a default import.. It is possible that I just need to wait until @types/marked is bumped up a major version though.

paddotk commented 2 years ago

@UziTech I tried that but didn't work... @AlanMorel From the error it looks like a Webpack issue. It also shows in my unit tests which are .js files.

AlanMorel commented 2 years ago

It seems unlikely to be a webpack-specific issue because the project I'm using Marked on is not using webpack at all.

maurelio1234 commented 2 years ago

It is possible that I just need to wait until @types/marked is bumped up a major version though.

I have the same problem and @types/marked is still in 3.X

UziTech commented 2 years ago

@types/marked v4 should be released soon

AlanMorel commented 2 years ago

Great, I believe that update to @types/marked will resolve my issue, so I will wait for that, thanks!

Side question though: any reason marked itself is not providing the typings for the library? It would both eliminate needing a separate @types/marked dependency while also ensuring that you can bump both the library and typings at the same time. Not a huge deal though, just curious.

rtjtc commented 2 years ago

Also waiting for @types/marked ... Do you guys have a workaround or maybe I should go back to previous stable version?

AlanMorel commented 2 years ago

Pretty sure your only options are wait for the updated types (which should be coming soon) or use a previous version.

paddotk commented 2 years ago

Ok, thanks. If it is the typings that cause the issue though, is there any way to omit the blocking error for now? Such as placing a // @ts-ignore comment somewhere?

jfcere commented 2 years ago

@paddotk If you are in a hurry you can always use gitpkg.now.sh and get an NPM package from the latest commit of UziTech's PR while waiting for it to be merged.

"@types/marked": "https://gitpkg.now.sh/UziTech/DefinitelyTyped/types/marked?415785793c958a98fa8902c482fe8be7959f86f6"
AlanMorel commented 2 years ago

The types have been merged and it's looking good on my end now

boazy commented 2 years ago

It seems like v4.0.0 still doesn't work with Webpack. It looks like Webpack is trying to import lib/marked.cjs as an ES6 module. If I manually remove the "browser" settings in package.json or set it to be the same as "main", webpack works. I guess this stems from the pre-ES6 module PR #1661, but I think it's safe to at least revert this PR for the short term until a better solution is available, if it causes webpack to not work at all...

UziTech commented 2 years ago

looks like webpack suggests this fix.

@boazy if you want to test that out and create a PR for that we could get it merged in.

scottlet commented 2 years ago

I'm also having issues. I'm not using webpack, typescript, babel or anything, just using ESM module to run my code in Express.

v3 works correctly, if I upgrade to v4 and switch my import from import marked from 'marked'; to import { marked } from 'marked'; I get the following error trying to run it:

/<path>/app/shared/text/format.js:1
Error [ERR_REQUIRE_ESM]: require() of ES Module /<path>/node_modules/marked/lib/marked.esm.js not supported.
Instead change the require of marked.esm.js in null to a dynamic import() which is available in all CommonJS modules.
rfgamaral commented 2 years ago

I also have the same issue when using marked in CodeSandbox.

When using marked@4.0.0, and trying to import { marked } from 'marked (using the latest @types/marked@4.0.0), marked is undefined. For now I've resorted to using marked@3.0.8 with import marked from 'marked. But it would e nice to have this fixed.

webstech commented 2 years ago

marked 4.0.1 has been released that may help with ESM instead of commonJS issues. The main entry in package.json now points to the commonJS code.

Real node ESM modules using babel will need to configure for it (unrelated to first comment).

scottlet commented 2 years ago

It seems to fix my issue, thanks!

rfgamaral commented 2 years ago

@webstech This still doesn't work for me:

const INITIAL_MARKED_OPTIONS = {
    gfm: false,
    headerIds: false,
}

// Reset Marked to the defaults and set custom options
marked.setOptions({
    ...marked.getDefaults(),
    ...INITIAL_MARKED_OPTIONS,
})

image

webstech commented 2 years ago

@webstech This still doesn't work for me:

Did you restart the editor? The types change requires that for some setups (vscode/eslint in my case). Are you getting compile errors? Pasted your code into mine and there were no complaints. _marked.marked does not show up in a search. Do you know where this is coming from?

rfgamaral commented 2 years ago

@webstech

I was actually working on CodeSandbox. Tried a couple of times but couldn't get it working.

Here's a demo:

I tried to download the sandbox (File → Export to ZIP), and did the following:

But I got this:

Failed to compile.

./src/Application.tsx
Attempted import error: 'marked' is not exported from 'marked'.
/home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/chokidar.js:17
throw new Error(
^

Error: No version of chokidar is available. Tried chokidar@2 and chokidar@3.
You could try to manually install any chokidar version.
chokidar@3: Error: Cannot find module 'chokidar'
Require stack:
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/chokidar.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/DirectoryWatcher.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/watcherManager.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/watchpack.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/webpack/lib/node/NodeWatchFileSystem.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/webpack/lib/node/NodeEnvironmentPlugin.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/webpack/lib/webpack.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/react-scripts/scripts/start.js
chokidar@2: Error: Cannot find module 'watchpack-chokidar2'
Require stack:
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/chokidar.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/DirectoryWatcher.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/watcherManager.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/watchpack.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/webpack/lib/node/NodeWatchFileSystem.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/webpack/lib/node/NodeEnvironmentPlugin.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/webpack/lib/webpack.js
- /home/Ricardo/Workspace/Playground/g0bw2/node_modules/react-scripts/scripts/start.js

    at Object.<anonymous> (/home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/chokidar.js:17:7)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:94:18)
    at Object.<anonymous> (/home/Ricardo/Workspace/Playground/g0bw2/node_modules/watchpack/lib/DirectoryWatcher.js:9:16)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)

Proceeded with npm install chokidar@3 and then npm run start again, and now I got just this:

Failed to compile.

./src/Application.tsx
Attempted import error: 'marked' is not exported from 'marked'.

The development server was launched, and a browser window opened with this:

image

image

webstech commented 2 years ago

I was actually working on CodeSandbox. Tried a couple of times but couldn't get it working.

Sorry, I missed that. Tracked this down to a different change in package.json. This line:

"browser": "./lib/marked.cjs",

is causing the problem for react apps and possibly anyone using webpack. If it is removed or points to ./lib/marked.esm.js, your react app builds and runs (obviously I did not do this on CodeSandBox).

Found a possible solution .

  "browser": {
    "./lib/marked.cjs": "./lib/marked.cjs",
    "./lib/marked.esm.js": "./lib/marked.esm.js"
  },

Ran some tests (react and marked repo) with no problems. @benmccann Do you have any thoughts on this?

I do not have a test case where the commonJS file would be used for the browser.

webstech commented 2 years ago

Related to the previous solution link, there is a mention of using exports to resolve this. vscode says exports/browser is an unknown property and it does not appear to have any affect on webpack (invalid target mappings do not cause an error). Finished chasing this angle.

NicolasCARPi commented 2 years ago

For me #2276 broke marked. The ts compiler just couldn't find marked library anymore!! 4.0.0 is fine, but 4.0.1 doesn't work in my setup (typescript + webpack). I would be in favor of reverting that change or finding a fix that works for everyone.

benmccann commented 2 years ago

I think the current setup is pretty confusing because the .cjs file isn't strictly CJS, but is UMD. I sent a PR to make that clearer without making any other changes: https://github.com/markedjs/marked/pull/2281

As far as the issues people are having here, it's really difficult to tell what's going wrong without more details. I'd encourage anyone who is having an issue to create and share a repository to reproduce the issue

It may be impossible to support all combinations of bundlers and CDNs since so many do weird things. I think the folks that are having trouble with Webpack are most likely using Webpack 4, which is somewhat broken in the way it does resolution. If you use Webpack 5, I expect it will work.

NicolasCARPi commented 2 years ago

@benmccann I tried your branch (by cloning it directly into the node_modules/marked dir). I still have an issue:

In the code (targetting the browser):

import { marked } from 'marked';

This gives the error: TS2307: Cannot find module 'marked' or its corresponding type declarations. (works fine with 4.0.0)

Trying import { marked } from 'marked/lib/marked.umd' gives: Module not found: Error: Package path ./lib/marked.umd is not exported from package /elabftw/node_modules/marked (see exports field in /elabftw/node_modules/marked/package.json), but in the editor there is no error with this import, only with the bundler.

I'm not that familiar with the export part of the package.json, but maybe it's missing something? Anyway, thanks for trying to fix this! :)

If needed, I'll try and make a reproducible small repo. Right now files are here: import line and webpack config.

webstech commented 2 years ago

I'd encourage anyone who is having an issue to create and share a repository to reproduce the issue

npx create-react-app my-ts-app --template typescript
cd my-ts-app
yarn install

Edit App.tsx to add:

import { marked } from 'marked';
...
const msg = marked.parse('# Welcome');
{msg} // somewhere in the html

Run yarn install and yarn start and it fails. It works with the changes to marked package.json I mentioned in prior comment.

Will try with the pull request updates.

UPDATE: The pull request changes work with the sample above. Webpack 5.5.

webstech commented 2 years ago

@rfgamaral Your react app also runs with #2281. Webpack 4.44.

rfgamaral commented 2 years ago

@webstech Awesome, thank you for letting me know 👍

LukeNotable commented 2 years ago

I'd encourage anyone who is having an issue to create and share a repository to reproduce the issue

My issue is similar but not identical. When I moved some code from our web app (using create-react-app) to a library, it started failing with TypeError: Cannot read properties of undefined (reading 'parse').

Repro repo here.

UziTech commented 2 years ago

@LukeNotable It looks like the issue is that typescript compiles to javascript that looks for marked.marked.parse. I'm guessing this is a typescript issue and there is probably a tsconfig setting for this.

// my-lib/dist/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useMarked = void 0;
const marked_1 = require("marked");
function useMarked() {
    return marked_1.marked.parse('# hi');
}
exports.useMarked = useMarked;
//# sourceMappingURL=index.js.map
LukeNotable commented 2 years ago

Thanks for looking!

What that transpiled code is doing looks right, especially since the Usage in the docs says we can do const { marked } = require('marked');. However, trying that explicitly even in the app fails with the same error. 🤔

So it's not really a question of app vs lib, but of import vs require, although beyond that is over my head.

ryanadhi commented 2 years ago

I also facing same issue currently typescript with "@types/marked": "^4.0.3" and got error message ERROR: Could not resolve "marked"

NicolasCARPi commented 2 years ago

@ryanadhi I resolved to fix the lib manually before building with webpack:

It's ugly but it works and I just couldn't find a way to make marked work with my build process (webpack) after 4.0.1 :/

edit: june 2023: issue is gone, script is not needed anymore

emilmuller commented 1 year ago

I just did this for now

// @ts-ignore
import { marked } from "marked/lib/marked.esm.js"; // Using full path to library
laustdeleuran commented 1 year ago

I'm also experiencing this issue on Webpack 5. I'm importing marked in a package that just compiles to JS. That compilation changes the import statement from import to require.

That package is then imported by my Webpack 5 library, that correctly installs marked as a dependency, but throws the TypeError: Cannot read properties of undefined (reading 'use') error.

If I manually change the import to point at the esm module it works. If I use Webpack's resolve functionality to point to the version I need and remove the exports declaration from the marked package, it works. That's not a workable solution, though, since the exports clause limits me to import it directly.

Any chance you could expose all the files in the lib folder in the exports clause to sidestep this issue? That would allow us to use @emilmuller's workaround with Webpack 5.

UziTech commented 1 year ago

@laustdeleuran are you importing with import { marked } from 'marked'?

laustdeleuran commented 1 year ago

@UziTech sure am:

import { marked } from 'marked';

marked.use({
  ...
});
benmccann commented 1 year ago

@laustdeleuran it's hard to understand what might be wrong in your case because you're using an intermediate package and I can't see the source of that package. Could you please share it? It's quite likely the issue may be there

laustdeleuran commented 1 year ago

@benmccann , that's fair, I wish I had a more reproducible setup.

In short, we have a monorepo using pnpm. I have a package in that repo that uses marked. The file in question looks something like:

import DOMPurify from 'isomorphic-dompurify';
import { marked } from 'marked';

marked.use({
  renderer: {
    /* ...some options here */
  },
});

export const format = (markdown: string) =>
  DOMPurify.sanitize(marked.parse(markdown, { breaks: true }));

That package compiles that to CJS, which ends up looking something like:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.format = void 0;

var _isomorphicDompurify = _interopRequireDefault(require("isomorphic-dompurify"));

var _marked = require("marked");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

_marked.marked.use({
  renderer: {
    /* ...some options here */
  }
});

const format = markdown => _isomorphicDompurify.default.sanitize(_marked.marked.parse(markdown, {
  breaks: true
}));

exports.format = format;

That module then gets imported in another project in the monorepo, which is a create-react-app. I'm trying to upgrade the react-scripts in that project, which means I'm also upgrading from Webpack 4 to Webpack 5. That upgrade is going smoothly, except for the above file now throwing the TypeError: Cannot read properties of undefined (reading 'use') error.

laustdeleuran commented 1 year ago

@benmccann, if I get rid of the exports clause in marked's package.json, or expand it to include the individual builds, I can resolve this error by overriding the webpack import using resolve:

    "alias": {
      "marked": "marked/lib/marked.esm.js",
    },

Which in effect applies @emilmuller's fix to Webpack 5.

laustdeleuran commented 1 year ago

Put up a basic stab at that fix in #2747.

benmccann commented 1 year ago

@laustdeleuran does it work any better if you change this:

import { marked } from 'marked';

marked.use({
  renderer: {
    /* ...some options here */
  },
});

To this?

import { use } from 'marked';

use({
  renderer: {
    /* ...some options here */
  },
});

Or maybe this?

import * as marked from 'marked';

marked.use({
  renderer: {
    /* ...some options here */
  },
});

There's still not enough info here to really understand what's going on. What's the package.json in the intermediate package, how is the intermediate package being bundled, etc.?

laustdeleuran commented 1 year ago
import { use } from 'marked';

As far as I can tell, marked doesn't export use directly? This just gets me a TS error:

Screenshot 2023-03-02 at 16 14 56

import * as marked from 'marked';

This just gets me the same result, as it just compiles to the same thing in CJS.


There's still not enough info here to really understand what's going on. What's the package.json in the intermediate package, how is the intermediate package being bundled, etc.?

Fair, but I don't really know how to make a small repro for you. Here's the subpackage's package.json:

{
  "private": true,
  "main": "./dist/src/index.js",
  "types": "./dist/src/index.d.ts",
  "dependencies": {
    "@babel/cli": "^7.14.8",
    "@babel/core": "^7.15.0",
    "@babel/preset-env": "^7.15.0",
    "@babel/preset-typescript": "^7.15.0",
    "@types/handlebars": "^4.1.0",
    "@types/marked": "^4.0.8",
    "babel-plugin-module-resolver": "^4.1.0",
    "date-fns": "^2.29.3",
    "handlebars": "^4.7.7",
    "imask": "^6.3.0",
    "isomorphic-dompurify": "^0.19.0",
    "lodash": "^4.17.21",
    "marked": "^4.2.12",
    "mockdate": "^3.0.2",
    "pluralize": "^8.0.0",
    "tsc-alias": "^1.3.9",
    "typescript": "^4.3.5"
  },
  "devDependencies": {
    "@types/jest": "^27.4.1",
    "@types/node": "^16.7.1",
    "@typescript-eslint/eslint-plugin": "^4.29.2",
    "@typescript-eslint/parser": "^4.29.2",
    "babel-jest": "^27.0.6",
    "eslint": "^7.32.0",
    "eslint-config-airbnb-base": "^14.2.1",
    "eslint-config-airbnb-typescript": "^13.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-import-resolver-typescript": "^2.5.0",
    "eslint-plugin-import": "^2.24.1",
    "eslint-plugin-jest-dom": "^3.9.0",
    "eslint-plugin-prettier": "^3.4.0",
    "eslint-plugin-testing-library": "^4.11.0",
    "jest": "^27.5.1",
    "prettier": "^2.5.1"
  },
  "scripts": {
    "lint": "pnpm run lint:eslint && pnpm run lint:tsc",
    "lint:eslint": "eslint . --cache",
    "lint:tsc": "tsc --noEmit",
    "test": "TZ='Etc/UTC' jest",
    "build": "tsc --project tsconfig.build.json --emitDeclarationOnly && tsc-alias --project tsconfig.build.json -s && babel . --out-dir dist --extensions .ts,.tsx --ignore 'node_modules,dist,**/*.test.ts'",
    "install": "pnpm run build"
  }
}
laustdeleuran commented 1 year ago

@benmccann

I managed to make a minimal-ish repo that reproduces the error: https://github.com/laustdeleuran/marked-2265-module-import-export-issue

UziTech commented 1 year ago

This seems like a bug in webpack. This is how webpack compiles marked in your minimal repo (Thanks for that by the way :100:). Than tries to call String.marked.use which throws the error.

/***/ "../node_modules/.pnpm/marked@4.2.12/node_modules/marked/lib/marked.cjs":
/*!******************************************************************************!*\
  !*** ../node_modules/.pnpm/marked@4.2.12/node_modules/marked/lib/marked.cjs ***!
  \******************************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

"use strict";
module.exports = __webpack_require__.p + "static/media/marked.79f9f27bbd94805ba150.cjs";

/***/ }),
UziTech commented 1 year ago

Or there is some webpack configuration that needs to be changed. I am not a webpack expert but it might be helpful to create an issue in their repo to see if someone has seen this before and has an easy fix.

laustdeleuran commented 1 year ago

Okay. Thanks for looking into it. I've opened an issue in Webpack's issue tracker here, so we'll see what they say.

laustdeleuran commented 1 year ago

Webpack has a lot of open issues, though, so wondering if they'll have he resources to look into it. I looked in the issue tracker for create-react-app as well, and didn't see anything that looked related, outside of maybe https://github.com/facebook/create-react-app/issues/12100.

Which, in concert with @UziTech's comment about configurations, made me wonder if it's something in create-react-app's configuration that is interacting badly with how marked is compiled when used in a subpackage. Ack, there's so many interlocking tools here that's it's difficult to detangle.

laustdeleuran commented 1 year ago

I looked into the repo @LukeNotable mentioned above, and it looks remarkably similar to mine. Seems like it at least rules out pnpm as the culprit.