@@ -31,14 +31,17 @@ module.exports = function (source, map) {
3131 finalDescriptor . script . content = finalDescriptor . script . content . replace ( / ^ ( \/ \/ \n ) + / , '' )
3232 }
3333
34- // Change all extension points to <template> on the final resolved component to display fallback content
34+ // Change all extension points to <template> on the final component to display fallback content
3535 if ( finalDescriptor . template . attrs [ options . EXTENDABLE_ATTR ] ) {
3636 let finalDom = htmlparser . parseDOM ( finalDescriptor . template . content ) ;
3737 findDomElementsByTagName ( finalDom , options . EXT_POINT_TAG ) . forEach ( ext => {
3838 ext . name = 'template' ;
3939 delete ext . attribs [ options . EXT_POINT_NAME_ATTR ]
4040 } ) ;
41- finalComponent = `<template>${ htmlparser . DomUtils . getOuterHTML ( finalDom ) } </template> ${ descriptorToHTML ( finalDescriptor ) } ` ;
41+ finalComponent = `<template>
42+ ${ htmlparser . DomUtils . getOuterHTML ( finalDom ) }
43+ </template>
44+ ${ descriptorToHTML ( finalDescriptor ) } ` ;
4245 }
4346
4447 callback ( null ,
@@ -53,32 +56,52 @@ function resolveComponent(currentSource, context) {
5356 return new Promise ( ( resolve , reject ) => {
5457 try {
5558 let currentDesc = toDescriptor ( currentSource ) ;
59+
60+ // If the component extends another, resolve its source merging it with the base component
61+ // else return code as is
5662 if ( currentDesc . template . attrs [ options . EXTENDS_ATTR ] ) {
57- let baseAbsolutePath = path . join ( context . context , currentDesc . template . attrs [ options . EXTENDS_ATTR ] ) ;
63+ let baseRelPath = currentDesc . template . attrs [ options . EXTENDS_ATTR ] ;
64+ let baseAbsPath = path . join ( context . context , baseRelPath ) ;
65+
66+ // To make HMR aware of the base file and reload it when it changes
67+ context . addDependency ( baseAbsPath ) ;
5868
59- context . addDependency ( baseAbsolutePath ) ;
69+ fs . readFile ( baseAbsPath , 'utf8' , ( err , contents ) => {
70+ // File read error, reject
71+ if ( err ) reject ( err ) ;
6072
61- fs . readFile ( baseAbsolutePath , 'utf8' , ( err , contents ) => {
73+ // Resolve the base component recursively to support inheritance in N levels
6274 resolveComponent ( contents , context ) . then ( ( resolvedComponent ) => {
6375 try {
6476 let baseDescriptor = toDescriptor ( resolvedComponent ) ;
65- let baseDom = htmlparser . parseDOM ( baseDescriptor . template . content ) ;
6677
78+ let baseDom = htmlparser . parseDOM ( baseDescriptor . template . content ) ;
6779 let currentDom = htmlparser . parseDOM ( currentDesc . template . content ) ;
80+
81+ // Get all the child's component extensions
6882 let extensions = currentDom . find ( node => node . type = 'tag' && node . name === options . EXTENSIONS_TAG ) . children
6983 . filter ( node => node . type = 'tag' && node . name === options . EXTENSION_TAG ) ;
84+
85+ // Replace each of the Base component's extension points with the child's extensions
7086 findDomElementsByTagName ( baseDom , options . EXT_POINT_TAG ) . forEach ( extPoint => {
71- let extendingBlock = extensions . find ( node => node . attribs [ options . EXT_POINT_REF_ATTR ] === extPoint . attribs [ options . EXT_POINT_NAME_ATTR ] ) ;
87+ // Find the extend block for the current extension point
88+ let extendBlock = extensions . find ( node => node . attribs [ options . EXT_POINT_REF_ATTR ] === extPoint . attribs [ options . EXT_POINT_NAME_ATTR ] ) ;
7289
73- if ( extendingBlock ) {
74- extPoint . children = extendingBlock . children ;
90+ // If a extend block matching the extension point was found, replace the point's content with the extend block's
91+ if ( extendBlock ) {
92+ extPoint . children = extendBlock . children ;
7593 }
7694
77- // Change extension point tag to a template
95+ // Change extension point tag to a template tag
7896 extPoint . name = 'template' ;
7997 delete extPoint . attribs [ options . EXT_POINT_NAME_ATTR ] ;
8098 } ) ;
81- resolve ( `<template ${ options . EXTENDABLE_ATTR } >${ htmlparser . DomUtils . getOuterHTML ( baseDom ) } </template> ${ descriptorToHTML ( currentDesc ) } ` ) ;
99+
100+ // Resolve promise with the new generated SFC
101+ resolve ( `<template ${ options . EXTENDABLE_ATTR } >
102+ ${ htmlparser . DomUtils . getOuterHTML ( baseDom ) }
103+ </template>
104+ ${ descriptorToHTML ( currentDesc ) } ` ) ;
82105 } catch ( e ) {
83106 reject ( e )
84107 }
@@ -95,6 +118,10 @@ function resolveComponent(currentSource, context) {
95118 } )
96119}
97120
121+ /**
122+ * Returns the SFC descriptor for a given SFC sourcecode
123+ * @param source
124+ */
98125function toDescriptor ( source ) {
99126 return parse ( {
100127 source : source ,
@@ -107,6 +134,11 @@ function findDomElementsByTagName(dom, tag) {
107134 return htmlparser . DomUtils . findAll ( node => ( node . type === 'tag' && node . name === tag ) , dom )
108135}
109136
137+ /**
138+ * Given a SFC's descriptor, returns the SFC's source **without** the template part
139+ * @param descriptor - SFC descriptor
140+ * @returns {string } - SFC source code
141+ */
110142function descriptorToHTML ( descriptor ) {
111143 return descriptor . customBlocks
112144 . filter ( cb => cb . type !== options . EXTENSION_TAG )
0 commit comments