如何让Ember.js在渲染index路由前预加载全部路由及相关资源?
Hey there! I totally get where you're coming from—nothing kills that snappy app feel like waiting around for routes to load when you navigate, especially when you're just getting your feet wet with Ember. Let's walk through how you can preload all your app's routes, nested routes, templates, and components upfront, so you can ditch those laggy route transitions.
Key Approaches to Preload Everything
1. Preload Routes via the Application Route's beforeModel Hook
The application route is the perfect place to kick off preloading since it runs before any other route loads. You can use it to fetch all your app's route names and load their modules upfront. Here's how to do it:
// app/routes/application.js import Route from '@ember/routing/route'; import { all } from 'rsvp'; import { getOwner } from '@ember/application'; export default class ApplicationRoute extends Route { async beforeModel() { // Run the default application route setup first await super.beforeModel(...arguments); // Grab all registered route names from Ember's router const routeNames = Object.keys(this.router.recognizer.names); // Preload each route module by looking it up via the app's owner const preloadPromises = routeNames.map(routeName => { const owner = getOwner(this); // Looking up the route triggers Ember to load its module and dependencies return owner.lookup(`route:${routeName}`); }); // Wait for all routes to finish loading await all(preloadPromises); // Optional: Preload components too // If you know all your component names, you can preload them the same way: // const componentNames = ['your-component', 'nested/child-component']; // const componentPromises = componentNames.map(name => owner.lookup(`component:${name}`)); // await all(componentPromises); } }
This will load every route (and their associated templates) before your app renders the index route. For components, you'll need to list them explicitly (or generate a list from your app's metadata if you have many) since Ember doesn't expose a built-in way to fetch all component names.
2. Disable Code Splitting with Embroider (For Ember 3.28+)
If you're using Embroider (the default build tool for modern Ember apps), it splits your app into smaller chunks that load lazily by default. To bundle all routes and components into the main initial chunk, adjust your ember-cli-build.js configuration:
// ember-cli-build.js 'use strict'; const EmberApp = require('ember-cli/lib/broccoli/ember-app'); const { Webpack } = require('@embroider/webpack'); module.exports = function(defaults) { let app = new EmberApp(defaults, { // Your existing app config }); return require('@embroider/compat').compatBuild(app, Webpack, { splitChunks: { chunks: 'all', cacheGroups: { // Disable default vendor and shared chunking default: false, vendors: false, // Bundle all app code into a single "app" chunk app: { name: 'app', test: /[\\/]app[\\/]/, chunks: 'all', enforce: true, }, }, }, }); };
This tells Webpack to package all your app's code into one main bundle, so everything loads on initial page load—no more lazy loading delays when switching routes.
3. Optimize the Loading Experience
To make sure users see a loading state while all resources are preloading, you can use Ember's built-in loading route. Create a app/templates/loading.hbs file with your loading UI (spinner, progress bar, etc.), and Ember will automatically show this template while the application route's beforeModel hook is running. Once preloading is done, it'll transition smoothly to your index route.
Important Trade-off to Consider
Preloading everything will make your initial page load take longer (since you're downloading all app code upfront) but eliminates route transition delays entirely. This is a great fit for small-to-medium apps like yours, but for larger apps, you might want to balance preloading critical routes with lazy loading less-used ones.
内容的提问来源于stack exchange,提问作者Benisburgers

