Skip to content

Proposal: Integrated html vue type file

Glenn Ko edited this page Apr 28, 2017 · 50 revisions

Proposal: Integrated .html/.vue-type file for HaxeVx components' markup + CSS modules (with compile-time strict-typed checking).

<template>
 <div class="dot-big">
	<div @click="doClickMe()" :wonderful="123" class="${STYLE.abc} ${dddStyle.wonderFl} dot-big-pulse"></div>
	<div class="dot-big-shape"></div>
</div>
</template>

<style var="STYLE" ext="css">
.abc {
	color:#ff0000;
}
.wonder-fl {

}
.${CSTYLE.someProp} .${CSTYLE.col2} .my-module-cls {
	position:relative;
}
</style>

<css>
	<i file="filename/fawf.css" var="GLOBAL" />
	<i file="blahblah/awfaw/ffss.scss" var="CSTYLE"/>
	<i className="com.blahblah.some.StaticClass" var="dddStyle"/>
</css>

A file format spec specifically suited for editing (and compiling with relevant .hxml file), for frontend designers especially, since it only contains markup and CSS only.

<style> tag refers to the module style solely relevant to the component. For <style> tag, if var is left undefined, it's assumed to be STYLE by default (according to convention). Unlike regular Vue, HaxeVx assumes all <style> refers to the CSS module tied to the HaxeVx Vue component. To force-declare a global <style> in certain cases, there's a consideration to be able to use a global attribute like <style global>. However, it's better for global styles to be written elsewhere instead of the component file generally, or even better, set up a relevant global/shared style module accordingly so everything is name-spaced accordingly. (Note: Currently, I don't have any pipeline supporting global attribute for component styles, which is a bit of an oxymoron to me...).

When using other CSS modules within <style> via the ${} token, the compiler must check that a dot . must always precede the ${} token, unlike the token used in class attribute within the html template. This token (including the preceding .) will be string-replaced by the Haxe macro at compile-time with the respective module CSS classname, and wrapped as :global(.some-resolved-css-module-classname).

File extension attribute under <style ext="...> is css by convention (default), but may use scss or whatever accordingly, depending on situation. Of course, this is only meant for any integrated gulp processes that needs information on what CSS module-prefixed files to generate, and thus what file extension to use.


Format is similar to .vue spec (at a very basic level and is intended to be cross-compatible), but the <css> imports part is specifically HaxeVx-feature only, to support importing CSS module singleton-cached instances as component class's static var {{varName}} references accordingly, which you can use in your template.

And of course, the Haxe codebase is still in a seperate .hx file that coders will have to view split screen in their IDEs.

The .vue-like template is parsed as a form of HTML to XML conversion, than analysed accordingly to validate against the relevant HaxeVx component codebase in the .hx file, according to spec https://github.com/Glidias/haxevx/wiki/Proposal:-Lint-Vue-templates-and-check-bindings-against-Haxe-codebase , so you get full strict-typed compiling when doing development builds, and, depending on your IDE, quick jumping to compile-time error locations in the .vue file, useful for any developer/designer hopefully. So, no more typos or mismatched types with CSS modules and template code bindings.

By default, the build macro will use following file extension priority: .vue .html, if file extension is left undefined in build macro parameters.

Components specs proposal:

Some other considerations like <components> imports might be a good consideration to have, but currently this responsiblity is left soley to the .hx file instead as of now. I'd rather not mix-and-match both, so it's either one or the other, though having the option for the /vue file to exclusively declare your Components() (ie. Vue's components: in component definition) as of below, might be useful for often-used reusable components.

<components>
	<i className="some.thirdparty.ComponentName" name="my-cool-component" var="Comp_MyCoolComponent" />
</components>

name refers to the literal component tag name to use. var is optional, but if included, a static inline var reference will be created where you can use something like <${Comp_MyCoolComponent}> instead to avoid typos with component name literals. Of course, the danger is in declaring a variable that is already declared in the Haxe codebase (though the compiler will catch this), so you need to use some conventions on your own to ensure uniqueness of component var name references. If name is left undefined, a long name is used instead based on the className.

What about non-HaxeVx (ie.native VueJS) components? A specific attribute like require instead of className might need to be used for native JS module externs (ie. components that aren't HaxeVx-based) though. Would have to finalise such edge cases.

What about dynamically initialized HaxeVx components? Other considerations would be to support custom constructor/factory method/component factory parameters as well, and not mere singleton caches, since some Component specs may be dynamically initialised with different parameters per instance.

Drawbacks with combined .vue file

I've encountered various IDEs that don't provide full Intellisense within the <style> tags of .html/.vue files, unfortunately. Hopefully, this will change in the future. Also, you won't get Intellisense type completion with CSS modules unless you write the html part within the .hx files itself, and I don't see anyway of having CSS module intellisense completion within <style> tags as well.