- Published on
XY problem - Debugging spiral with Rollup and esbuild
- Authors
- Name
I do this way too often:
- I have a problem
- I think of a solution
- The solution doesn't work
- I try a fix for the solution
- The fix doesn't work
- I try a fix for the fix
- The fix for the fix doesn't work
- and on it goes, until I've completely lost track of what the original problem was.
Here is my latest example of this.
Problem
I was trying to remove reliance of next-transpile-modules
for my component library @planda/design-system
, since Next.js's dev speed was way too slow (20-30s start up speed), so I had to use turbo. Turbo didn't work with next-transpile-modules, so I had to remove it. I'm pretty sure something is really wrong with my Next.js build, I'll be focusing on fixing the speed issues next.
1. Inital look at the problem
Here's some context:
- I had been using Rollup to bundle my package, and it was working fine.
- I'm on an old version of Rollup, and I've had issues with it before. I previously tried upgrading the version and didn't manage to get it to work.
- I have very little understanding on bundlers and how they work.
- I've used esbuild before, and had a great experience with it. That was for an AWS lambda function in Typescript.
Since I didn't know how to do the next-transpile-modules
part during the rollup build, for some reason I thought I should switch to esbuild.
2. Type errors
- I needed declaration files for my package, which I realized would be included if I set
noEmit
tofalse
in mytsconfig.json
file. - I had a lot of type errors in my project, which I ignored before since Rollup built anyway.
- I needed to fix all of these in order to get those
.d.ts
files from runningtsc
- At first I was getting errors from
node_modules/next/...
, which was odd since this was a devDependency, andnode_modules
was excluded in mytsconfig.json
file. - Doing
tsx --explainFiles
made be realize that thenode_modules/next
was being included because thenext-env.d.ts
file. - I excluded
next-env.d.ts
intsconfig.json
, but then got more errors that I solved from upgradingtypescript
. However, the reason I was on an older version oftypescript
was becausestitches
didn't work with the newer version. - I found something on the Github issue for the
stitches
problem that I never saw before: there was actually a fix, but it was in thecanary
version ofstitches
. - I installed the canary version, had to fix a few more types, including dealing with this Github issue
- Had more type errors, which I fixed by upgrading
@types/react
,@types/react-dom
, and@types/node
- Now all my type errors were resolved. The next step was getting esbuild to work...
3. esbuild config
- Below was my (initial) esbuild config. I failed to get it to work due to CSS modules.
esbuild.config.js
const esbuild = require('esbuild');
const { nodeExternalsPlugin } = require('esbuild-node-externals');
const { dependencies, peerDependencies } = require('./package.json');
const react18Plugin = require('esbuild-plugin-react18');
const esbuildPluginTsc = require('esbuild-plugin-tsc');
const CssModulesPlugin = require('esbuild-css-modules-plugin');
esbuild
.build({
entryPoints: ['src/index.ts'],
outdir: 'dist',
bundle: true,
minify: false,
treeShaking: true,
// sourcemap: true,
format: 'esm',
target: ['es6'],
loader: {
'.module.css': 'local-css',
},
plugins: [
CssModulesPlugin({}),
nodeExternalsPlugin(),
react18Plugin(),
// esbuildPluginTsc({ tsx: true }),
],
external: [].concat.apply(
[],
[Object.keys(dependencies || {}), Object.keys(peerDependencies || {})]
),
})
.then(async (result) => {
console.log('Build complete');
})
.catch((e) => {
console.error(e);
process.exit(1);
});
- At first, esbuild would always remove my singular
.module.css
file, and throw an error due to the missing import. - I tried adding a loader like the docs say, but it was still excluding the file.
- I used the
esbuild-css-modules-plugin
plugin, but it was adding files in thedist/src
folder, while my files trying to import the error were in thedist
folder, therefore couldn't find the file. - I realized after everything was over, that the error was due to
tsc
, which was run after esbuild, but during the process, I got stuck here, decided it wasn't worth the time to fix.
4. Back to Rollup
- ChatGPT and Gemini were not helpful in debugging esbuild, so I tried GPT's solution for the Rollup config.
- I ran into this error:
export { AnnouncementsBar } from './custom/AnnouncementsBar.js';
^^^^^^
SyntaxError: Unexpected token 'export'
- I tried a lot of things to get it to work, which included spending a lot of types trying to get
type: 'module'
inpackage.json
to work, but my dependencies didn't supportesm
, so I dropped that. - I realized that the
rollup.config.js
file GPT had given me earlier usedformat: 'cjs'
instead offormat: 'esm'
, so I tried that, and it worked! (*after a few more tweaks of switching back fromesm
tocommonjs
) - I was also stuck on this issue for a while. What finally fixed it though was publishing a
canary
version tonpm
and installing that, instead of installing the local package. - I figured this was because the local
react
in the package, which was apeerDependency
, was interfering with the project'sreact
, even though I made sure both were the same version andnpm ls react
showed no duplicates.
Back to esbuild
- While writing the esbuild part of this blog post, I realized what my error was coming from.
- The reason I was getting the error was from running
tsc
after esbuild, which was adding thejs
files which had errors on top of the.d.ts
files I wanted. - The reason I was running
tsc
was becauseesbuild
doesn't include declaration files, and I needed types. I fixed this settingemitDeclarationOnly: true
in theesbuild
config. - I fixed this, changed
esbuild
tocjs
too, and it worked! - I'm pretty sure I'm still not doing things fully right, since in my
package.json
file, my types come from thedist
, while the main file comes fromdist/src
.
"exports": {
".": {
"require": "./dist/src/index.js",
"import": "./dist/src/index.js",
"types": "./dist/index.d.ts"
}
},
- It works though, so I'm not spending more time on it.
Final thoughts, lessons learned
- I learned most about
tsconfig.json
through this process. I now have a better understanding of a lot more of the settings. - I learned that in the end, Rollup and esbuild are similar, if my config doesn't work with one, it probably won't work in the other.
- The final solution of the last issue I spent a lot of time dealing with was super simple, I just had to switch from
esm
tocjs
in my Rollup and esbuild config. - I learned more about esm vs commonjs in the process, such as how the requirements for using
esm
are quite strict, and many libraries don't support it. - I should be better at identifying whether a problem is an
esm
vscjs
problem now.
Some proposed solutions so I don't spiral into the XY problem again
- Write down the original problem
- Take breaks
Create an ecard at CelebrateThisMortal.com • Be more productive with Planda