-
Notifications
You must be signed in to change notification settings - Fork 794
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(build): build the CLI module with esbuild #4187
Conversation
|
Path | Error Count |
---|---|
src/dev-server/index.ts | 37 |
src/mock-doc/serialize-node.ts | 36 |
src/dev-server/server-process.ts | 32 |
src/compiler/build/build-stats.ts | 27 |
src/compiler/output-targets/dist-lazy/generate-lazy-module.ts | 25 |
src/compiler/style/test/optimize-css.spec.ts | 23 |
src/testing/puppeteer/puppeteer-element.ts | 23 |
src/compiler/prerender/prerender-main.ts | 22 |
src/runtime/vdom/vdom-render.ts | 20 |
src/runtime/client-hydrate.ts | 19 |
src/screenshot/connector-base.ts | 19 |
src/compiler/config/test/validate-paths.spec.ts | 16 |
src/dev-server/request-handler.ts | 15 |
src/compiler/prerender/prerender-optimize.ts | 14 |
src/compiler/sys/stencil-sys.ts | 14 |
src/compiler/transpile/transpile-module.ts | 14 |
src/runtime/vdom/vdom-annotations.ts | 14 |
src/sys/node/node-sys.ts | 14 |
src/compiler/build/build-finish.ts | 13 |
src/compiler/prerender/prerender-queue.ts | 13 |
Our most common errors
Typescript Error Code | Count |
---|---|
TS2345 | 424 |
TS2322 | 398 |
TS18048 | 310 |
TS18047 | 100 |
TS2722 | 38 |
TS2532 | 34 |
TS2531 | 23 |
TS2454 | 14 |
TS2352 | 13 |
TS2769 | 10 |
TS2790 | 10 |
TS2538 | 8 |
TS2344 | 5 |
TS2416 | 4 |
TS2493 | 3 |
TS18046 | 2 |
TS2684 | 1 |
TS2488 | 1 |
TS2430 | 1 |
Unused exports report
There are 12 unused exports on this PR. That's the same number of errors on main, so at least we're not creating new ones!
Unused exports
File | Line | Identifier |
---|---|---|
src/runtime/bootstrap-lazy.ts | 21 | setNonce |
src/screenshot/screenshot-fs.ts | 18 | readScreenshotData |
src/testing/testing-utils.ts | 198 | withSilentWarn |
src/utils/index.ts | 145 | CUSTOM |
src/compiler/app-core/app-data.ts | 25 | BUILD |
src/compiler/app-core/app-data.ts | 115 | Env |
src/compiler/app-core/app-data.ts | 117 | NAMESPACE |
src/compiler/fs-watch/fs-watch-rebuild.ts | 123 | updateCacheFromRebuild |
src/compiler/types/validate-primary-package-output-target.ts | 62 | satisfies |
src/compiler/types/validate-primary-package-output-target.ts | 62 | Record |
src/testing/puppeteer/puppeteer-declarations.ts | 485 | WaitForEventOptions |
src/compiler/sys/fetch/write-fetch-success.ts | 7 | writeFetchSuccessSync |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just noting a few things
main: cjsFilename, | ||
module: esmFilename, | ||
types: dtsFilename, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likewise, this is copied too:
stencil/scripts/bundles/cli.ts
Lines 55 to 61 in 8301b79
writePkgJson(opts, opts.output.cliDir, { | |
name: '@stencil/core/cli', | |
description: 'Stencil CLI.', | |
main: cjsFilename, | |
module: esmFilename, | |
types: dtsFilename, | |
}); |
'@stencil/core/compiler': './compiler/stencil.js', | ||
'@stencil/core/dev-server': './dev-server/index.js', | ||
'@stencil/core/mock-doc': './mock-doc/index.cjs', | ||
'@stencil/core/internal/testing': './internal/testing/index.js', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set up aliases which will point to the entry points of other bundles. Note that in combination with getEsbuildExternalModules
, below, these will be marked as external and thus imported or required instead of being bundled in
* Node modules which should be universally marked as external | ||
* | ||
*/ | ||
const externalNodeModules = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the CLI module doesn't pull most of these in, but they are used by other bundles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a list of all the things we mark as external during the rollup build? Just so I know what to double check this list against 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it may not be totally exhaustive - on my other branch this was the external modules I collated while getting the cli
, compiler
, testing
, and mock-doc
bundles building with Esbuild, so when we go to tackle the others maybe we'll need a few more!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Man, I really wish there was a way to automatically generate this list (and the list of module aliases above). Feels like something easy to overlook.
Did you come up with all these by trial and error (like, does the build fail if we're missing one of these), or did you have to scan the code for each bundle to make sure you had all of them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I based this on the existing external
lists used for the rollup builds (see here, here, and here for instance) and then I think possibly had to add one or two things that weren't already present - it is a bit of an annoying thing, if we accidentally forget to add something we do want to have externalized to the list then esbuild (and rollup too!) will happily just pull it into the bundle.
e35f721
to
99546d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still getting accustomed to the ESBuild "world", but I don't wanna hold back a round of review on that account alone. I left a few different types of comments. Those that are marked secondary/tertiary aren't all that important ATM, just small comments here and there. The ones that aren't marked as secondary/tertiary are the more important ones here. LMK if you have any questions!
// node module redirection | ||
chalk: 'ansi-colors', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this comment/why we need this entry for cli
. I see references to something similar in alias-plugin.ts
:
const empty = new Set([
// we never use chalk, but many projects still pull it in
'chalk',
]);
Is this doing something to prevent 'chalk' usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't cli-specific, but actually from testing
:
stencil/scripts/bundles/testing.ts
Lines 91 to 93 in 9173759
if (importee === 'chalk') { | |
return require.resolve('ansi-colors'); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly in a no-browser-compilation world we don't need to worry about some of these things anymore (I hope so!)
* Node modules which should be universally marked as external | ||
* | ||
*/ | ||
const externalNodeModules = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a list of all the things we mark as external during the rollup build? Just so I know what to double check this list against 😆
2b4d653
to
85b80b0
Compare
Alright so I've just gotten some CI stuff together so that we now have essentially a parallel CI to our normal one which instead starts with the esbuild-based build and then runs the e2e, unit tests, etc (everything except browserstack) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took a look at most of this. Skipped over the actions stuff for now, but can review that if it's in a good state (wasn't sure if it's still a wip)
* Node modules which should be universally marked as external | ||
* | ||
*/ | ||
const externalNodeModules = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Man, I really wish there was a way to automatically generate this list (and the list of module aliases above). Feels like something easy to overlook.
Did you come up with all these by trial and error (like, does the build fail if we're missing one of these), or did you have to scan the code for each bundle to make sure you had all of them?
336b563
to
43f6029
Compare
Just took a little time to circle back on this and get CI passing, including the |
3fdee6b
to
e474e3b
Compare
e474e3b
to
4a40c34
Compare
4a40c34
to
776a9af
Compare
ee26959
to
a629d74
Compare
623cfc0
to
e377789
Compare
e377789
to
23cb0ad
Compare
000328e
to
2b5e571
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember feeling like this was in a decent state when we first looked through a long time ago. I think the most important aspects are:
- Bundle size should definitely be investigated before we rely on this full-time. If we wanna merge just to have CI run against this in the meantime I think that's fine
- Is there anything left to remove from the removal of in-browser compilation
506fd39
to
995558f
Compare
I realized the issue that was leading to the larger bundle size. In the rollup-based CLI bundle script we externalize the stencil/scripts/bundles/cli.ts Line 69 in b97dadc
Without that 'externalization' the So if you build with rollup:
vs with esbuild:
Now I'm unsure why the esbuild one is so much smaller! What was in the ~40kb? I'll look into that a bit. |
I think the difference in bundle size is basically down to the fact that the Rollup build retains all of our JSDoc comments while Esbuild removes them (the maintainer says this is a somewhat non-negotiable aspect of how esbuild works) |
@alicewriteswrongs Does that mean that |
I don't see a usage of that comment in the code that will be pulled into the |
Also just added an enhancement which is to add a way to watch the files built by esbuild, using a little helper function that takes in esbuild configs and, based on the |
2d7a53e
to
2df0a20
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just noting a few things I just changed
export function getBaseEsbuildOptions(): ESBuildOptions { | ||
return { | ||
bundle: true, | ||
legalComments: 'inline', | ||
logLevel: 'info', | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sets up a few base options which I think we'll always want across all future esbuild-based bundles we add, I thought we should probably just canonize this right now (especially the legalComments
bit based on @rwaskiewicz's comment)
export function runBuilds(builds: ESBuildOptions[], opts: BuildOptions): Promise<(void | ESBuildResult)[]> { | ||
if (opts.isWatch) { | ||
return Promise.all( | ||
builds.map(async (buildConfig) => { | ||
const context = await esbuild.context(buildConfig); | ||
return context.watch(); | ||
}), | ||
); | ||
} else { | ||
return Promise.all(builds.map(esbuild.build)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this lil helper will take an array of esbuild configs and our own Stencil-specific BuildOptions
object and if the isWatch
property is set on the BuildOptions
it will run a watch-mode build using esbuild.context
, otherwise it will just use esbuild.build
to do a single build.
The idea is that each of our bundle functions would create a series of esbuild configurations, do any other setup that is necessary, and then return the result of calling this function with those build configs. Then in our main entry point we use Promise.all
to await the result of all the builds.
also kind of funny that the esbuild interface is also called BuildOptions
, so I've taken to aliasing it as ESBuildOptions
c9e592a
to
1aced01
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds a support for building Stencil with [esbuild](https://esbuild.github.io/). This comprises: - a new subdirectory `scripts/esbuild` which holds all the esbuild-related stuff - support for bundling the `cli/` bundle with esbuild - new `package.json` scripts `build.esbuild` and `build.esbuild.watch` for doing a "hybrid" build - new CI workflows to build Stencil with esbuild and then run the existing unit and e2e test suites against the build artifact Right now this new build / bundle setup exists parallel to the existing, rollup-based build setup. The idea is that we'll continue to use rollup for building and releasing, but we'll gradually increase the scope of the esbuild-based pipeline until it can build all of stencil. As noted above, this PR starts with just the `cli/` module. The esbuild-based pipeline is also set up to first call the existing rollup-based build. It then deletes the `cli/` module built by rollup and replaces it with its own output. Esbuild has a few notable differences from rollup which are relevant here: - It can directly bundle and transform TypeScript, so we can go from TypeScript to bundled JS in one step (rather than with our Rollup pipeline, where we run `tsc` and then run Rollup on the JS emitted by `tsc`). This decreases a bit of build complexity because for instance esbuild can read the `paths` configuration in `tsconfig.json`, so we no longer need something analogous to our [alias plugin](https://github.com/ionic-team/stencil/blob/b97dadc967b1fde892cb75a544b1eecd2361b194/scripts/bundles/plugins/alias-plugin.ts) which normally brings those aliases into the Rollup build. - It's very fast! the `cli/` module builds in about 13ms. - It also strips documentation comments from the code, I think because it does an AST based transform and discards comments as part of parsing (or doesn't make an effort to keep them around). This results in smaller bundle sizes. It does have support for retaining [certain specially-formatted comments](https://esbuild.github.io/api/#legal-comments) which is a good thing because we use a few magic comments for Vite support. - OOB it supports pretty much all of what we're currently doing in our Rollup-based build pipeline, so we should be able to gradually port everything over. Once this is merged we can start using esbuild for local development and also start to port over other modules.
1aced01
to
9b3987e
Compare
This adds a support for building Stencil with esbuild. This comprises:
scripts/esbuild
which holds all the esbuild-related stuffcli/
bundle with esbuildpackage.json
scriptsbuild.esbuild
andbuild.esbuild.watch
for doing a "hybrid" buildRight now this new build / bundle setup exists parallel to the existing, rollup-based build setup. The idea is that we'll continue to use rollup for building and releasing, but we'll gradually increase the scope of the esbuild-based pipeline until it can build all of stencil. As noted above, this PR starts with just the
cli/
module.The esbuild-based pipeline is also set up to first call the existing rollup-based build. It then deletes the
cli/
module built by rollup and replaces it with its own output.Esbuild has a few notable differences from rollup which are relevant here:
tsc
and then run Rollup on the JS emitted bytsc
). This decreases a bit of build complexity because for instance esbuild can read thepaths
configuration intsconfig.json
, so we no longer need something analogous to our alias plugin which normally brings those aliases into the Rollup build.cli/
module builds in about 13ms.Once this is merged we can start using esbuild for local development and also start to port over other modules. I have a working build already for the
compiler/
directory, getting that set up for local development will really speed things up!Pull request checklist
Please check if your PR fulfills the following requirements:
npm run build
) was run locally and any changes were pushednpm test
) were run locally and passednpm run test.karma.prod
) were run locally and passednpm run prettier
) was run locally and passedPull request type
Please check the type of change your PR introduces:
What is the current behavior?
no esbuild, rollup slow
What is the new behavior?
yes esbuild, rollup still slow!
Does this introduce a breaking change?
Testing
I've built and packed this and then run it in several little example projects and in Framework with no problems.