developit / microbundle

📦 Zero-configuration bundler for tiny modules.
https://npm.im/microbundle
MIT License
8.04k stars 362 forks source link

`[name].cjs` file will be output regardless of config #917

Closed pomle closed 2 years ago

pomle commented 2 years ago

Version: 0.14.2

Config

{
  "name": "my-lib",
  "version": "0.2.1",
  "description": "API client for JavaScript and TypeScript",
  "license": "UNLICENSED",
  "type": "module",
  "source": "src/index.ts",
  "main": "dist/foo.js",
  "module": "dist/foo.modern.js",
  "scripts": {
    "build": "microbundle",
    "dev": "microbundle watch",
    "test": "jest"
  },
  "publishConfig": {
    "source": "src/index.ts",
    "main": "dist/foo.js",
  },
  "files": [
    "dist"
  ],
  "devDependencies": {
    "@types/jest": "^26.0.15",
    "@types/node": "^12.0.0",
    "jest": "^27.4.5",
    "microbundle": "^0.14.2",
    "prettier": "^2.5.1",
    "ts-jest": "^27.1.1",
    "ts-node": "^10.4.0",
    "typescript": "^4.5.4"
  }
}

Output: image

This seems to prevent packages compatible with both Jest and CRA for example.

developit commented 2 years ago

The CommonJS output file is generated with .cjs when you have "type":"module" in your package.json, because it needs to use that extension to force Node to recognize files as CommonJS.

You can avoid this by removing "type":"module" from your package.json:

{
  "source": "src/index.ts",
  "main": "dist/foo.js",
  "module": "dist/foo.modern.mjs",
  "exports": {
    "module": "./dist/foo.modern.js",
    "import": "./dist/foo.modern.js",
    "default": "./dist/foo.js"
  }
}
pomle commented 2 years ago

Hey, thank you very much.

I know this is probably not a microbundle thing anymore. But when I remove type: "module", Jest stops working for the package itself, and when type is set, microbundle forces a .cjs file which jest will not recognize as a valid import in a package. The only state I have managed to get this to work is if I set type: "module" in my package that I build with microbundle, then rename the created index.cjs file to index.js.

I'm just... what's going on. :D

How did I get myself into this mess.

image

rschristian commented 2 years ago

But when I remove type: "module", Jest stops working for the package itself

If you weren't aware, setting "type": "module" signals to Node (and any other tool that follows the spec) that .js is to be treated as ESM, and .cjs is what will be used when referring to CJS. Removing "type" or setting it to "commonjs" says that .js is to be treated as CJS, and .mjs is what will be used when referring to ESM.

By "Jest stops working", what I imagine is happening is that you're not transpiling with Jest and it (correctly) trips over the fact that you're writing ESM in a module that is treated as CJS. Without an error/repo, I'm just guessing though.

microbundle forces a .cjs file which jest will not recognize as a valid import in a package.

How are you importing it? With require() or import?

I can take a look if you can provide a repo. Jest's support of Node-native ESM is still experimental AFAIK, so you may want to transpile to or author in CJS still.

pomle commented 2 years ago

Hello @rschristian, and thank you for you comments.

I am using import only in this project.

What I meant by "jest stops working" was that it stopped being able to parse its own config file jest.config.js when I removed "type": "module". This seems to be because it used export default, which I guess is module syntax.

/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
export default {
  preset: "ts-jest",
  testPathIgnorePatterns: ["dist/"],
  testEnvironment: "node",
};

I updated the jest.config.js to use module.exports and after that it seems to work as I expect to. Below is the full diff that got me to a spot where I can continue working.

diff --git a/packages/api-client/jest.config.js b/packages/api-client/jest.config.js
index a4e34ee..10540cb 100644
--- a/packages/api-client/jest.config.js
+++ b/packages/api-client/jest.config.js
@@ -1,5 +1,5 @@
 /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
-export default {
+module.exports = {
   preset: "ts-jest",
   testPathIgnorePatterns: ["dist/"],
   testEnvironment: "node",
diff --git a/packages/api-client/package.json b/packages/api-client/package.json
index 62635d1..f042fc6 100644
--- a/packages/api-client/package.json
+++ b/packages/api-client/package.json
@@ -4,7 +4,6 @@
   "description": "API client for JavaScript and TypeScript",
   "author": "Pontus Persson <pontus@cur8.co>",
   "license": "UNLICENSED",
-  "type": "module",
   "source": "src/index.ts",
   "module": "./dist/index.modern.js",
   "main": "./dist/index.js",
@@ -13,10 +12,6 @@
     "dev": "microbundle watch",
     "test": "jest"
   },
-  "exports": {
-    "require": "./dist/index.cjs",
-    "default": "./dist/index.modern.js"
-  },
   "publishConfig": {

Thanks for you help!

rschristian commented 2 years ago

Gotcha! Yep, when switching back to CJS from ESM you'd have to use module.exports or change Jest's config file to .mjs (if it supports that, not sure off the top of my head).