In the above

Current version: 0.0.1-alpha.0

Project address document NPM

refactoring

Renderer

Because of the heavy coupling of the DOM API to runtime compilations in older versions, the same compilation logic had to be reimplemented when server-side renderings were written. I decided to strip out the DOM API and abstract out a generic compilation logic.

After much thought and reference to the methods of the three existing frameworks, we isolated the platform API by exposing a base class named Renderer to encapsulate some of the rendering methods. With the implemented virtual DOM, diff changes are made to the virtual DOM each time the runtime is compiled, and Renderer is finally rendered by implementing an instance of the Renderer.

export abstract class Renderer {
  public abstract nativeElementToVnode(nativeElement: any, parseVnodeOptions? : ParseOptions): Vnode[];public abstract getElementsByTagName(name: string) :any;
  public abstract hasChildNodes(nativeElement: any) :boolean;
  public abstract getChildNodes(nativeElement: any) :any[];
  public abstract removeChild(parent: any, child: any) :void;
  public abstract appendChild(parent: any, child: any) :void;
  public abstract insertBefore(parent: any, child: any, index: number) :void;
  public abstract isContainted(parent: any, child: any) :boolean;
  public abstract creatElement(tagName: string) :any;
  public abstract creatTextElement(value: string) :any;
  public abstract getAttribute(element: any, name: string) :any;
  public abstract setAttribute(element: any, name: string, value: any) :void;
  public abstract setNvAttribute(element: any, name: string, value: any) :void;
  public abstract removeAttribute(element: any, name: string, value? :any) :void;
  public abstract removeNvAttribute(element: any, name: string, value? :any) :void;
  public abstract setNodeValue(element: any, nodeValue: any) :void;
  public abstract setValue(element: any, value: any) :void;
  public abstract removeEventListener(element: any, eventType: string, handler: any) :void;
  public abstract addEventListener(element: any, eventType: string, handler: any) :void;
  public abstract setStyle(element: any, name: string, value: any) :void;
  public abstract removeStyle(element: any, name: string) :void;
  public abstract getStyle(element: any, name: string) :void;
}
Copy the code

Finally, cross-platform rendering can be achieved by implementing this class through a plugin for the platform. (Now only platform-browser is implemented.. Server in progress).

Virtual DOM

Because the template is a string template, the first version of the virtual DOM is actually made with innerHTML of the DOM. For cross-platform rendering, we use the regular matching template to find tags and attributes.

packages/core/vnode/parse.ts

const tagRegex: RegExp = / 
      ])+>/g;
Copy the code

packages/core/vnode/parse-tag.ts

const tagRegex: RegExp = / 
      ])+>/g;
Copy the code

Using these two re’s to match the tags and attributes of the corresponding template, you can get a DOM-like Vnode without applying innerHTML.

packages/core/vnode/vnode.ts

class Vnode {
  publictagName? :string;
  publicnativeElement? :any;
  publicparentVnode? : Vnode;publicattributes? : TAttributes[];publicnodeValue? :string | null;
  publicchildNodes? : Vnode[];public type? :string;
  publicvalue? :string | number;
  publicrepeatData? :any;
  publiceventTypes? : TEventType[] = [];publickey? :any;
  publicchecked? :boolean;
  publicvoidElement? :boolean = false;
  publictemplate? :string;
  publicindex? :number;
 }
Copy the code

Finally, in compile stage, the page structure can be updated by operating the Vnode to obtain the corresponding latest Vnode and patch the differences after diff.

See the virtual DOM and cross-platform rendering chapters for details.

In addition, incidentally, some of the previous problems with repeat instructions were fixed.

update

  • removestateProperty, you can now directly use all of the class’s member properties and member methods. Member properties that are parsed to and passed by the template before the Oninit life cycle@Watch()Annotated member attributes are added to the listener, and property changes are triggeredrender
  • removepropsProperties can now be passed directly through@Input(name? : string)Directly specify which property or method to map the component’s input to
  • inJavaScriptYou can use classes as tokens directly in static properties, in order to correspond to constructor arguments
  • The life cyclenvDoCheckInstead ofnvWatchStateTo delete parameters. (In fact, each change of state is known, so the last state is not significant)
  • The life cyclenvReceivePropsrenamednvReceiveInputs
  • Optimize rendering through events on proxy instructions. Render will not fire when the event is fired and will fire after the event handler finishesrenderwithwatcher. When there are multiple attribute changes in an event, merge the changes into a single change and push it to the render queue
  • @NvModuleLazy loading modules and root modules are now mandatorybootstrapmetadata
  • increaseElementRefandRenderer, can be directly injected in the component or instruction, respectively, to obtain the component or instruction mountednativeElementAnd global fumigation instances. Therefore, using the BROWSER API directly to manipulate the DOM is not recommended, but rather recommendedElementRefandRenderer

The last

emmmm…. At last I looked more and more like NG.

Compilation and rendering are all JIT based now, AOT and pipes will be supported in the future, so I set a flag here.