diff --git a/esm-dist.sh b/esm-dist.sh new file mode 100755 index 000000000..d55123427 --- /dev/null +++ b/esm-dist.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Place a package.json so Node know that the dist/esm is ESM. +echo '{ "type": "module" }' > dist/esm/package.json + +# Copy the types in there so TS knows it's ESM as well. +cp index.d.ts dist/esm/index.d.ts diff --git a/package.json b/package.json index a23f0dc4d..082647189 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,23 @@ "module": "dist/esm/index.js", "browser": "dist/cjs/index.js", "types": "index.d.ts", + "exports": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./index.d.ts", + "default": "./dist/cjs/index.js" + } + }, "scripts": { "build": "rollup -c", "build:flow": "flow-copy-source -v --ignore=*.spec.js src/ dist/cjs", "prebuild": "rm -rf dist/", "postbuild": "npm run build:flow", + "postbuild:flow": "npm run build:esm", + "build:esm": "./esm-dist.sh", "prepare": "npm run build", "lint": "eslint .", "lint:fix": "npm run lint -- --fix", diff --git a/src/dist.spec.js b/src/dist.spec.js new file mode 100644 index 000000000..a7c77a4da --- /dev/null +++ b/src/dist.spec.js @@ -0,0 +1,45 @@ +const { resolve } = require('path'); +const { writeFileSync, unlinkSync } = require('fs'); +const { spawnSync } = require('child_process'); +const { tmpdir } = require('os'); + +// escape from Jest's environment, and from this folder. +// This ensures that we are loading the distribution files +// from a completely separate location, as one will when using +// this module as a dependency either via import() or require(). +const cjsMod = resolve(__dirname, '../dist/cjs/index.js'); +const esmMod = resolve(__dirname, '../dist/esm/index.js'); +const testCode = ` +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +const cjsDist = require(${JSON.stringify(cjsMod)}); +const esmDist = await import(${JSON.stringify(esmMod)}); +import assert from 'assert'; + +for (const [name, value] of Object.entries(cjsDist)) { + assert.equal(typeof esmDist[name], typeof value, 'esm has ' + name); +} +for (const [name, value] of Object.entries(esmDist)) { + assert.equal(typeof cjsDist[name], typeof value, 'cjs has ' + name); +} +assert.equal(typeof cjsDist.default, 'function', 'cjs default function'); +assert.equal(typeof esmDist.default, 'function', 'cjs default function'); + +console.log('ok'); +`; +const testFile = resolve(tmpdir(), 'reactElementToJSXString.test.mjs'); + +describe('cjs and esm distributions', () => { + it('writes the test file', () => writeFileSync(testFile, testCode)); + + it('exports matching cjs and esm', () => { + const result = spawnSync(process.execPath, [testFile], { + encoding: 'utf8', + }); + expect(result.error).toBe(undefined); + expect(result.stderr).toEqual(''); + expect(result.stdout).toEqual('ok\n'); + }); + + it('cleans up', () => unlinkSync(testFile)); +});