[AngularJS2]AngularJS2应用启动过程

来源:互联网 发布:网络功能虚拟化 编辑:程序博客网 时间:2024/05/21 21:47

当浏览器访问Angular应用时,首先index.html页面被加载。









然后,inline.bundle.js被浏览器加载执行。在inline.bundle.js中定义了函数webpackJsonp(...)__webpack_require__(...)
通过函数webpackJsonp(chunkIds, moreModules, executeModules)可以向应用添加代码块,参数chunkIds是代码块的ID, moreModules是代码块中包含的模块,而executeModules指定了需要执行的模块。webpackJsonp(...)调用__webpack_require__()执行executeModules指定的模块。

/******/ (function(modules) { // webpackBootstrap/******/     // install a JSONP callback for chunk loading/******/     var parentJsonpFunction = window["webpackJsonp"];/******/     window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {/******//******/         ... .../******//******/         if(executeModules) {/******/             for(i=0; i < executeModules.length; i++) {/******/                 result = __webpack_require__(__webpack_require__.s = executeModules[i]);/******/             }/******/         }/******/         return result;/******/     };/******//******/     ... .../******//******/     // The require function/******/     function __webpack_require__(moduleId) {/******//******/         ... .../******//******/         // Execute the module function/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******//******/         ... .../******//******/         // Return the exports of the module/******/         return module.exports;/******/     }/******//******/ })/******/ ([]);

当main.bundle.js被浏览器加载执行,函数webpackJsonp(["main"], ..., [0])会被调用执行。ID为“0”的模被块被执行,在执行中”../../../../../src/main.ts”模块也会被执行__webpack_require__("../../../../../src/main.ts")

这里就是angular应用入口点: platformBrowserDynamic().bootstrapModule(AppModule));

webpackJsonp(["main"],{"../../../../../src/main.ts":(function(module, __webpack_exports__, __webpack_require__) {"use strict";eval("Object.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\nvar __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(\"../../../core/esm5/core.js\");var __WEBPACK_IMPORTED_MODULE_1__angular_platform_browser_dynamic__ =     __webpack_require__(\"../../../platform-browser-dynamic/esm5/platform-browser-dynamic.js\");var __WEBPACK_IMPORTED_MODULE_2__app_app_module__ = __webpack_require__(\"../../../../../src/app/app.module.ts\");Object(__WEBPACK_IMPORTED_MODULE_1__angular_platform_browser_dynamic__[\"a\" /* platformBrowserDynamic */])()    .bootstrapModule(__WEBPACK_IMPORTED_MODULE_2__app_app_module__[\"a\" /* AppModule */])); /***/ 0:/***/ (function(module, exports, __webpack_require__) {__webpack_require__("../../../../webpack-dev-server/client/index.js?http://0.0.0.0:0");module.exports = __webpack_require__("../../../../../src/main.ts");/***/ })},[0]);

platformBrowserDynamic的定义可以在angular源代码packages\platform-browser-dynamic\src\platform-browser-dynamic.ts中找到。

export const platformBrowserDynamic = createPlatformFactory    ( platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);

createPlatformFactory()创建并返回对应的PlatformRef对象,PlatformRef是应用程序运行的环境。在packages\core\src\core\application_ref.ts中我们可以找到PlatformRef的定义。

export class PlatformRef {  private _modules: NgModuleRef<any>[] = [];  private _destroyListeners: Function[] = [];  private _destroyed: boolean = false;  bootstrapModule<M>(      moduleType: Type<M>, compilerOptions: (CompilerOptions&BootstrapOptions)|      Array<CompilerOptions&BootstrapOptions> = []): Promise<NgModuleRef<M>> {    const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);    const options = optionsReducer({}, compilerOptions);    const compiler = compilerFactory.createCompiler([options]);    return compiler.compileModuleAsync(moduleType)        .then((moduleFactory) => this.bootstrapModuleFactory(moduleFactory, options));  }}

在BootstrapModule()中,首先是模块被编译, 然后调用BootstrapModuleFactory()_moduleDoBootstrap()。在_moduleDoBootstrap()中,我们可以看到对象ApplicationRefbootstrap()方法被调用,参数是模块的每一Component。

const appRef = moduleRef.injector.get(ApplicationRef) as ApplicationRef;if (moduleRef._bootstrapComponents.length > 0) {  moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));

ApplicationRef.bootstrap(componentOrFactory: ComponentFactory<C>|Type<C>, rootSelectorOrNode?: string|any)的实现:

const selectorOrNode = rootSelectorOrNode || componentFactory.selector;const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);compRef.onDestroy(() => { this._unloadComponent(compRef); });const testability = compRef.injector.get(Testability, null);if (testability) {  compRef.injector.get(TestabilityRegistry)      .registerApplication(compRef.location.nativeElement, testability);}this._loadComponent(compRef);

在这个函数里,componentFactoryComponentFactory_对象的一个实例。componentFactory.create()的定义可以在packages\core\source\view\ref.ts中找到。

   class ComponentFactory_ extends ComponentFactory<any>       /**   * Creates a new component.   */  create(      injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,      ngModule?: NgModuleRef<any>): ComponentRef<any> {    if (!ngModule) {      throw new Error('ngModule should be provided');    }    const viewDef = resolveDefinition(this.viewDefFactory);    const componentNodeIndex = viewDef.nodes[0].element !.componentProvider !.nodeIndex;    const view = Services.createRootView(        injector, projectableNodes || [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT);    const component = asProviderData(view, componentNodeIndex).instance;    if (rootSelectorOrNode) {      view.renderer.setAttribute(asElementData(view, 0).renderElement, 'ng-version', VERSION.full);    }    return new ComponentRef_(view, new ViewRef_(view), component);  }}

core\src\view\view.ts: function createRootView()->core\src\view\services.ts: function createProdRootView()->function createRootData()/function createRootView()

export function createRootView(root: RootData, def: ViewDefinition, context?: any): ViewData {  const view = createView(root, root.renderer, null, null, def);  initView(view, context, context);  createViewNodes(view);  return view;}

createViewNode()会遍历view.def.nodes。如果node的类型是NodeFlags.TypeElement,createElement()会被调用在DOM树上创建节点,如果这个节点还是一个component, componentView也会被创建。
最后,调用execComponentViewsAction(view, ViewAction.CreateViewNodes),如果子节点是componentView, 递归的调用callViewAction()-> createViewNodes()来创建子节点,直到没有子节点是component.

function createViewNodes(view: ViewData) {  let renderHost: any;  if (isComponentView(view)) {    const hostDef = view.parentNodeDef;    renderHost = asElementData(view.parent !, hostDef !.parent !.nodeIndex).renderElement;  }  const def = view.def;  const nodes = view.nodes;  for (let i = 0; i < def.nodes.length; i++) {    const nodeDef = def.nodes[i];    Services.setCurrentNode(view, i);    let nodeData: any;    switch (nodeDef.flags & NodeFlags.Types) {      case NodeFlags.TypeElement:        const el = createElement(view, renderHost, nodeDef) as any;        let componentView: ViewData = undefined !;        if (nodeDef.flags & NodeFlags.ComponentView) {          const compViewDef = resolveDefinition(nodeDef.element !.componentView !);          componentView = Services.createComponentView(view, nodeDef, compViewDef, el);        }        listenToElementOutputs(view, componentView, nodeDef, el);        nodeData = <ElementData>{          renderElement: el,          componentView,          viewContainer: null,          template: nodeDef.element !.template ? createTemplateData(view, nodeDef) : undefined        };        if (nodeDef.flags & NodeFlags.EmbeddedViews) {          nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData);        }    nodes[i] = nodeData;  }  // Create the ViewData.nodes of component views after we created everything else,  // so that e.g. ng-content works  execComponentViewsAction(view, ViewAction.CreateViewNodes);export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {  const elDef = def.element !;  const rootSelectorOrNode = view.root.selectorOrNode;  const renderer = view.renderer;  let el: any;  if (view.parent || !rootSelectorOrNode) {    if (elDef.name) {      el = renderer.createElement(elDef.name, elDef.ns);    } else {      el = renderer.createComment('');    }    const parentEl = getParentRenderElement(view, renderHost, def);    if (parentEl) {      renderer.appendChild(parentEl, el);    }  } else {    el = renderer.selectRootElement(rootSelectorOrNode);  }  if (elDef.attrs) {    for (let i = 0; i < elDef.attrs.length; i++) {      const [ns, name, value] = elDef.attrs[i];      renderer.setAttribute(el, name, value, ns);    }  }  return el;}export function createComponentView(    parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {  const rendererType = nodeDef.element !.componentRendererType;  let compRenderer: Renderer2;  if (!rendererType) {    compRenderer = parentView.root.renderer;  } else {    compRenderer = parentView.root.rendererFactory.createRenderer(hostElement, rendererType);  }  return createView(      parentView.root, compRenderer, parentView, nodeDef.element !.componentProvider, viewDef);}