jaredpalmer / tsdx

Zero-config CLI for TypeScript package development
https://tsdx.io
MIT License
11.22k stars 507 forks source link

Allow built ESM to be native ES2015+ (not ES5) #963

Open justin-schroeder opened 3 years ago

justin-schroeder commented 3 years ago

Current Behavior

When creating a new library that needs no legacy support (ES6+ is just 👌) — I seem unable to produce esm outputs that are not transpiled to ES5. Reproduction:

  1. Create a new project and add
    npx tsdx create my-es6-module
  2. Add target: 'ES2015 to compileOptions in tsconfig.js:
    {
    // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
    "include": ["src", "types"],
    "compilerOptions": {
    "module": "esnext",
    "target": "ES2015",
    "lib": ["dom", "esnext"],
    "importHelpers": true,
    // output .d.ts declaration files for consumers
    "declaration": true,
    // output .js.map sourcemap files for consumers
    "sourceMap": true,
    // match output dir to input dir. e.g. dist/index instead of dist/src/index
    "rootDir": "./src",
    // stricter type-checking for stronger correctness. Recommended by TS
    "strict": true,
    // linter checks for common issues
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    // use Node's module resolution algorithm, instead of the legacy TS one
    "moduleResolution": "node",
    // transpile JSX to React.createElement
    "jsx": "react",
    // interop between ESM and CJS modules. Recommended by TS
    "esModuleInterop": true,
    // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
    "skipLibCheck": true,
    // error out if import and file system have a casing mismatch. Recommended by TS
    "forceConsistentCasingInFileNames": true,
    // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
    "noEmit": true,
    }
    }
  3. Some sample code in the index.ts:
export function logSecond(...args: any[]) {
  if (args.length > 1) {
    const [,second] = args;
    console.log(second);
  }
}
  1. Run yarn build
  2. Check the dist/es-6-module.esm.js output:

    
    function logSecond() {
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
    }
    
    if (args.length > 1) {
    var second = args[1];
    console.log(second);
    }
    }

export { logSecond };


### Desired Behavior

Ideally there would be a way to not build for ES5. 

### Suggested Solution

I'm wondering if this has more to do with Rollup or Babel because modern TS doesn't do this? I've messed around with a `tsdx.config.js`, but still with no improvements.

### Who does this impact? Who is this for?

Library authors wanting to drop legacy node and browser support.
justin-schroeder commented 3 years ago

FWIW — TSDX is an awesome project, was really helpful in bootstrapping a new typescript project. It's helpful to have an opinionated approach like this. The project I'm working on is trying to shave every byte out it can so this issue was a bit of a showstopper for me — in the meantime i've moved to straight tsc compilation with a custom terser implementation to shave a few extra bytes off.

xdoer commented 3 years ago

You can create a babel config file, and specify true to targets.esmodules option.

remcohaszing commented 2 years ago

I found out this can be done by adding the following .browserslistrc file in your project root:

last 2 Chrome versions
last 2 Firefox versions
last 2 Safari versions
node 12

It can’t be too new, because tsdx uses an older version of terser which doesn’t understand some syntax (such as optional?.chaining)