UNPKG

aurelia-bootstrapper

Version:

Sets up the default configuration for the aurelia framework and gets you up and running quick and easy.

218 lines (185 loc) 8.55 kB
import 'aurelia-polyfills'; import { Aurelia, Loader } from 'aurelia-framework'; import { isInitialized, PLATFORM } from 'aurelia-pal'; type RuntimeProcess = typeof process & { browser: any; type: string; }; type AureliaFactoryFn = () => Aurelia; let bootstrapPromises = []; let startResolve: (value: AureliaFactoryFn | Promise<AureliaFactoryFn>) => void; const startPromise = new Promise<AureliaFactoryFn>(resolve => startResolve = resolve); const host = PLATFORM.global; const isNodeLike = typeof process !== 'undefined' && !(process as RuntimeProcess).browser && (process as RuntimeProcess).version; function ready() { if (!host.document || host.document.readyState === 'complete') { return Promise.resolve(); } return new Promise<void>(resolve => { host.document.addEventListener('DOMContentLoaded', completed); host.addEventListener('load', completed); function completed() { host.document.removeEventListener('DOMContentLoaded', completed); host.removeEventListener('load', completed); resolve(); } }); } function createLoader() { // Note: Please do NOT add any PLATFORM.moduleName annotation in this method, // for example around 'aurelia-loader-default'. // Each import has been carefully written so that it is picked up by // its respective bundler and is ignored by others. // Adding moduleName() would add a static dependency, which we don't // want as the correct loader is determined at build time. // Custom Loader Support if (PLATFORM.Loader) { return Promise.resolve(new PLATFORM.Loader()); } if (typeof AURELIA_WEBPACK_2_0 === 'undefined') { // Webpack Loader Support if (typeof __webpack_require__ !== 'undefined') { // Webpack needs the require to be top level to parse the request. // However, we don't want to use require or that will cause the Babel // transpiler to detect an incorrect dependency. const m = __webpack_require__(require.resolve('aurelia-loader-webpack')); return Promise.resolve(new m.WebpackLoader()); } // SystemJS Loader Support if (host.System && typeof host.System.config === 'function') { return host.System.normalize('aurelia-bootstrapper').then(bsn => { return host.System.normalize('aurelia-loader-default', bsn); }).then(loaderName => { return host.System.import(loaderName).then(m => new m.DefaultLoader()); }); } // AMD Module Loader Support if (typeof host.require === 'function' && typeof host.define === 'function' && typeof host.define.amd === 'object') { return new Promise((resolve, reject) => host.require(['aurelia-loader-default'], m => resolve(new m.DefaultLoader()), reject)); } // Node.js and Electron Support if (isNodeLike && typeof module !== 'undefined' && typeof module.require !== 'undefined') { // note: we use a scoped module.require() instead of simply require() // so that Webpack's parser does not automatically include this loader as a dependency, // similarly to the non-global call to System.import() above const m = module.require('aurelia-loader-nodejs'); return Promise.resolve(new m.NodeJsLoader()); } } // endif AURELIA_WEBPACK_2_0 return Promise.reject('No PLATFORM.Loader is defined and there is neither a System API (ES6) or a Require API (AMD) globally available to load your app.'); } function initializePal(loader: Loader) { if (isInitialized) return Promise.resolve(); let type; const isRenderer = isNodeLike && ((process as RuntimeProcess).type === 'renderer' || process.versions['node-webkit']); if (isNodeLike && !isRenderer) { type = 'nodejs'; } else if (typeof window !== 'undefined') { type = 'browser'; } else if (typeof self !== 'undefined') { type = 'worker'; } else { throw new Error('Could not determine platform implementation to load.'); } // Note: Please do NOT try to add PLATFORM.moduleName() annotations here. // This would create a static dependency between bootstrapper and a PAL, which we don't want. // The correct PAL to bundle must be determined by the bundling tool at build time. return loader.loadModule('aurelia-pal-' + type) .then(palModule => type === 'nodejs' && !isInitialized && palModule.globalize() || palModule.initialize()); } function preparePlatform(loader: Loader) { const map = (moduleId, relativeTo) => loader.normalize(moduleId, relativeTo) .then(normalized => { loader.map(moduleId, normalized); return normalized; }); return initializePal(loader) .then(() => loader.normalize('aurelia-bootstrapper')) .then(bootstrapperName => { // aurelia-framework re-exports pretty much everything. // As can be seen at the end of this method, the only field accessed by bootstrapper is `Aurelia`, // so we document that to enable tree shaking on all other exported members. const frameworkPromise = map(PLATFORM.moduleName('aurelia-framework', { exports: ['Aurelia'] }), bootstrapperName); // Please do NOT add PLATFORM.moduleName() around any of those modules. // They are not actually loaded here, only mapped. return Promise.all([ frameworkPromise, frameworkPromise.then(frameworkName => map('aurelia-dependency-injection', frameworkName)), map('aurelia-router', bootstrapperName), map('aurelia-logging-console', bootstrapperName) ]); }) .then(([frameworkName]) => loader.loadModule(frameworkName)) .then((fx: typeof import('aurelia-framework')) => startResolve(() => new fx.Aurelia(loader))); } function config(appHost: Element, configModuleId: string, aurelia: Aurelia): Promise<Aurelia> { aurelia.host = appHost; aurelia.configModuleId = configModuleId || null; if (configModuleId) { return aurelia.loader .loadModule(configModuleId) .then(customConfig => { if (!customConfig.configure) { throw new Error(`Cannot initialize module '${configModuleId}' without a configure function.`); } return customConfig.configure(aurelia); }); } aurelia.use .standardConfiguration() .developmentLogging(); return aurelia.start().then(() => aurelia.setRoot()); } function run() { return ready() .then(createLoader) .then(preparePlatform) .then(() => { const appHosts = host.document.querySelectorAll('[aurelia-app],[data-aurelia-app]'); for (let i = 0, ii = appHosts.length; i < ii; ++i) { const appHost = appHosts[i]; const mainModuleId = appHost.getAttribute('aurelia-app') || appHost.getAttribute('data-aurelia-app'); bootstrap(config.bind(null, appHost, mainModuleId)); } // This can't be moved before preparePlatform. // In old IE the console object only exists after F12 tools have been opened and PAL creates a substitute. const toConsole = console.error.bind(console); const bootstraps = bootstrapPromises.map(p => p.catch(toConsole)); bootstrapPromises = null; return Promise.all(bootstraps); }); } /** * Manually bootstraps an application. * @param configure A callback which passes an Aurelia instance to the developer to manually configure and start up the app. * @return A Promise that completes when configuration is done. */ export function bootstrap(configure: (aurelia: Aurelia) => any): Promise<void>; export function bootstrap(configure: Function): Promise<void>; export function bootstrap(configure: Function): Promise<void> { const p = startPromise.then(factory => configure(factory())); if (bootstrapPromises) bootstrapPromises.push(p); return p; } /** * A promise that represents the bootstrapper's startup process. * It resolves when the process has finished starting. */ export const starting = run(); /** @internal */ declare global { const AURELIA_WEBPACK_2_0: any; const __webpack_require__: Function; } /** @internal */ declare module 'aurelia-framework' { interface Aurelia { configModuleId: string; } } /** @internal */ declare module 'aurelia-loader' { interface Loader { // overload normalize(moduleId: string): Promise<string>; } }