# esmjs / esmc - Draft

> **E**SMC is **S**mart **M**odules **C**ompiler. The Power of Intelligence.
> **E**SM are **S**weet **M**odules. The Power of Intelligence.
> **E**SMJS, **S**weet **M**odules **J**ava**S**cript. The Power of Intelligence.

- Full power of ES Modules - using `esm` loader, creating ESM <-> CJS bridge
- Full power of Babel - TypeScript, React, Nodejs 8/10, Browsers, Preset Env, Stage 3
  + transpiles to Node 8/10 in `dist/nodejs` with `.mjs` files
  + transpiles to Browserlist's `>=1%, not ie` query in `dist/browsers` with `.js` files
  + generates `dist/typings` files, ready for the `types` field in `package.json`
  + both outpus for nodejs and browsers are using ES Modules, intentionally
    - 1) because Webpack/Rollup need es modules
    - 2) because we generates the `dist/nodejs/index.js` which is `esm` bridge
  + the browsers output only needs to be bundled, no transpilation needed
- Full power of ESLint - AirBnB, Prettier, React, Nodejs, TypeScript
- Full power of TypeScript - tslint, type checking and type distribution
- Full power of bundling - Rollup/Webpack (rollup by default)
- Intelligent workflow and target detection
  + easy start with `esm init`
  + you are ready to `esm watch`, `esm build` and `esm bundle`
- If you don't want type things, just write JS/JSX in `.mjs` source files
- If you want static typing and etc, write `.ts` and `.tsx` source files

## How it works

### Scenario 1: You want TypeScript

If you love and want static typing, just write `.ts` or `.tsx` files. Here should be noted
that TypeScript forces us to use different extension if we want to write some JSX (the `.tsx` extension).

We don't use the TypeScript compiler `tsc` binary. We transform
the source files in `src/` directory with Babel 7 using the `@babel/preset-typescript`.
This gives us the full power of Babel such as Preset Env, Stage 3 and React. And the
Stage 3 preset isn't scary - we just use it because the Class Properties proposal
(in the case when we not transpiling typescript), Dynamic Import and import.meta syntax plugins.
The `@babel/preset-env` is used just because we want to have ability to transpile for
specific browsers/nodejs versions. Here for browsers we use the `>=1%, not ie` query of
Browserlist.

**So, what's the execution order?**
1. Run `tsc` without emitting type declaration files, just type checking.
2. Run `eslint --fix` over the source files, which does the fixing and formatting with Prettier.
3. Run `tsc` only emitting declaration files, which creates `dist/typings` directory.
4. Compile the `.ts`/`.tsx` files into `.js` files to `dist/nodejs` and `dist/browsers` folders.
5. Run `prettier 'dist/**/*' --write` to only prettify the output of Babel. 
6. Rename all `.js` files from `dist/nodejs` folder to have `.mjs` extension.
7. Generate a `dist/nodejs/index.js` file which in turn uses the `esm` package to load the `.mjs` files.

### Scenario 2: You love modern JavaScript.

In case you don't love static typing and TypeScript/FlowType, you can just write awesome
modern JavaScript/JSX into `.mjs` files in your `src/` directory and we will disable the typescript preset.
It will allow you to use everything that Node 8/10 supports plus the Class Properties & Dynamic Import.
The rest is the same - we compiles these files to `dist/nodejs` and `dist/browsers` folders, using the
same Browserlist query for the browsers.

**So, what's the execution order?**
1. Run `eslint --fix` over the source files, which does the fixing and formatting with Prettier.
2. Compile the `.mjs` files into `.mjs` files at `dist/nodejs` (with Babel's `--keep-file-extension`)
3. Compile the `.mjs` files into `.js` files at `dist/browsers`
4. Run `prettier 'dist/**/*' --write` to only prettify the output of Babel. 
5. Generate a `dist/nodejs/index.js` file which in turn uses the `esm` package to load the `.mjs` files.

### Bundling: Rollup / Webpack

And so, the only thing that left to be done is **bundling**, but that's optional only if you need
to have browser bundles. You can use either Rollup or Webpack to bundle the `dist/browsers/index.js` entry.
Notice that you don't need to transpile, but only need to resolve all deps and make single bundle file
which will be used in the browsers (or multiple bundle chunks, using Code Splitting).

### Code Style, Linting: ESLint / AirBnB / Prettier

We use very well fine-tuned ESLint config which integrates AirBnB preset (including their React and JSX configs)
and the Prettier plugin. There are things that are handled by TypeScript/TSLint defaults,
so they are disabled from the ESLint. There are other things that are disabled from AirBnB, 
so they won't conflict with the Prettier or TypeScript. But we intentionally don't use the `eslint-config-prettier`, 
instead we disabled one by one rules that are not okey with the Prettier formatting.

We also use the typescript, import, node, promise ESLint plugins with few eslint-import resolvers, such
as the `eslint-import-resolver-typescript` and `eslint-import-resolver-node`.