-
-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: import native mjs files; - all test files must be mjs - allows -r esm hook still, if wanted - does not work in < Node 12 Node 8-10 throw with `import()` immediately With `esm`, "native `require` cannot sideload `mjs` files" * chore: add "esm.native" example * v0.4.0-next.0 * fix(run): add `file:///` protocol for windows; - see nodejs/node#31710 - alt?: https://nodejs.org/api/url.html#url_url_pathtofileurl_path - thank you @TehShrike * v0.4.0-next.1 * fix(diff): workaround for `diff` importer; - blocked by kpdecker/jsdiff#292 - will (finally) craft own diff library if unwilling to resolve * v0.4.0-next.2 * v0.4.0-next.3 * v0.4.0-next.4 * fix(bin): add `import()` builder; - avoids Node 8.x and 10.x syntax error * fix(bin): remove unused import * chore: bump `diff` version * fix(parse): export type interfaces * break(parse): default -> named export * break(run): default -> named export * v0.5.0-next.0 * fix(uvu): don't immediately exit process; When invoking `node` directly on a test file, allow native `stderr` output error(s) to write to console, allowing Node to explain why _it_ aborted. Important for ESM adopters/transitions. * v0.5.0-next.1 * chore: add "esm" examples * chore: add `esm` docs * chore: add `readme` to "esm" examples
- Loading branch information
Showing
27 changed files
with
430 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# ES Modules | ||
|
||
EcmaScript Modules have landed in Node.js (> 12.x)! Check out the official language documentation<sup>[[1](https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules)][[2](https://nodejs.org/api/packages.html)]</sup> to learn more. | ||
|
||
...but, here's the **TL;DR:** | ||
|
||
* by default, only files with `.mjs` extension are treated as ESM | ||
* by default, `.js` – and now `.cjs` – files are treated as CommonJS | ||
* by defining `"type": "module"` in your `package.json` file, all `.js` files are treated as ESM | ||
* when using ESM, any `import`s must reference the _full_ filepath, including its extension | ||
* the `.cjs` extension is _always_ CommonJS, even if `"type": "module"` is defined | ||
|
||
## Examples | ||
|
||
Knowing the above, there are a few ways we can use/integrate ESM into our `uvu` test suites! | ||
|
||
> **Important:** Only uvu v0.5.0+ has native ESM support | ||
### Native ESM – via `.mjs` files | ||
|
||
> Visit the working [`/examples/esm.mjs`](/examples/esm.mjs) demonstration~! | ||
This example only works in Node.js v12.0 and later. In other words, it requires that _both_ your test files _and_ your source files possess the `.mjs` extension. This is – by default – the only way Node.js will load ES Modules and allow them to import/reference one another. | ||
|
||
***PRO*** | ||
|
||
* Modern | ||
* Native / less tooling | ||
|
||
***CON*** | ||
|
||
* Requires Node.js 12.0 and later | ||
* Exposes you to CommonJS <-> ESM interop issues | ||
* Cannot test older Node.js versions – unless maintain a duplicate set of source _and_ test files | ||
|
||
|
||
### Polyfill – via `esm` package | ||
|
||
> Visit the working [`/examples/esm.loader`](/examples/esm.loader) demonstration~! | ||
Thanks to [`esm`](http://npmjs.com/package/esm), this example works in **all** Node.js versions. However, for best/consistent results, you **should avoid** using `.mjs` files when using this approach. This is because `esm` has some [limitations](https://www.npmjs.com/package/esm#extensions) and chooses not to interact/tamper with files that, by definition, should only be running with the native loader anyway. | ||
|
||
In other words, it requires that _both_ your test files _and_ your source files possess the `.mjs` extension. This is – by default – the only way Node.js will load ES Modules and allow them to import/reference one another. | ||
|
||
***PRO*** | ||
|
||
* Makes ESM accessible to older Node.js versions | ||
* Solves (most) CommonJS <-> ESM interop issues | ||
* Only requires a simple `--require/-r` hook | ||
* Quick to attach and quick to execute | ||
|
||
***CON*** | ||
|
||
* Not native | ||
* Not compatible with `.mjs` files | ||
|
||
|
||
### Native ESM – via `"type": "module"` | ||
|
||
> Visit the working [`/examples/esm.dual`](/examples/esm.dual) demonstration~! | ||
This example combines the best of both worlds! It makes use of native ESM in Node.js versions that support it, while still making it possible to run your tests in older/legacy Node.js versions. | ||
|
||
With `"type": "module"`, we are able to use ESM within `.js` files. | ||
Node 12.x and later to process those files as ESM, through native behavior. | ||
And then older Node.js versions can run/process the _same_ files by simply including the [`esm`](http://npmjs.com/package/esm) loader. | ||
|
||
At worst – all we have is a "duplicate" test script... which is much, much better than duplicating sets of files. We end up with something like this: | ||
|
||
```js | ||
{ | ||
"type": "module", | ||
// ... | ||
"scripts": { | ||
"test:legacy": "uvu -r esm tests", | ||
"test:native": "uvu tests" | ||
} | ||
} | ||
``` | ||
|
||
Your CI environment would execute the appropriate script according to its Node version :tada: | ||
|
||
***PRO*** | ||
|
||
* Native when possible | ||
* No additional maintenance | ||
* Run tests in wider Node.js matrix | ||
* Easy to drop legacy support at anytime | ||
|
||
***CON*** | ||
|
||
* Defining `"type": "module"` may change how your package is consumed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"private": true, | ||
"type": "module", | ||
"scripts": { | ||
"test:legacy": "uvu -r esm tests", | ||
"test:native": "uvu tests" | ||
}, | ||
"devDependencies": { | ||
"esm": "3.2.25", | ||
"uvu": "^0.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Example: esm.dual | ||
|
||
Please read [/docs/esm](/docs/esm.md) for full details & comparisons. | ||
|
||
## Why | ||
|
||
Unlike [/examples/esm.loader](/examples/esm.loader), this example uses the native ESM loader whenever it's available. | ||
|
||
Unlike [/examples/esm.mjs](/examples/esm.mjs), this example will run in all versions of Node.js – including older versions where ESM is not natively supported. | ||
|
||
|
||
## Highlights | ||
|
||
* Define `"type": "module"` within `package.json` <br>Allows Node.js to treat `.js` files as ESM. | ||
|
||
* Define `import` statements with full file paths <br>Required by Node.js whenever ESM in use. | ||
|
||
* Define two `test` scripts: | ||
* `"test:native"` – for use within Node 12+ | ||
* `"test:legacy"` – for use with Node < 12 | ||
|
||
## License | ||
|
||
MIT © [Luke Edwards](https://lukeed.com) |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { suite } from 'uvu'; | ||
import * as assert from 'uvu/assert'; | ||
import * as math from '../src/math.js'; | ||
|
||
const sum = suite('sum'); | ||
|
||
sum('should be a function', () => { | ||
assert.type(math.sum, 'function'); | ||
}); | ||
|
||
sum('should compute values', () => { | ||
assert.is(math.sum(1, 2), 3); | ||
assert.is(math.sum(-1, -2), -3); | ||
assert.is(math.sum(-1, 1), 0); | ||
}); | ||
|
||
sum.run(); | ||
|
||
// --- | ||
|
||
const div = suite('div'); | ||
|
||
div('should be a function', () => { | ||
assert.type(math.div, 'function'); | ||
}); | ||
|
||
div('should compute values', () => { | ||
assert.is(math.div(1, 2), 0.5); | ||
assert.is(math.div(-1, -2), 0.5); | ||
assert.is(math.div(-1, 1), -1); | ||
}); | ||
|
||
div.run(); | ||
|
||
// --- | ||
|
||
const mod = suite('mod'); | ||
|
||
mod('should be a function', () => { | ||
assert.type(math.mod, 'function'); | ||
}); | ||
|
||
mod('should compute values', () => { | ||
assert.is(math.mod(1, 2), 1); | ||
assert.is(math.mod(-3, -2), -1); | ||
assert.is(math.mod(7, 4), 3); | ||
}); | ||
|
||
mod.run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { suite } from 'uvu'; | ||
import * as assert from 'uvu/assert'; | ||
import * as utils from '../src/utils.js'; | ||
|
||
const capitalize = suite('capitalize'); | ||
|
||
capitalize('should be a function', () => { | ||
assert.type(utils.capitalize, 'function'); | ||
}); | ||
|
||
capitalize('should capitalize a word', () => { | ||
assert.is(utils.capitalize('hello'), 'Hello'); | ||
}); | ||
|
||
capitalize('should only capitalize the 1st word', () => { | ||
assert.is(utils.capitalize('foo bar'), 'Foo bar'); | ||
}); | ||
|
||
capitalize.run(); | ||
|
||
// --- | ||
|
||
const dashify = suite('dashify'); | ||
|
||
dashify('should be a function', () => { | ||
assert.type(utils.dashify, 'function'); | ||
}); | ||
|
||
dashify('should replace camelCase with dash-case', () => { | ||
assert.is(utils.dashify('fooBar'), 'foo-bar'); | ||
assert.is(utils.dashify('FooBar'), 'foo-bar'); | ||
}); | ||
|
||
dashify('should enforce lowercase', () => { | ||
assert.is(utils.dashify('foobar'), 'foobar'); | ||
}); | ||
|
||
dashify.run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,6 @@ | |
}, | ||
"devDependencies": { | ||
"esm": "3.2.25", | ||
"uvu": "^0.0.18" | ||
"uvu": "^0.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Example: esm.loader | ||
|
||
Please read [/docs/esm](/docs/esm.md) for full details & comparisons. | ||
|
||
## Why | ||
|
||
This example makes use of the [`esm`](https://npmjs.com/package/esm) module, which rewrites all ESM syntax to CommonJS on the fly. | ||
|
||
|
||
## Highlights | ||
|
||
* Use ESM within regular `.js` files | ||
|
||
* Works in all versions of Node.js <br>Because the `esm` loader is invoked – never the native behavior. | ||
|
||
* Solves CommonJS <-> ESM interop issues <br>A significant portion of the npm ecosystem is still CommonJS-only. | ||
|
||
|
||
## License | ||
|
||
MIT © [Luke Edwards](https://lukeed.com) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const sum = (a, b) => a + b; | ||
export const div = (a, b) => a / b; | ||
export const mod = (a, b) => a % b; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export function capitalize(str) { | ||
return str[0].toUpperCase() + str.substring(1); | ||
} | ||
|
||
export function dashify(str) { | ||
return str.replace(/([a-zA-Z])(?=[A-Z\d])/g, '$1-').toLowerCase(); | ||
} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"private": true, | ||
"scripts": { | ||
"test": "uvu tests" | ||
}, | ||
"devDependencies": { | ||
"uvu": "^0.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Example: esm.mjs | ||
|
||
Please read [/docs/esm](/docs/esm.md) for full details & comparisons. | ||
|
||
## Why | ||
|
||
This example makes use of the native ESM loader – available in version Node 12 and later! | ||
|
||
|
||
## Highlights | ||
|
||
* Uses native ESM via the `.mjs` file extension <br>This is the Node's default behavior. | ||
|
||
* Define `import` statements with full file paths <br>Required by Node.js whenever ESM in use. | ||
|
||
|
||
## License | ||
|
||
MIT © [Luke Edwards](https://lukeed.com) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const sum = (a, b) => a + b; | ||
export const div = (a, b) => a / b; | ||
export const mod = (a, b) => a % b; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export function capitalize(str) { | ||
return str[0].toUpperCase() + str.substring(1); | ||
} | ||
|
||
export function dashify(str) { | ||
return str.replace(/([a-zA-Z])(?=[A-Z\d])/g, '$1-').toLowerCase(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { suite } from 'uvu'; | ||
import * as assert from 'uvu/assert'; | ||
import * as math from '../src/math.mjs'; | ||
|
||
const sum = suite('sum'); | ||
|
||
sum('should be a function', () => { | ||
assert.type(math.sum, 'function'); | ||
}); | ||
|
||
sum('should compute values', () => { | ||
assert.is(math.sum(1, 2), 3); | ||
assert.is(math.sum(-1, -2), -3); | ||
assert.is(math.sum(-1, 1), 0); | ||
}); | ||
|
||
sum.run(); | ||
|
||
// --- | ||
|
||
const div = suite('div'); | ||
|
||
div('should be a function', () => { | ||
assert.type(math.div, 'function'); | ||
}); | ||
|
||
div('should compute values', () => { | ||
assert.is(math.div(1, 2), 0.5); | ||
assert.is(math.div(-1, -2), 0.5); | ||
assert.is(math.div(-1, 1), -1); | ||
}); | ||
|
||
div.run(); | ||
|
||
// --- | ||
|
||
const mod = suite('mod'); | ||
|
||
mod('should be a function', () => { | ||
assert.type(math.mod, 'function'); | ||
}); | ||
|
||
mod('should compute values', () => { | ||
assert.is(math.mod(1, 2), 1); | ||
assert.is(math.mod(-3, -2), -1); | ||
assert.is(math.mod(7, 4), 3); | ||
}); | ||
|
||
mod.run(); |
Oops, something went wrong.