One goal of the Ember Initiative is to bring a modern toolchain based on Vite to Ember. This increases compatibility with the wider JavaScript ecosystem and brings potential for faster builds, rebuilds, route splitting, and more.
To get numbers on how Vite can improve the build pipeline of real-world production applications, we need your feedback. Using the open source tool we've built to measure the differences in build and pageload times, you can share your benchmarks with us so we can continue making Ember better and faster for everyone.
anchorHow the classic build system differs from Vite
The classic build setup uses ember-cli, which builds your app using an underlying technology called broccoli, although some adventurous Ember developers might have been using webpack through embroider. In both cases, everything is compiled up front, and the app is loaded as a few bundled AMD-based entry files or chunks, even when the app runs in development mode. Roughly speaking, the initial build is slow, then makes up for some of that time during the page load by bundling everything up into a minimal number of files.
Vite follows a very different philosophy when it comes to dev builds: it has multiple stages to optimise the input and sends real JavaScript modules and entry points to the client. This means that for every module in your app (and every entry-point in your dependencies), you will see a new network request for that individual module in the browser. With large apps, you could start the dev server blazingly fast, only to have a perceived slowdown as the browser loads large numbers of tiny files, which in turn are much faster to reload for small changes.
anchorBuild, Measure, Optimise, Repeat
Moving to Vite has many more benefits than just raw speed, but speed is always an important factor of development, and it is worth spending some time investigating the impact of migrating a classic Ember app to build with Vite.
We need to learn how well Vite does in on your applications, big and small. We are looking for the following metrics, both from a cold start and a warm start after caches have been created:
- Production build time after installing the packages
- Development server startup time
- Development time to first paint
- Development time to app load, waiting for an element rendered by your app
- Development reload time after a file in your app changes
We built build-start-rebuild-perf to take care of the development measurements. See its README or --help output for supported parameters.
anchorTest protocol
As projects have their individual choices, we decided to not fully automate the workflow. This post assumes a "normal" Ember project as generated by running ember new.
Expectations:
- You run macOS or Linux (or are willing to go on your own adventures on Windows)
- You have a
mainbranch (or a last commit "C") of your app that builds and runs usingember-cli - You have a
migrate-to-vitebranch (or a first commit "C+1") that builds and runs using the new Embroider and Vite - Both branches use the same version of Node and the package manager of your choice, i.e. pnpm
- Your app has a
<img class="logo">that is part of your components and not inside yourindex.html - Your app has an
app/router.jswhich, when changed, triggersember-cliorviteto rebuild
Let's get started! Open up the survey form, which will give you the same prompts as below and input fields to put the results. Don't rush this.
anchor1 - Ember CLI Production Build Time
Let's start by switching to your main branch and cleaning your built assets and caches:
# Start from main
git switch main
# Make sure you clear out artefacts
rm -rf dist
# Clear out ALL build caches
rm -rf $TMPDIR/embroider $TMPDIR/broccoli-*(N) node_modules/.embroiderNow, let's get the first build measurement. You will run your ember-cli build with time to measure things. The following example assumes your package.json script build command runs ember build --env=production. The output will print extra lines at the end, containing the execution time measurement. We are looking for the real or total or Executed in number, i.e. real 0m4.139s:
# 1 - Ember CLI Production Build Time
# -----------------------------------
time npm run buildanchor2 - Ember CLI Cold Start
Next, we will measure the "cold start" of your dev build. This means how long it takes to start the build and see your app running in the browser, assuming you're starting without any build caches. Let's start by removing ./dist again and clearing our cache:
# Make sure you clear out artefacts
rm -rf dist
# Clear out ALL build caches
rm -rf $TMPDIR/embroider $TMPDIR/broccoli-*(N) node_modules/.embroiderThen we're going to execute the build-start-rebuild-perf command to measure the important aspects of your dev server build time. Note this assumes that the development server launches at //localhost:4200:
# 2 - Ember CLI Cold Start
# ------------------------
# 2.1 Dev Server Ready
# 2.2 Development time to first paint
# 2.3 First Paint
# 2.4 Development reload time
npx build-start-rebuild-perf --file "app/router.js" --wait-for ".logo" --command "npm start"anchor3 - Ember CLI Warm Start
Next, we do the same command, but we don't clear the caches first this time.
# 3 - Ember CLI Warm Start
# ------------------------
# 3.1 Dev Server Ready
# 3.2 Development time to first paint
# 3.3 First Paint
# 3.4 Development reload time
npx build-start-rebuild -perf --file "app/router.js" --wait-for ".logo" --command "npm start"And that's it for the classic build; it's time for us to switch over to your Vite branch.
By the way, you made it to the halfway point of this process 🎉 Let's keep going.
anchor4 - Vite Production Build
First, we will switch to our Vite branch and clear out any caches you had from previous Vite builds:
git switch migrate-to-vite
# Remove any build caches
rm -rf node_modules/.vite node_modules/.embroiderNext, we will again time the production build time using the time command. This assumes that your package.json build script has been updated to run vite build:
# 4 - Vite Production Build
# -------------------------
time npm run buildanchor5 - Vite Cold Start
Just to make sure that the Vite production build didn't create any build caches, we should clear them out again:
# Remove any build caches
rm -rf node_modules/.vite node_modules/.embroiderAnd then we run the same command that we did in #2 above and report the same numbers, but this time with Vite:
# 5 - Vite Cold Start
# -------------------
# 5.1 Dev Server Ready
# 5.2 Development time to first paint
# 5.3 First Paint
# 5.4 Development reload time
npx build-start-rebuild-perf --file "app/router.js" --wait-for ".logo" --command "npm start"And just like we did before, to get the warm start numbers, we run the same command without first clearing any caches:
# 6 - Vite Warm Start
# -------------------
# 6.1 Dev Server Ready
# 6.2 Development time to first paint
# 6.3 First Paint
# 6.4 Development reload time
npx build-start-rebuild-perf --file "app/router.js" --wait-for ".logo" --command "npm start"anchorSubmit your numbers
You made it all the way to the end 🎉 Assuming you have been filling in the form as you went along, it's now time to hit that submit button. Otherwise, here is the link again if you want to fill in all the numbers you have collected.
anchorConclusion
If you made it through this blog and submitted the form, thank you very much. We appreciate the time you spent, and you have contributed to the Ember Initiative's efforts to make Ember better for everyone.
We are still looking for more Ember Initiative members if you want to contribute more directly. You can read more about the benefits of joining the Ember Initiative a member on our dedicated Ember Initiative page.
