Skip to content

Commit

Permalink
refactor: Output ESM files w/ .mjs when appropriate (#950)
Browse files Browse the repository at this point in the history
* fix: Output ESM w/ .mjs ext when pkg type is cjs

* docs: Adding changeset

* Update README.md

* Update README.md

Co-authored-by: Jason Miller <developit@users.noreply.github.com>

* chore: Add warning for new ESM output extension behavior

* Update src/index.js

Co-authored-by: Jason Miller <developit@users.noreply.github.com>

Co-authored-by: Jason Miller <developit@users.noreply.github.com>
  • Loading branch information
rschristian and developit committed Apr 25, 2022
1 parent 242754f commit 6f6e080
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 297 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-ducks-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'microbundle': minor
---

Microbundle will now output ESM using `.mjs` as the file extension when the package type is CJS
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ export default function (e, t, r) {
```jsonc
{
"main": "./dist/foo.umd.js", // legacy UMD output (for Node & CDN use)
"module": "./dist/foo.module.js", // legacy ES Modules output (for bundlers)
"exports": "./dist/foo.modern.js", // modern ES2017 output
"module": "./dist/foo.module.mjs", // legacy ES Modules output (for bundlers)
"exports": "./dist/foo.modern.mjs", // modern ES2017 output
"scripts": {
"build": "microbundle src/foo.js"
}
Expand All @@ -134,9 +134,9 @@ The `"exports"` field can also be an object for packages with multiple entry mod
{
"name": "foo",
"exports": {
".": "./dist/foo.modern.js", // import "foo" (the default)
"./lite": "./dist/lite.modern.js", // import "foo/lite"
"./full": "./dist/full.modern.js" // import "foo/full"
".": "./dist/foo.modern.mjs", // import "foo" (the default)
"./lite": "./dist/lite.modern.mjs", // import "foo/lite"
"./full": "./dist/full.modern.mjs" // import "foo/full"
},
"scripts": {
"build": "microbundle src/*.js" // build foo.js, lite.js and full.js
Expand All @@ -163,15 +163,15 @@ The filenames and paths for generated bundles in each format are defined by the

```jsonc
{
"source": "src/index.js", // input
"main": "dist/foo.js", // CommonJS output bundle
"umd:main": "dist/foo.umd.js", // UMD output bundle
"module": "dist/foo.m.js", // ES Modules output bundle
"source": "src/index.js", // input
"main": "dist/foo.js", // CommonJS output bundle
"umd:main": "dist/foo.umd.js", // UMD output bundle
"module": "dist/foo.mjs", // ES Modules output bundle
"exports": {
"require": "./dist/foo.js", // CommonJS output bundle
"default": "./dist/foo.modern.js", // Modern ES Modules output bundle
"require": "./dist/foo.js", // CommonJS output bundle
"default": "./dist/foo.modern.mjs", // Modern ES Modules output bundle
},
"types": "dist/foo.d.ts" // TypeScript typings directory
"types": "dist/foo.d.ts" // TypeScript typings directory
}
```

Expand Down
25 changes: 20 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs';
import { resolve, relative, dirname, basename, extname } from 'path';
import camelCase from 'camelcase';
import escapeStringRegexp from 'escape-string-regexp';
import { blue, red } from 'kleur';
import { blue, yellow, red } from 'kleur';
import { map, series } from 'asyncro';
import glob from 'tiny-glob/sync';
import autoprefixer from 'autoprefixer';
Expand Down Expand Up @@ -282,6 +282,7 @@ function walk(exports, includeDefault) {
function getMain({ options, entry, format }) {
const { pkg } = options;
const pkgMain = options['pkg-main'];
const pkgTypeModule = pkg.type === 'module';

if (!pkgMain) {
return options.output;
Expand All @@ -301,18 +302,23 @@ function getMain({ options, entry, format }) {
mainsByFormat.es = replaceName(
pkg.module && !pkg.module.match(/src\//)
? pkg.module
: pkg['jsnext:main'] || 'x.esm.js',
: pkg['jsnext:main'] || pkgTypeModule
? 'x.esm.js'
: 'x.esm.mjs',
mainNoExtension,
);

mainsByFormat.modern = replaceName(
(pkg.exports && walk(pkg.exports, pkg.type === 'module')) ||
(pkg.exports && walk(pkg.exports, pkgTypeModule)) ||
(pkg.syntax && pkg.syntax.esmodules) ||
pkg.esmodule ||
'x.modern.js',
pkgTypeModule
? 'x.modern.js'
: 'x.modern.mjs',
mainNoExtension,
);
mainsByFormat.cjs = replaceName(
pkg['cjs:main'] || (pkg.type && pkg.type === 'module' ? 'x.cjs' : 'x.js'),
pkg['cjs:main'] || (pkgTypeModule ? 'x.cjs' : 'x.js'),
mainNoExtension,
);
mainsByFormat.umd = replaceName(
Expand Down Expand Up @@ -440,6 +446,15 @@ function createConfig(options, entry, format, writeMeta) {
const outputDir = dirname(absMain);
const outputEntryFileName = basename(absMain);

// Warn about the (somewhat) breaking change in #950
if (format === 'es' && !pkg.module && outputEntryFileName.endsWith('.mjs')) {
stdout(
yellow(
'Warning: your package.json does not specify {"type":"module"}. Microbundle assumes this is a CommonJS package and is generating ES Modules with the ".mjs" file extension.',
),
);
}

let config = {
/** @type {import('rollup').InputOptions} */
inputOptions: {
Expand Down
Loading

0 comments on commit 6f6e080

Please sign in to comment.