emotion-js/emotion 12598
👩🎤 CSS-in-JS library designed for high performance style composition
TheLarkInn/unity-component-specification 212
This is a WIP draft of the Unity (Single File Web Component) Specification
css-in-reason
Feature Flags: The Next Generation
macros for babel. I think.
threepointone/asyncstorage-mock 9
a mock for react-native's asyncstorage api. useful for testing.
iOS apps in Javascript like React Native.
global event bus
threepointone/async-act-test-21-11 1
Created with CodeSandbox
threepointone/backbone-mongodb 1
Backbone extensions to support local MongoDB back-end storage
issue commentreactjs/react-codemod
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
We ran into this also. You can fix it by setting the
jsx
compiler option: https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#react-17-jsx-factories
ok
"jsx": "preserve",
comment created time in 4 hours
issue commentevanw/esbuild
collect performance timings about plugin cost
@evanw ,it seems esbuild-wasm's plugin does not running concurrently, I do some profile on my application(https://github.com/evanw/esbuild/files/6095377/browser.cpuprofile.zip), It seems that handleRequest's cost is a little too high(the cost is mostly in the js-to-wasm function, and the cost is much slower on node #922 ),
it seems that can do some perf metrics on esbuild's js side
https://github.com/evanw/esbuild/blob/899414ec00b92e069060f049084d061b534c634f/lib/common.ts#L632-L658, since it already await esbuild plugin's resolve&load hooks.
comment created time in 4 hours
issue openedevanw/esbuild
[Feature]: lib/main.js should target to node:10 or higher node version
since lib/main.js always runs on node, and node 10+(node@8 already reaches ends-of-life) supports most esnext features, I think it should transformed target to node10+ other than es2015( for performance and debugging), especially the transformed async/await is not easy to debug.
created time in 5 hours
issue commentevanw/esbuild
Good to know. Thanks for calling this out. As you can tell I don't use yarn myself. It looks like this only happens with yarn 1 but not with yarn 2? Technically I could just not print the time if the
npm_config_user_agent
environment variable containsyarn/1.
. Maybe I'll try that.
I’m on Yarn 1.22 and I always see this footer when running commands such as yarn esbuild
. I don’t know whether Yarn 2 also does this, but I would expect 90%+ of your Yarn-based users to be on 1.x.
Yarn’s decorative text gets annoying when you are relying on terminal output for debugging, so I’ve started doing ./node_modules/.bin/esbuild
and more recently I just alias esbuild as alias esbuild=node_modules/.bin/esbuild
in my .bash_profile
. I think there’s a silent flag for yarn
but it’s tripped me up in the past so I don’t bother with it anymore.
General example:
Yarn + esbuild example: (I’m on a Mac FWIW)
I don't think there is a number you can assign to each file that would mean something useful.
Anyway, I do think it’s important for your users to understand how fast esbuild is without the need for time esbuild ...
.
Somewhat related: Create React App does some interesting profiling when building (i.e. react-scripts build
) where it compares your previous build against your current build (not time measured, but bundle sizes). I found this image online so you can see what I mean. This might be a nice enhancement to summary output, reporting time measured and bundle size deltas. (Just an idea, not requesting this)
One interesting direction you could take this is emitting some kind of stats file (a little like your metafile idea, but for bundle statistics / performance metrics). One way I’ve done this in the past (not related to esbuild) is by running a small script on build so every release includes some metadata. If you were to support something like this for esbuild with normal builds (maybe a stats
flag?) then esbuild would be able to compare stats from previous builds assuming it relates to the same build.
Sorry for getting off-topic. I just think terminal UIs are generally under-appreciated but is actually critical to adopting new users.
comment created time in 5 hours
push eventevanw/esbuild
commit sha 05cb1a01bbecedba376081ebfdc76e4638e640df
remove "startService" from uglify and terser tests
push time in 5 hours
issue openedevanw/esbuild
I wonder if ESBuild WASM could enable “dev-serverless” JS
Specifically the flow would be:
- Go to special (remote) webpage
- Drag and drop code folder into page with index.html
- Using the new Filesystem API, contents of page are replaced with index.html, but esbuild runs in web worker and live bundles app / assets.
- NPM imports replaced with Skypack/JSPM/whatever
- URL changes to match directory name and the directory handle is persisted to IndexedDB. Next time you refresh it reloads the folder and bundles again (remembers)
- Now you have an in-browser “dev-server” without installing any software or running Node.js and with modern JS tooling
- Unlike CodeSandbox/etc this lets you use your own local and comfortable development environment/IDE.
- maybe could do deploys this way too. With a literal one-click in-app deploy button
- with a lot of work, could probably make it Next.js compatible via intercepting fetch requests in service workers & magic
if the bundler is fast enough to run inside the webpage and works with the local dev environment, why would people still use and install a CLI?
The 2nd order effects would be interesting too.
Will the next generation of frontend engineers know how to use terminals? If you only use a terminal to run “git pull”, “git clone”, “git commit” and “git push” then a git GUI makes more sense.
If you’re not running npm install, will web apps still have a package.json?
created time in 6 hours
push eventevanw/esbuild
commit sha b2d208933fd230b67f2aaad9b59561e4e6377d0e
fix typescript type error
commit sha 17fc69e999761f864b6f8e8575396acb1330f146
avoid run time in summary for yarn 1
push time in 6 hours
issue commentevanw/esbuild
Edit: I now see that
--summary
has been supported since 0.8.28 so you probably won’t want to change it. 😅
I'm fine with changing it. People shouldn't be parsing it (e.g. it's truncated over a certain number of entries) so it should only be for humans.
My only concern is that when using esbuild with
yarn
for example, is that the output is going to get very noisy sinceyarn
also decorates outputs with its ownDone in X seconds
footer. I’m not sure it actually makes sense for esbuild output to be shaped byyarn
, but I felt I should bring attention to this.
Good to know. Thanks for calling this out. As you can tell I don't use yarn myself. It looks like this only happens with yarn 1 but not with yarn 2? Technically I could just not print the time if the npm_config_user_agent
environment variable contains yarn/1.
. Maybe I'll try that.
That way users can see, whether for one file or for many, how long each file took to process.
I don't think there is a number you can assign to each file that would mean something useful. Go has a preemptable task scheduler so just measuring the time difference between the start and the end of a task doesn't mean the task was running for that whole time. And also esbuild is heavily multithreaded so all of the times would add up to much longer than the actual running time, which is misleading IMO.
comment created time in 6 hours
push eventevanw/esbuild
commit sha 5f161e43660a2c47e58f831a4346d58119552050
add node unref tests to common tests
commit sha 826e791bd357850f27347f903f5208b5bf3adcd0
remove "startService" in unref tests
push time in 6 hours
push eventevanw/esbuild
commit sha bdc21687092cc7ff3a0a0353635c8dd136a28f21
remove the "startService" API
commit sha 1ed4fce9918928bee1564ea2d5c110521496651a
types: consolidate the "ImportKind" type
commit sha e796c45b215e270119dfc924f31f0b057c59a864
enforce that "transform" input is a string
push time in 6 hours
issue closedevanw/esbuild
[Question] Extending esbuild-style logs in TypeScript
I really enjoy how esbuild logs are printed. I have a very clear sense of what went wrong and why, and the colors help draw attention to the important bits.
I’m poking around in internal and found:
// ...
if terminalInfo.UseColorEscapes {
if d.Suggestion != "" {
return fmt.Sprintf("%s%s%s:%d:%d: %s%s: %s%s\n%s%s%s%s%s%s\n%s%s%s%s%s\n%s%s%s%s%s%s%s\n",
textColor, textIndent, d.Path, d.Line, d.Column,
kindColor, kind.String(),
textResetColor, d.Message,
colorResetDim, d.SourceBefore, colorGreen, d.SourceMarked, colorResetDim, d.SourceAfter,
emptyMarginText(maxMargin, false), d.Indent, colorGreen, d.Marker, colorResetDim,
emptyMarginText(maxMargin, true), d.Indent, colorGreen, d.Suggestion, colorResetDim,
d.ContentAfter, colorReset)
}
return fmt.Sprintf("%s%s%s:%d:%d: %s%s: %s%s\n%s%s%s%s%s%s\n%s%s%s%s%s%s%s\n",
textColor, textIndent, d.Path, d.Line, d.Column,
kindColor, kind.String(),
textResetColor, d.Message,
colorResetDim, d.SourceBefore, colorGreen, d.SourceMarked, colorResetDim, d.SourceAfter,
emptyMarginText(maxMargin, true), d.Indent, colorGreen, d.Marker, colorResetDim,
d.ContentAfter, colorReset)
}
// ...
My question is, does this cover all esbuild-style logs? It would be helpful to better understand this so as I attack this in JS, I have a complete picture of how logs should appear generally.
I want to faithfully recreate these logs for JavaScript since esbuild cannot be used to run JavaScript (as talked about in #903). So I know I can use logLevel
to get esbuild to emit errors for bundling / building; I simply want to extend this terminal UI to errors generally as I’ve found them to be so useful.
Previously I drafted something like this:
export function format(msg: esbuild.Message, color: (...args: unknown[]) => void): string {
const meta = msg.location!
const namespace = `${meta.file}:${meta.line}:${meta.column}`
const error = `esbuild: ${msg.text}`
let code = ""
code += `${meta.lineText.slice(0, meta.column)}`
code += `${color(meta.lineText.slice(meta.column, meta.column + meta.length))}`
code += `${meta.lineText.slice(meta.column + meta.length)}`
return `${namespace}: ${error}
${meta.line} ${terminal.dim("|")} ${code}
${" ".repeat(String(meta.line).length)} \x20 ${" ".repeat(meta.column)}${color("~".repeat(meta.length))}`
}
closed time in 7 hours
zaydekissue commentevanw/esbuild
[Question] Extending esbuild-style logs in TypeScript
I understand Unicode and runes in the abstract but implementation is another story. I previously wrote / forked some code and created this to help me distinguish between ASCII / BMP / astral code points (for a previous project) but using regex for this kind of thing seems crude and offensive: https://github.com/codex-src/codex-wysiwyg/blob/master/src/lib/UTF8/testAlphanum/index.js.
because different terminals have different levels of Unicode support so there is no one code point width table algorithm that works for all terminals
I hadn’t considered that, but yes, terminal encoding is another story. In my own experience I haven’t noticed any hiccups with caret or tilde alignment in terminal output but I’ll be sure to report them if I come across them in the wild.
Yes. And esbuild also indicates where the plugin was registered as well. That looks like this:
Ah. I think I now understand why you are splitting stacks beyond the first stack trace in common.ts:
let lines = (e.stack + '').split('\n', 4)
// ...
location = parseStackLinesV8(streamIn, (e.stack + '').split('\n', 3), '')
It looks like you’re propagating relevant stack traces to the user in this case. Thanks for pointing that out. I wasn’t sure if you were always omitting the stack trace from the user, but now I can see that it depends.
I’m gonna close this since you’ve more than answered my questions. Thank you for taking the time to do that.
I’ll also link this since it’s somewhat relevant to terminal UI / UX: https://github.com/evanw/esbuild/issues/704#issuecomment-791907616.
comment created time in 7 hours
issue commentevanw/esbuild
I wanted to get a sense of what the summary options feels like so I took a screenshot for myself and or others:
My only concern is that when using esbuild with yarn
for example, is that the output is going to get very noisy since yarn
also decorates outputs with its own Done in X seconds
footer.
Given the you have outdir
and outbase
options, would it make more sense to put milliseconds next to every file instead of as a footer? That way users can see, whether for one file or for many, how long each file took to process. This may not make perfect sense with how esbuild works, given it uses concurrency, etc., but you can also measure the differences between processing file A from file B.
In my own project (which uses esbuild), output looks like this. Maybe there is some inspiration to be shared?
<details> <summary>Implementation here:</summary>
import * as esbuild from "esbuild"
import * as path from "path"
import * as terminal from "../shared/terminal"
import * as types from "./types"
import * as utils from "./utils"
const TERM_WIDTH = 40
function formatMS(ms: number): string {
switch (true) {
case ms < 250:
// 250ms
return `${ms}ms`
default:
// 0.25ms
return `${(ms / 1e3).toFixed(2)}s`
}
}
export function export_(runtime: types.Runtime, meta: types.RouteMeta, start: number): void {
const dur = formatMS(Date.now() - start)
const l1 = runtime.directories.srcPagesDirectory.length
const l2 = runtime.directories.exportDirectory.length
let color = terminal.white
if (meta.routeInfo.type === "dynamic") {
color = terminal.cyan
}
let dimColor = terminal.dim.white
if (meta.routeInfo.type === "dynamic") {
dimColor = terminal.dim.cyan
}
const src = meta.routeInfo.src.slice(l1)
const src_ext = path.extname(src)
const src_name = src.slice(1, -src_ext.length)
const dst = meta.routeInfo.dst.slice(l2)
const dst_ext = path.extname(dst)
const dst_name = dst.slice(1, -dst_ext.length)
const sep = "-".repeat(Math.max(0, TERM_WIDTH - `/${src_name}${src_ext}\x20`.length))
console.log(
`\x20${terminal.dim(utils.timestamp())}\x20\x20` +
`${dimColor("/")}${color(src_name)}${dimColor(src_ext)} ${dimColor(sep)} ${dimColor("/")}${color(dst_name)}${
start === 0 ? "" : ` ${dimColor(`(${dur})`)}`
}`,
)
}
export function serve(args: esbuild.ServeOnRequestArgs): void {
const dur = formatMS(args.timeInMS)
let color = terminal.normal
if (args.status < 200 || args.status >= 300) {
color = terminal.red
}
let dimColor = terminal.dim
if (args.status < 200 || args.status >= 300) {
dimColor = terminal.dim.red
}
let logger = (...args: unknown[]): void => console.log(...args)
if (args.status < 200 || args.status >= 300) {
logger = (...args) => console.error(...args) // eslint-disable-line
}
const path_ = args.path
const path_ext = path.extname(path_)
const path_name = path_.slice(1, -path_ext.length)
const sep = "-".repeat(Math.max(0, TERM_WIDTH - `/${path_name}${path_ext}\x20`.length))
logger(
`\x20${terminal.dim(utils.timestamp())}\x20\x20` +
`${dimColor("/")}${color(path_name)}${dimColor(path_ext)} ${dimColor(sep)} ${color(args.status)} ${dimColor(
`(${dur})`,
)}`,
)
}
</details>
I recorded my output to provide an example. Also a screenshot since I think GH requires the video be downloaded first?
https://user-images.githubusercontent.com/58870766/110203178-f170a500-7eaf-11eb-8d88-773b154adac9.mov
comment created time in 8 hours
issue commentevanw/esbuild
Mix esbuild-loader and ts-loader
Just checking for an @ is to naive. Npm repos often use orgs -> require('@org/reponame')
and people could use @ in comments like jsdoc or just copyright statements. Thus this would limit the speed increase too much.
comment created time in 8 hours
push eventevanw/esbuild
commit sha ce41544761b331e7c4d322b2caacde821a332b50
single-line to multi-line build calls
commit sha 059f7c07689b9793b8227c6a0175a95b571af93d
remove "--summary", always print summary instead
push time in 8 hours
issue commentevanw/esbuild
[Question] Extending esbuild-style logs in TypeScript
I noticed the polish. It really shows! I wish more CLIs felt like esbuild. It has this really nice balance of discoverability / understandability which is ideal for your end users.
Thanks! That's great to hear.
I don’t mind starting with a naive implementation for now. Eventually I’d like to respect all of your original considerations.
I wouldn't do the Unicode table thing since esbuild doesn't even do that yet (and may never do it). I think it's actually really hard (or impossible?) to do this right anyway because different terminals have different levels of Unicode support so there is no one code point width table algorithm that works for all terminals. It felt appropriate to bring it up to mention what esbuild doesn't currently handle.
Am I right to assume that when plugins crash, esbuild decorates those errors too?
Yes. And esbuild also indicates where the plugin was registered as well. That looks like this:
Not sure if that's relevant for what you're doing or not.
comment created time in 8 hours
issue commentevanw/esbuild
Mix esbuild-loader and ts-loader
it's very hard for me to detect if a file contains a decorator
I was imagining you could do something like /@\w+/.test(contentsOfFile)
to reject files that definitely don't contain a decorator. That might look something like this (a real-world plugin would likely read from tsconfig.json
somehow):
let tscDecoratorPlugin = {
name: 'tsc-decorator',
setup(build) {
let options = {
// Note: This would be more complicated in practice
experimentalDecorators: true,
emitDecoratorMetadata: true,
};
// Note: May want to support "*.tsx" too
build.onLoad({ filter: /\.ts$/ }, async (args) => {
let ts = await require('fs').promises.readFile(args.path, 'utf8')
if (/@\w+/.test(ts)) {
let program = require('typescript').createProgram([args.path], options);
let contents;
program.emit(void 0, (path, js) => contents = js);
return { contents };
}
})
},
}
require('esbuild').build({
entryPoints: ['entry.ts'],
bundle: true,
outfile: 'out.js',
plugins: [tscDecoratorPlugin],
}).catch(() => process.exit(1))
comment created time in 8 hours
issue commentevanw/esbuild
Support emitting typescript decorator metadata
I'm currently trying to write an esbuild plugin which will try to build with esbuild and compile only the files containing docorators with tsc again. This should result in faster build times as usually not all files use decorators. See https://github.com/evanw/esbuild/issues/915#issuecomment-791758649
comment created time in 8 hours
issue commentevanw/esbuild
[Question] How to reuse esbuild-style logging in JavaScript?
Replicating this exactly will likely be kind of hard because there has been a lot of polish put into them.
I noticed the polish. It really shows! I wish more CLIs felt like esbuild. It has this really nice balance of discoverability / understandability which is ideal for your end users.
Thank you for elaborating on some of the more subtle implementations details. I can mostly understand logger.go now.
Another detail that esbuild doesn't yet handle is that some Unicode code points can technically take up zero or two columns instead of just one. This isn't common with the code I work with but may be more of an issue for people working in other languages. Handling this is really gross though and involves large tables of code point values.
I’ve dealt with a fair share of Unicode / regex / tables and yeah, I know what you mean. I don’t mind starting with a naive implementation for now. Eventually I’d like to respect all of your original considerations.
Here’s my WIP for what it’s worth:
<details> <summary>WIP implementation here:</summary>
export function formatMessage(message: esbuild.Message): string {
const loc = message.location!
let file = ""
file += path.relative(process.cwd(), loc.file) + ":"
file += loc.line + ":"
file += loc.column + 1 // One-based
const text = message.text
if (text.endsWith("is not defined")) loc.length = text.slice(0, -" is not defined".length).length
let code = ""
code += loc.lineText.slice(0, loc.column)
code += terminal.green(loc.lineText.slice(loc.column, loc.column + loc.length))
code += loc.lineText.slice(loc.column + loc.length)
let gap1 = ""
gap1 += " ".repeat(3)
gap1 += loc.line + " "
gap1 += "│"
let gap2 = ""
gap2 += " ".repeat(3)
gap2 += " ".repeat((loc.line + " ").length)
gap2 += "│"
return (
terminal.bold(` > ${file}: ${terminal.red("error:")} ${text}`) +
`
${gap1} ${code}
${gap2} ${" ".repeat(loc.column)}${loc.length === 0 ? terminal.green("^") : terminal.green("~".repeat(loc.length))}
`
)
}
export function formatMessages(messages: esbuild.Message[]): string {
let str = ""
str += messages.map(message => formatMessage(message))
str += "\n"
str += `${messages.length} error${messages.length === 1 ? "" : "s"}`
return str
}
</details>
I discovered your extractErrorMessageV8
code in lib/common.ts
, and used that to help me bootstrap parsing V8 stack traces.
<details> <summary>Working implementation here:</summary>
import * as esbuild from "esbuild"
import * as fsp from "fs/promises"
// This implementation is heavily based on @evanw’s "extractErrorMessageV8"
// implementation in esbuild.
//
// https://github.com/evanw/esbuild/blob/master/lib/common.ts
export default async function parseV8ErrorStackTrace(error: any): Promise<esbuild.Message> {
let text = "Internal error"
let location: esbuild.Location | null = null
try {
text = ((error && error.message) || error) + ""
} catch {}
// Optionally attempt to extract the file from the stack trace, works in V8/node
try {
const stack = error.stack + ""
const lines = stack.split("\n", 3)
const at = " at "
// Check to see if this looks like a V8 stack trace
if (!lines[0]!.startsWith(at) && lines[1]!.startsWith(at)) {
let line = lines[1]!.slice(at.length)
while (true) {
// Unwrap a function name
let match = /^\S+ \((.*)\)$/.exec(line)
if (match) {
line = match[1]!
continue
}
// Unwrap an eval wrapper
match = /^eval at \S+ \((.*)\)(?:, \S+:\d+:\d+)?$/.exec(line)
if (match) {
line = match[1]!
continue
}
// Match on the file location
match = /^(\S+):(\d+):(\d+)$/.exec(line)
if (match) {
const contents = await fsp.readFile(match[1]!, "utf8")
const lineText = contents.split(/\r\n|\r|\n|\u2028|\u2029/)[+match[2]! - 1] || ""
location = {
file: match[1]!,
namespace: "file",
line: +match[2]!,
column: +match[3]! - 1,
length: 0,
lineText: lineText, // + "\n" + lines.slice(1).join("\n"),
}
}
break
}
}
} catch {}
const message: esbuild.Message = {
detail: undefined, // Must be defined
location,
notes: [], // Must be defined
text,
}
return message
}
</details>
Am I right to assume that when plugins crash, esbuild decorates those errors too?
comment created time in 8 hours
issue commentevanw/esbuild
Mix esbuild-loader and ts-loader
@evanw it's very hard for me to detect if a file contains a decorator. Thus I'm thinking of compiling the code with esbuild and then check for __decorate
in the esbuild output and compile it again with tsc. Is there a hook available for this? Or could you create a new one where I could do this?
comment created time in 8 hours
pull request commentevanw/esbuild
This plan looks amazing! Thank you! Please, let me know if I can contribute with something, could work on some tasks for the JS APIs for example.
comment created time in 9 hours
push eventevanw/esbuild
commit sha 745d9c0121a412745fe9d8feabda255c9f6a9345
remove unused "SpinnerBusy" and "SpinnerIdle"
push time in 9 hours
PR opened evanw/esbuild
I'm using this PR to put together the next breaking change release as I build it. Not sure if a PR is the best format for this but I'm giving it a shot. So this PR exists to publicly document what's going into the upcoming version 0.9.0 release. I will be updating it as I go.
For context: I have been trying to batch breaking changes together so that they are less disruptive. But they have been piling up because one of the big changes (the linker rewrite) is unfortunately taking longer than I had hoped. I'd like to do a breaking change release now to get some of these breaking changes out even though it won't contain the linker rewrite just to keep other things moving along. This might mean there are at least two breaking change releases coming up: this one and another one with the linker rewrite. Note that the next version after version 0.9.0 will be version 0.10.0, not version 1.0.0. It's definitely getting close to 1.0.0 but it's not quite that close.
The rewrite of the linker is being done to address many shortcomings of the current linker all at once. However, that has involved some significant R&D effort (e.g. 1, 2, 3, 4) and it is unfortunately still a work in progress. I did a brain dump of some information about the linker rewrite at the end of this post.
Definitely in version 0.9.0
-
[x] Remove the now-unused
--avoid-tdz
flagThis flag no longer does anything because this transformation is now always applied during bundling. It hasn't been removed yet to avoid a breaking change.
-
[ ] Remove
SpinnerBusy
andSpinnerIdle
from the Go APIThese options were part of an experiment with the CLI that didn't work out. Watch mode no longer uses a spinner because it turns out people want to be able to interleave esbuild's stderr pipe with other tools and were getting tripped up by the spinner animation. These options are currently ignored but haven't been removed yet to avoid a breaking change.
-
[ ] Remove the
--summary
flag and instead just always print a summaryThe summary can be disabled if you don't want it by passing
--log-level=warning
instead. I'm going to try this because I believe it will improve the UX. People have this problem with esbuild when they first try it where it runs so quickly that they think it must be broken, only to later discover that it actually worked fine. While this is funny, it seems like a good indication that the UX could be improved. So I'm going to try automatically printing a summary to see how that goes. -
[ ] Remove the
startService()
API, leaving onlybuild()
andtransform()
The context is that the
startService()
API was added quickly in response to a user request and at the time I was unaware ofunref()
which makes it possible to use a child process without requiring people to callservice.stop()
. Many thanks to @SalvatorePreviti who contributed this change in #656. Callingservice.stop()
no longer does anything, so there is no longer a strong reason for keeping thestartService()
API around. The primary thing it currently does is just make the API more complicated and harder to use. I plan to add aninitialize({ wasmURL })
API to replace the configuration ofwasmURL
in the browser that used to be done bystartService()
. And thebuildSync()
andtransformSync()
APIs will still exist on node. -
[ ] Split the banner and footer features into separate values for JS and CSS (#712)
I have been trying to make sure all of the features added are language-agnostic where it makes sense. However, the banner and footer features were an oversight and were added as a JavaScript-specific feature. They don't currently work with CSS. I plan to change the API to make it a mapping of language to value to make it more language-agnostic, which is a breaking change.
Probably in version 0.9.0
-
[ ] Remove the implicit
.mjs
and.cjs
extensionsI added these because Webpack has implicit
.mjs
extensions and it seemed like a reasonable idea to support these at the time. However, doing this can actually break packages that havesome-file.mjs
andsome-file.js
sitting side-by-side. This also isn't how node works so doing this breaks compatibility with node. So it feels like this should be an opt-in change instead of an opt-out change. I'm going to try removing them from the default configuration. You can still configure them yourself with the "resolve extensions" setting if you'd like, although it might break stuff. Otherwise you should use the.mjs
and.cjs
extensions explicitly instead of omitting them. -
[ ] Remove the ability to use
require(...)
on a file in ESM (ECMAScript module) formatI had originally enabled this because it seemed reasonable to support. You can just convert the ESM file to a CommonJS file when you hit this case and then load it as CommonJS instead. However, this has a few problems:
-
This isn't how node works. Doing this in node is impossible and will cause a syntax error. So it's kind of a weird thing to support and there isn't really a precedent that says how it should behave. I want esbuild to follow existing conventions instead of inventing new ones, and it turns out this was kind of inventing a new convention. It feels best for esbuild and for the ecosystem if people don't come to rely on this weird thing actually working, so I'm going to try disabling this.
-
Doing this makes import order really confusing to reason about. Part of what I am doing with the linker rewrite is to be much more strict about having esbuild follow the correct import order, but this edge case doesn't have a well-defined import ordering. The problem is that ESM import order is determined by a depth-first traversal of the import graph and is entirely statically determined at link time, but
require(...)
is dynamically-determined at run time. Where do ESM imports in the required file end up in the static module initialization order? Do they even end up in the static module initialization order at all? Should they also be converted from ESM to CommonJS recursively, potentially contaminating a large part of the bundle? There isn't really any existing ESM-native platform that behaves this way. -
It also causes extra issues now that TLA (top-level await) is a part of JavaScript. TLA is only available in ESM files and means that loading them can now be asynchronous. But
require(...)
is synchronous so loading an ESM file with a TLA file anywhere in its dependency chain must be forbidden. If usingrequire(...)
with ESM were to be supported then you may be seemingly arbitrarily prevented from adding anawait
to a file because some other file in a seemingly unrelated place happened to use arequire(...)
call. It seems better for code health to just avoid this possibility in the first place. This constraint also makes the bundler simpler to implement.
Getting this change out should hopefully make the linker rewrite go more smoothly.
-
Maybe in version 0.9.0
-
[ ] Remove the
metafile
fromoutputFiles
(#633)Right now using
metafile
with the API is unnecessarily cumbersome because you have to extract the JSON metadata from the output file yourself instead of it just being provided to you as a return value. This is especially a bummer if you are usingwrite: false
because then you need to use a for loop over the output files and do string comparisons with the file paths to try to find the one corresponding to themetafile
. Returning the metadata directly is an important UX improvement for the API. This hasn't been done yet because doing this is a breaking change. -
[ ] Add support for node's
exports
field inpackage.json
(#187)This feature was recently added to node. It allows you to rewrite what import paths inside your package map to as well as to prevent people from importing certain files in your package. Adding support for this to esbuild is a breaking change (i.e. code that was working fine before can easily stop working) so it must be done in a breaking change release.
-
[ ] Support content hashes in entry point names (#518)
Support for this is already planned. The plan is to add the
--entry-names=
flag and let you put the[hash]
placeholder somewhere inside it to cause esbuild to include the content hash in entry point names. You can then use themetafile
to figure out what the output path was for each entry point. However, this would introduce cycles into the content hash calculation as the content hash includes not just the current file but also all of the content hashes of all transitive dependencies and entry points can reference each other using dynamicimport(...)
expressions.Addressing this requires a different approach to chunk generation that is part of the linker rewrite. This technically isn't a breaking change but it has a strong possibility of accidentally introducing bugs (especially with source maps) since it's a lot of new code, so it may also be appropriate for a breaking change release. Although it could potentially make sense to hold this back for the next breaking change release to avoid delays.
Hopefully in version 0.10.0
-
Code splitting for all output formats (#16)
Right now code splitting only works for the
esm
output format, and only works for JavaScript. It should also work for theiife
andcjs
output formats, and also for CSS. I have a plan to address this and it is a part of the linker redesign. -
Manual chunk labels (#207)
This feature isn't implemented yet because it creates import cycles and the content hashing algorithm can't deal with cycles yet. But this is being kept in mind during the linker rewrite so this should be relatively easy to add when the new linker is ready.
-
Collapse duplicate external imports (#475)
Right now each individual
import
statement for an external module ends up in the bundle even though they all reference the same external path and the external file is only ever imported once. I plan to collapse this into as few import statements as possible (usually one but may be up to three) as part of the rewrite of the linker. -
Bundling with top-level await (#253)
It's important to have esbuild support top-level await now that it's officially a part of JavaScript and usable in both node and in the browser. Unfortunately the semantics are extremely complicated (and not even implemented correctly in V8 yet!) so esbuild's initial implementation may not be totally accurate. It will at least contain the important parts (
await
works and sibling modules go in parallel). Currently all implementations behave slightly differently so there isn't yet common consensus about exact behavior among implementations. My current plan is to bundle files into groups by what asynchronous files they transitively depend on to reduce the overall number of files, then evaluate files within those groups in the order they would have been evalauted in if there was no top-level await. Cross-group ordering will depend on the order of promise resolutions. -
Fix import ordering issues with internal code (#399, #465)
Right now import order is not accurate when code splitting is active. The fundamental issue is that code in chunks is eagerly evaluated when that chunk is imported but different parts of the chunk need to be evaluated at different times for correctness. Either the chunk needs to be split into smaller chunks or code in chunks must be lazily evaluated to fix import order. I'm currently planning to lazily evaluate code to avoid additional chunk splits.
-
Potentially break the ordering of external imports
External imports cannot be lazily evaluated in
esm
and respecting the correct import order would hurt bundle optimization and make the bundler more complicated. Either chunks would have to be split into further chunks or code would potentially need to be awkwardly stuffed intoimport
statements containing data URLs, both of which would bloat code and hurt bundle download performance. I'm currently considering having external import order still be incorrect (i.e. hoisted to the top) since that's much simpler and seems to be what some other bundlers do anyway. -
Potentially roll back the file splitting optimization
Currently esbuild contains an optimization that no other bundler supports: individual unrelated statements within a file can end up in separate chunks when code splitting is active if they are used by a disjoint set of entry points. This means you can have a big library file of functions and potentially not have any shared chunks if no two entry points use any of the same functions. However, the blocking for top-level await works at the file boundary and this optimization made thinking through top-level await evaluation order too complicated. I'm seriously considering removing this optimization to restore my sanity and get top-level await out the door. I don't feel too bad about this because no other bundler does this yet anyway.
pr created time in 9 hours
issue commentevanw/esbuild
Yes, that's correct. It doesn't use Microsoft's implementation at all although I did reference it heavily when I made it. There are other similar efforts that do this too (reimplement TypeScript-to-JavaScript conversion from scratch) such as Babel, Sucrase, and SWC. I know at least Babel and Sucrase have similar limitations to esbuild around isolatedModules
.
comment created time in 10 hours
issue commentevanw/esbuild
Can you please mention list of supported fields (from tsconfig.json) in the corresponding section?
👍
What is the ES version used by default during TS compilation to JS? And can adjust this version somehow?
The
--target=
flag defaults toesnext
but you can set it to values such as--target=es2018
,--target=chrome80
,--target=node15
, or even a comma-separated list of targets such as--target=es2020,chrome58,firefox57,safari11,edge16
. The full documentation is here: https://esbuild.github.io/api/#target.
Thank you. Do I understand correctly that esbuild contains its own (custom) compiler/transpiler from Typescript to ES?
comment created time in 10 hours
issue commentevanw/esbuild
vite events.js:292 throw er; // Unhandled 'error' event
No, npm did not report an error, the installation is normal, but I found no esbuild.exe exists in node_modules/esbuild
comment created time in 12 hours
issue commentevanw/esbuild
[Question] How to reuse esbuild-style logging in JavaScript?
Replicating this exactly will likely be kind of hard because there has been a lot of polish put into them. Some details to think about:
- When computing column counts, keep in mind that JavaScript strings are UTF-16 while the actual files are UTF-8. You may need to operate on UTF-8 buffers instead for sanity. Not sure.
- Lines that are longer than the terminal width are truncated with
...
ellipses, potentially on one or both sides (this gets pretty complicated). This helps a lot with errors in minified code but is otherwise probably not necessary. - Tab stops should be expanded for the underline to line up correctly. This is also relevant when truncating lines since the post-expanded content should be the truncated part.
Another detail that esbuild doesn't yet handle is that some Unicode code points can technically take up zero or two columns instead of just one. This isn't common with the code I work with but may be more of an issue for people working in other languages. Handling this is really gross though and involves large tables of code point values.
comment created time in 14 hours
push eventevanw/esbuild
commit sha 8ca9f4626fa1dffb9f99eec06838f93878c0efb9
fix class fields with "keep names"
push time in 15 hours