├── .gitignore ├── README.md ├── cjs ├── cjs.cjs ├── index.js ├── mjs.mjs └── package.json ├── export-star ├── index.js ├── one.js ├── package.json └── two.js ├── exports ├── index.js ├── package.json └── sub.js ├── index.js ├── package.json └── ts ├── index.js ├── index.ts ├── package-lock.json ├── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Errors 2 | 3 | ### `ERR_UNSUPPORTED_DIR_IMPORT` 4 | 5 | Directory imports aren't supported with native ESM 6 | 7 | I tried and failed to use the `package.json` `exports` feature to side-step 8 | this. This is due to the fact that: 9 | 10 | > "exports" is only read when using bare import specifiers (i.e. not relative 11 | > paths, absolute paths or URLs). 12 | > 13 | > In other words, only when importing deps from node_modules. – 14 | > [Nicolò Ribaudo](https://twitter.com/NicoloRibaudo/status/1370298430791282689) 15 | 16 | ### `ERR_MODULE_NOT_FOUND` 17 | 18 | You have to include the module's extension when importing. 19 | 20 | > You can sidestep these with `--es-module-specifier-resolution=node` – 21 | > [Caleb Boyd](https://github.com/kentcdodds/native-esm-experiments/commit/b3412c9f0a7ac068a7c6ea46619b324410ccbf5c#r48177953) 22 | 23 | ### `ERR_REQUIRE_ESM` 24 | 25 | You cannot use `require` to get a module. You have to use `import`, but you 26 | can't use an `import` statement or you'll get: 27 | 28 | > SyntaxError: Cannot use import statement outside a module 29 | 30 | You have to use a dynamic import: 31 | 32 | ```diff 33 | - const m = require('./thing.mjs') 34 | + import('./thing.mjs').then(m => {}) 35 | ``` 36 | 37 | Yes, that means now you have to make everything async. Yes, Node now _does_ have 38 | top-level `await`, however that only works in native ESM files, which means 39 | that's not going to help us with this particular issue. If you try using top 40 | level await in a CommonJS module, you'll get: 41 | 42 | > SyntaxError: await is only valid in async function 43 | 44 | ### `ERR_UNKNOWN_FILE_EXTENSION` 45 | 46 | ``` 47 | TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/kentcdodds/Desktop/native-esm-experiments/ts/index.ts 48 | ``` 49 | 50 | This happened when I set `"type": "module"` and ran `ts-node index.ts`. 51 | 52 | Solve this by using the experimental loader feature in node and the esm loader: 53 | 54 | ``` 55 | node --loader ts-node/esm index.ts 56 | ``` 57 | -------------------------------------------------------------------------------- /cjs/cjs.cjs: -------------------------------------------------------------------------------- 1 | async function main() { 2 | const mjs = await import('./mjs.mjs') 3 | console.log(mjs.fn(1, 2)) 4 | } 5 | main() 6 | -------------------------------------------------------------------------------- /cjs/index.js: -------------------------------------------------------------------------------- 1 | console.log('cjs/index.js') 2 | 3 | module.exports = { 4 | /** 5 | * Adds the two numbers 6 | * 7 | * @param {number} a the first number 8 | * @param {number} b the second number 9 | * @returns {number} 10 | */ 11 | fn(a, b) { 12 | return a + b 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /cjs/mjs.mjs: -------------------------------------------------------------------------------- 1 | console.log('cjs/mjs.mjs') 2 | 3 | /** 4 | * Adds the two numbers 5 | * 6 | * @param {number} a the first number 7 | * @param {number} b the second number 8 | * @returns {number} 9 | */ 10 | const fn = (a, b) => a + b 11 | export {fn} 12 | -------------------------------------------------------------------------------- /cjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cjs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type": "commonjs", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Kent C. Dodds (https://kentcdodds.com/)", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /export-star/index.js: -------------------------------------------------------------------------------- 1 | export * from './one.js' 2 | export * from './two.js' 3 | export const one = 3 4 | -------------------------------------------------------------------------------- /export-star/one.js: -------------------------------------------------------------------------------- 1 | export const one = 1 2 | -------------------------------------------------------------------------------- /export-star/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "export-star", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type": "module", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Kent C. Dodds (https://kentcdodds.com/)", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /export-star/two.js: -------------------------------------------------------------------------------- 1 | export const two = 2 2 | -------------------------------------------------------------------------------- /exports/index.js: -------------------------------------------------------------------------------- 1 | console.log('exports/index.js') 2 | 3 | /** 4 | * Adds the two numbers 5 | * 6 | * @param {number} a the first number 7 | * @param {number} b the second number 8 | * @returns {number} 9 | */ 10 | const fn = (a, b) => a + b 11 | export {fn} 12 | -------------------------------------------------------------------------------- /exports/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exports", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "", 6 | "exports": { 7 | ".": "./index.js", 8 | "./subtract": "./sub.js" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "keywords": [], 14 | "author": "Kent C. Dodds (https://kentcdodds.com/)", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /exports/sub.js: -------------------------------------------------------------------------------- 1 | console.log('exports/sub.js') 2 | 3 | /** 4 | * Subtracts the two numbers 5 | * 6 | * @param {number} a the first number 7 | * @param {number} b the second number 8 | * @returns {number} 9 | */ 10 | const fn = (a, b) => a - b 11 | export {fn} 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import {fn as cjsFn} from './cjs/index.js' 2 | import {fn as exportsFn} from './exports/subtract' 3 | import * as exportStar from './export-star/index.js' 4 | 5 | console.log('index.js') 6 | console.log(cjsFn(1, 2)) 7 | console.log(exportsFn(2, 1)) 8 | console.log(exportStar) 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-esm-experiments", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Kent C. Dodds (https://kentcdodds.com/)", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /ts/index.js: -------------------------------------------------------------------------------- 1 | import { fn } from '../cjs/index.js'; 2 | console.log('ts/index.ts'); 3 | console.log(fn(2, 3)); 4 | -------------------------------------------------------------------------------- /ts/index.ts: -------------------------------------------------------------------------------- 1 | import {fn} from '../cjs/index.js' 2 | console.log('ts/index.ts') 3 | console.log(fn(2, 3)) 4 | -------------------------------------------------------------------------------- /ts/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "arg": { 8 | "version": "4.1.3", 9 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 10 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" 11 | }, 12 | "buffer-from": { 13 | "version": "1.1.1", 14 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 15 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 16 | }, 17 | "create-require": { 18 | "version": "1.1.1", 19 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 20 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" 21 | }, 22 | "diff": { 23 | "version": "4.0.2", 24 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 25 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" 26 | }, 27 | "make-error": { 28 | "version": "1.3.6", 29 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 30 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" 31 | }, 32 | "source-map": { 33 | "version": "0.6.1", 34 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 35 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 36 | }, 37 | "source-map-support": { 38 | "version": "0.5.19", 39 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 40 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 41 | "requires": { 42 | "buffer-from": "^1.0.0", 43 | "source-map": "^0.6.0" 44 | } 45 | }, 46 | "ts-node": { 47 | "version": "9.1.1", 48 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", 49 | "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", 50 | "requires": { 51 | "arg": "^4.1.0", 52 | "create-require": "^1.1.0", 53 | "diff": "^4.0.1", 54 | "make-error": "^1.1.1", 55 | "source-map-support": "^0.5.17", 56 | "yn": "3.1.1" 57 | } 58 | }, 59 | "typescript": { 60 | "version": "4.2.3", 61 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", 62 | "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" 63 | }, 64 | "yn": { 65 | "version": "3.1.1", 66 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 67 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "node --loader ts-node/esm ./index.ts" 10 | }, 11 | "keywords": [], 12 | "author": "Kent C. Dodds (https://kentcdodds.com/)", 13 | "license": "MIT", 14 | "dependencies": { 15 | "ts-node": "^9.1.1", 16 | "typescript": "^4.2.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["*.ts"], 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "moduleResolution": "Node" 6 | } 7 | } 8 | --------------------------------------------------------------------------------