- emitted syntax (roughly)
- target
- alwaysStrict
- jsx
- jsxFactory
- jsxFragmentFactory
- jsxImportSource
- importsNotUsedAsValues
- preserveValueImports
- verbatimModuleSyntax (not yet implemented)
- useDefineForClassFields
- module resolution
- jsxImportSource?
- baseUrl
- moduleSuffixes
- paths
- other
- extends
target
- why would anyone want multiple syntaxes within the same bundle?
- IMO, respect only esbuild's top-level setting, then warn if esbuild option is unset but found in tsconfig
alwaysStrict
- better named
alwaysEmitUseStrictPrologue
- This is always enabled if in "strict" checking mode.
- Can this just always be true? If targeting ESM, you cannot avoid strict.
- If this is off, and you run esbuild on tsc output, how is that code referenced? Is it more imports?
- CJS is not necessarily strict.
- But, now that we're deprecating
noImplicitUseStrict
; does tsc always emit strict no matter what?- We emit "use strict" when
strict=false
,alwaysStrict=false
,noImplicitUseStrict=true
, so, ifnoImplicitUseStrict
is always true, all TS code that is modules is strict? - https://www.typescriptlang.org/play?strict=false&alwaysStrict=false&module=2&noImplicitUseStrict=false&suppressExcessPropertyErrors=false#code/KYDwDg9gTgLgBAMwK4DsDGMCWEWIhACgEo4BvAWACg4a4qBfIA
- So, the answer here is to just make esbuild always use strict?
- We emit "use strict" when
- better named
jsx
, etc- Would someone intentionally use multiple jsx targets? Maybe, in a monorepo? But would they really be using React and Preact?
- If someone ran tsc and emit, there would be no problem, because TS would emit JS with the right syntax/imports, so it feels like esbuild should allow it.
- why would anyone want "preserve" as a target in esbuild?
importsNotUsedAsValues
,preserveValueImports
,verbatimModuleSyntax
- Unfortunate effect of these is that bundlers have to handle all of them, so
adding a third one didn't make things simpler. Bundlers still have to know
which one a user is expecting, unless they universally throw their hands up
and assume that we're in a
verbatimModuleSyntax
world- In 5.5, we delete the first two? Won't stop people from using old versions, esbuild may have to do all three for a long time
- Unclear whether or not esbuild will actually respect side effects in
verbatimModuleSyntax
? verbatimModuleSyntax
forces writingimport foo = require("foo")
even though the bundler won't actually care?
- Unfortunate effect of these is that bundlers have to handle all of them, so
adding a third one didn't make things simpler. Bundlers still have to know
which one a user is expecting, unless they universally throw their hands up
and assume that we're in a
useDefineForClassFields
- Oh boy.
- This can only affect the project being bundles, not dependencies; they will have already had their stuff set up as desired.
- swc is moving to
[[Define]]
(in ES2022+?) unless configured otherwise.- Is that just TS's behavior?
- Does it make sense for both to coexist if we can do multiple tsconfigs? Maybe?
- evanw/esbuild#2993 (comment)
- Talks about deriving this from esbuild's target
- I agree this is a bad idea, this is a TS transformation problem
- Doesn't affect JS, right? Pure JS only has define semantics?
experimentalDecorators
- just like JSX, this could be scoped per-project
baseUrl
/paths
- handled by plugins in other bundlers
- if you run tsc and pass it into esbuild, it won't resolve.
- https://www.npmjs.com/package/tsconfig-paths-webpack-plugin
- maybe this should be a plugin too?
- But, esbuild may already have to process tsconfig anyhow.
- Comes down to people using
paths
for shortening imports when using a bundler - I don't think that pattern's going to go away
- https://github.com/vuejs/create-vue/blob/main/template/tsconfig/base/tsconfig.json
moduleSuffixes
- This is a hint to typescript for type checking, but does not affect emitted
paths.
- Code compiled with ts and then put through esbuild would not work!
- evanw/esbuild#2395 (comment)
- React native webpack uses
resolve.extensions
, maybe drop this feature and tell people to useresolveExtensions
like webpack? - https://esbuild.github.io/api/#resolve-extensions
- Using this would get the "project wide toggle" thing, because people can set
extensions to
[".ios.ts", ".native.ts", ".ts"]
- This is a hint to typescript for type checking, but does not affect emitted
paths.
jsxImportSource
- running tsc locks this in
tsconfig
and.ts
innode_modules
? Seems ill-advised to ever have this.- how about js files included via allowJs?
- could esbuild check to see if a tsconfig includes a file in includes/excludes/files and warn if a file is referenced but not listed?
- Generally, I think we can be guided by:
- What would happen if everyone ran
tsc
and then ran esbuild on the output? - Would anyone actually want the behavior?
- What would happen if everyone ran
- Keep supporting multiple tsconfigs. It seems required for too many options.
paths
,baseUrl
,jsx*
,useDefineForClassFields
,experimentalDecorators
, etc
- Entirely ignore
tsconfig
innode_modules
. Better yet, ignore.ts
innode_modules
too. If esbuild weren't involved, the.js
files will be executed, not the.ts
files. - Ignore
target
, let it be controlled by esbuild globally. It doesn't make sense to have this configured per project.- Gilding the lily: warn if
target
is unset, buttsconfig
has a value. - This is an exception to "what if tsc then esbuild".
- Gilding the lily: warn if
- Ignore
alwaysStrict
and always assume strict. For TS code, it's going to become effectively impossible to write code without being in strict mode. - Ignore
moduleSuffixes
and recommend esbuild'sresolveExtensions
, which is how it works in webpack and matches the user expectation of "global config".- They can set
[".ios.ts", ".native.ts", ".ts", ...]
.
- They can set
- Allow multiple
jsx
settings per-project. It's possible that there are monorepos with mixed environments. - Respect
useDefineForClassFields
+target
for TS code in choosing class emit style.- Alternatively, enabling this by default may also be fine; all "bad" code for this should only ever be in the user's project, not their dependencies. They can discover the problem themselves, right?
- Respect
experimentalDecorators
for TS code for figuring out which decorator to use. - Respect
paths
/baseUrl
, in the nearesttsconfig
. There is really no way to determine which tsconfig is the one to emit any particular file, so this seems like the only reasonable thing, besides giving esbuild a list oftsconfig
files that could apply and then have it run the globs to determine which one is the most applicable.- I just don't see people stopping using these options for more than just
describing runtime resolution. Many popular frameworks suggest using paths
like
@/*
forsrc
: https://github.com/vuejs/create-vue/blob/main/template/tsconfig/base/tsconfig.json - Gilding the lily: warn if that
tsconfig
'sinclude
/exclude
/files
do not include that file.
- I just don't see people stopping using these options for more than just
describing runtime resolution. Many popular frameworks suggest using paths
like
- Respect
importsNotUsedAsValues
,preserveValueImports
,verbatimModuleSyntax
? This really only depends on how much side effect behavior esbuild is wanting to emulate. Unfortunately us adding a third variant means more work, because dropping the other two means not supporting TS <5.0.
Gotchas:
- All of the above only apply to TS code...
- Except JSX emit, as those need to get downleveled at some point. By nature of "what if tsc ran", those need to be configurable too.
- Except
.js
files +paths
/baseUrl
; should paths apply? What do do? Should this be a plugin + aliases?
For settings that would typically require a tsconfig
, instead expand out
esbuild's configuration to allow them to be configured by path.
baseUrl
/paths
replaced withalias
.- Prior art: tsconfig-paths-webpack-plugin
jsx
options can be configured dynamically.useDefineForClassFields
andexperimentalDecorators
set per path, to help work around differences.
This feels less friendly to the users, though.