mixmark-io / turndown

🛏 An HTML to Markdown converter written in JavaScript
https://mixmark-io.github.io/turndown
MIT License
8.94k stars 881 forks source link

pkg.main, pkg.module are incompatible, so require("turndown") behaves differently under Rollup/Webpack #345

Open andersk opened 4 years ago

andersk commented 4 years ago

In Node, require("turndown") returns TurndownService, but in Rollup or Webpack, require("turndown") returns { default: TurndownService }. This means a Turndown dependent can’t be compatible with both environments without contortions.

$ npm i rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve turndown webpack webpack-cli
$ echo 'console.log(require("turndown"))' > src.js
$ node src.js
[Function: TurndownService]
$ npx rollup src.js -p node-resolve -p commonjs -f cjs -o out.js
$ node out.js
{ default: [Getter] }
$ npx webpack --mode=development --target=node
$ node dist/main.js 
Object [Module] { default: [Getter] }

This is because Node is using pkg.main (lib/turndown.cjs.js), while Rollup and Webpack are using pkg.module (lib/turndown.es.js), and the two files do not provide compatible interfaces.

This problem is called out in the Rollup documentation:

Note: There are some tools such as Babel, TypeScript, Webpack, and @rollup/plugin-commonjs that are capable of resolving a CommonJS require(...) call with an ES module. If you are generating CommonJS output that is meant to be interchangeable with ESM output for those tools, you should always use named export mode. The reason is that most of those tools will by default return the namespace of an ES module on require where the default export is the .default property.

Three potential solutions are:

jackmawer commented 4 years ago

I'm currently facing this issue in an environment that runs both in Node and a webworker. Is there a workaround to this issue?

martincizek commented 3 years ago

First of all, thanks for the steps to reproduce! Though they're not working with the current webpack.

There are also a few changes in packaging since 7.1.1 (and currently even Rollup outputs warning related to this), the current output is:

$ npm i rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve turndown webpack webpack-cli
added 151 packages, and audited 152 packages in 5s
[...]
$ echo 'console.log(require("turndown"))' > src.js
$ node src.js
[Function: TurndownService]
$ npx rollup src.js -p node-resolve -p commonjs -f cjs -o out.js

src.js → out.js...
(!) Entry module "src.js" is implicitly using "default" export mode, which means for CommonJS output that its default export is assigned to "module.exports". For many tools, such CommonJS output will not be interchangeable with the original ES module. If this is intended, explicitly set "output.exports" to either "auto" or "default", otherwise you might want to consider changing the signature of "src.js" to use named exports only.
https://rollupjs.org/guide/en/#outputexports
src.js
created out.js in 157ms
$ node out.js
{ default: [Getter] }
$ npx webpack -d
[webpack-cli] Error: Option '-d, --devtool <value>' argument missing
[webpack-cli] Run 'webpack --help' to see available commands and options

Would you mind looking into the issue again and suggest updated options to solve it if the problem persist?

andersk commented 3 years ago

Your output demonstrates that the problem persists with Rollup. (The warning from rollup src.js is about the exports of src.js, which don’t matter in this example. It can be appeased with either --exports=named or --exports=default with no other effect. The problem is in Turndown’s Rollup configuration, not mine.)

For webpack-cli@4, replace -d with --mode=development --target=node.