I've been reviewing Aurelia and Vue for use in the next 2+ years (my timeline) and I really like how in Vuejs it is possible to merge style, template and JS into a .vue file with a webpack or browserify way to extract it out. Is this paradigm possible with Aurelia because I think that it is a huge innovation. I don't like JSX and I'd like to keep the various fragments in their own section.
see vue-loader
You want all the source in the same file for development? Or you want all html/js/css in the same bundle for deployment?
[edit] First save attempt failed because I used a raw <script> in the message.
Yes all of the source in the same file for development. I know that Aurelia already has the JSPM and (soon-to-be) Webpack bundling. I recently watched this Vue Laracast on a hangover day and I really liked it (Vue not hangover). Of course Aurelia is younger and isn't out of beta yet so there isn't that full ecosystem yet and that kind of thing really helps to get it into people's hands.
So say that you have the Aurelia equivalent of a component. It would be great to optionally divide it into <script>, <template> and <style> within a single file. From bundling / build perspective each import (in any dialect) starting with ./ would just referencing the current directory in the same way and it gets put through the appropriate loader for that type. So its basically like having anonymous files in a directory all smooshed together.
In my current Ampersand.js project I'm porting over the old Backbone code base and renaming old CSS names to BEM naming, jquery HTML mush to proper templates. I have too many stupid small files open and I realized that most of them are not that big and it would be great to be able to put them all together like Vue does.
So why couldn't Aurelia do that?
It seems to fit the HTML5 and ES6 kind of way in that you would have a <script> tag that just exports a proper ES6 class, style in whatever language that you want, template in whatever language you want (through lang="whatever").
Personally, I don't think it's a good idea to put it all in the same file, but you can do it today like this:
import {inlineView} from 'aurelia-templating';
@inlineView(`
<div>${message}</div>
`)
export class MyComponent {
constructor() {
this.message = 'Hello World';
}
}
You could create a custom element to add/remove styles.
I bring you the future:
Presenting:
MyComponent.aurelia:
<style>
@import "theme/vars";
.my-component {
background-color: var(--color-yellow);
}
</style>
<template>
<div class="my-component">${message}</div>
</template>
<script>
export class MyComponent {
constructor() {
this.message = 'Hello World';
}
}
</script>
Alternatively:
<!-- no style -->
<template>
<div class="my-component">${message}</div>
</template>
<script>
// attach style here
import './style'
export class MyComponent {
constructor() {
this.message = 'Hello World';
}
}
</script>
or:
<script>
@inlineView(`
<div>${message}</div>
`)
export class MyComponent {
constructor() {
this.message = 'Hello World';
}
}
</script>
Or load a normal .js file. Set the webpack loader to look for .aurelia before .js or .css.
Also github seems to automatically know how to highlight this .aurelia file ;).
You could certainly write a build task to parse a file like that, tear it apart and turn it into the individual modules, with proper hookups if you want.
I think that browserify and webpack are the only two suitable tools for this. I see a tool to break it all apart as more like a migration away from Aurelia tool (if anyone every wanted to do that someday). Again, its above my skills so all that I can do is be a wise-guy.
+1 Polymer also uses this single-file per component approach
<dom-module id="contact-card">
<style>...</style>
<template>
<content></content>
<iron-icon icon="star" hidden$="{{!starred}}"></iron-icon>
</template>
<script>
Polymer({
is: 'contact-card',
properties: {
starred: Boolean
}
});
</script>
</dom-module>
I could have sworn I saw a blog post somewhere saying this would be possible in Aurelia at some point, but I can't find it now :(
I might be willing to contribute something to help with this but I'm not sure where to start. I assume there'd be some way in Aurelia to hook into the loading process rather than trying to use a build engine like gulp to split the file out.
You can put the html and js in one file if you really want to by using @inlineView(). We just don't recommend that since it mixes concerns together and can effect work parallelization, source control systems and effective use of various code editors.
You make a good point, but I guess the only issue I have with the inlineView is that I'm not sure all text editors would understand it contains an html string. With the Polymer approach, the file is essentially a somewhat-valid HTML file with just [style], [script], and [template] tags which means any html editor should be able to make sense of it. Certainly not a show-stopper, but seems like something that could be done.
Riot.js which I've played with a bit also uses this single-file approach:
<todo>
<!-- layout -->
<h3>{ opts.title }</h3>
<ul>
<li each={ item, i in items }>{ item }</li>
</ul>
<form onsubmit={ add }>
<input>
<button>Add #{ items.length + 1 }</button>
</form>
<!-- style -->
<style scoped>
h3 {
font-size: 14px;
}
</style>
<!-- logic -->
<script>
this.items = []
add(e) {
var input = e.target[0]
this.items.push(input.value)
input.value = ''
}
</script>
</todo>
@EisenbergEffect This is closed, but I would like to say that use @inlineView is not a good answer.
The idea a good, and is a minus for aurelia the limitation of js first components with the html in a string.
In some components html can represent the biggest part of the code, with just a few things in Js (thank you data-binding), jsx is ugly and not better than a script tag.
Use something like a task or loader to pre-"compile" in 2 files html and js, or a js with a @inlineView(htmlFileContent) decorator is not so hard, but should not be this supported an aurelia feature, like an out of the box viewStategy !!???
Not sure how aurelia components works at run-time, But could it work in s HTML file with script tag that could get a sibling template tag.
<require from="htmlwithscripttag.hyml">
htmlwithscripttag.html
<template>
view
</template>
<script has-view-model?>
// omitted in convenction
@useSiblingAsView?
class viewmodel {
}
</script>
Can someone please explain to me why single file components are such a big deal? We already have HTML only custom elements, are working on HTML only pages. For any reasonably complex component, I just don't see the point of shoehorning everything in to a single file. What's so bad about cleanly separating the view from the view-model? Honestly, to me it just seems like an "All the cool kids are doing it" type of argument.
I've been building front-end software for a dozen years now and can't recall a single time thinking "You know what would make this 200 line HTML file better? Including another 200 lines of JS in it."
I think the single-file thing for me is that it just goes so well with thinking about things as components. Having the entire component self-contained in a single file just feels right to me. I certainly understand the other side of the argument but just wish we had the choice with Aurelia. Maybe I'll get around to adding it myself at some point :smile:
Yeah, but what is so much different about thinking about the component as contained in a pair (or trio) of files? I'm really trying to understand why there is such a push for this, when, to my eye, it just seems like people asking us to let them use their scroll wheel (or scrolling gesture on their touchpad) more.
I just thought this:
When the file is longer there is more incentive to create smaller components..
I know, weak.. Don't take it too seriously. 馃槀
I just caught myself thinking that these vue files containing everything are pretty cool and I was asking myself why I thought so. Honestly, no idea.
I know I'm coming off as rather grumpy right now, but it's probably because I'm grumpy today. :-)
I don't see the point to have html, css and js all in one file.
Having 3 files : 1 for template (html), 1 for css (design) and 1 for code (js) keeps separation of concerns more explicit. And I can send the html and css to my designer without the code so he can work his voodoo designer skills.
as @Thanood pointed out, one reason why Vue's approach is getting more attention is focus on a single component. Moreof there is a mix of things.
Dumb / Smart components
For dumb components, most of the time you're just defining a few inputs (custom attributes) and let them be outputted (interpolation/binding). So a dumb component most of the times are very short, yet follow the principle of pure functions as such they do not have any sideeffects and only render what they get.
As such it kinda forces you to keep your components small and understandable, same like pure functions which are intended to be composed out of a range of other small ones.
Single file approach forces/promotes scoped CSS
Most implementations take care of having the inlined css applied in a scoped matter, whether it is with a natural shadow dom or faking via prefixing stuff with [component-name].
No string templates
As already pointed out the inlineView strategy takes a string, which is hard to be properly analyzed by most IDEs/editors.
I personally can see a benefit of providing this with Aurelia. The issue though is that Vue per se only provides this via the vue-loader which is a webpack loader plugin. Aurelia on the other hand supports whatever module loader you like. As such I can see a hard time adding this support for RequireJS, JSPM and all the others out there.
That said I wouldn't see this a core feature of Aurelia, but rather a contribution by the community which results in a aurelia-loader plugin. This might be well suited in the work @jods4 and @niieani recently did on the webpack front.
Let me just state at the end that I personally also dislike the one-file approach, as I do feel that a file separation, altough not a real separation of concerns, simply intrdoduces much less obstacles to bundlers and also suites whatever coding style you prefer, be it functional or what I like to call pragmatic
To add to my earlier grumpiness...
I was just reading the docs for Vue single-file components (https://vuejs.org/v2/guide/single-file-components.html). I'd like to focus on the beginning of them
In many Vue projects, global components will be defined using Vue.component, followed by new Vue({ el: '#container' }) to target a container element in the body of every page.
This can work very well for small to medium-sized projects, where JavaScript is only used to enhance certain views. In more complex projects however, or when your frontend is entirely driven by JavaScript, these disadvantages become apparent:
- Global definitions force unique names for every component
- String templates lack syntax highlighting and require ugly slashes for multiline HTML
- No CSS support means that while HTML and JavaScript are modularized into components, CSS is conspicuously left out
- No build step restricts us to HTML and ES5 JavaScript, rather than preprocessors like Pug (formerly Jade) and Babel
None of these disadvantages apply to Aurelia components as currently built, so other than just having things in a single file to minimize how many files we need to create, I remain unconvinced as to the usefulness of single-file components. I also remain ready for @zewa666 or anyone else to convince me.
Speaking of @zewa666.
Oh nice to see that some of my arguments matched Vues promotion page.
I'm fully with you that none of these is a disatvantage for Aurelia. Also I'm not to say that the feature would actually introduce any remarkable difference, except personal preferences. I personally would always stick to proper file separation but I can see the need for different approaches, based on different use cases.
I don't think this is about convincing what is better or worse but more of a diversity of options, which is something that Aurelia makes better then most other frameworks in my opinion. But than again since your reply sounds like a invite to a dance-off :)
HTML Only Custom Elements are great as all you need is a html file. I personally do frequently use those structure wise. What they don't do well is testability tough. You have not a real chance of instantiating the VM behind it and make sure the Custom Element behaves as a Pure Component. The MVVM pattern itself is big about proper separation of VMs and Views in order to simplify testability. So this could be seen as a disadvantage.
Yep and again this one is just about introducing a kind of convention where one-file-components would use scoped css by default.
I would argue that string templates are useful in the case of dynamic template generation, like pulling the template from a CMS database and dynamically rendering the output. Neither is the result or cause of the other.
@AshleyGrant @zewa666
First time when saw react I was surprised, who popular something based on that approach was. Today to me separation os concerns is not a golden rule to apply to every 200 lines of code.
If have small component, and I want to add some css rules, and some behavior with javascript, I prefer to see everything together in one file in different sections of a same document and scroll to read instead of being switching files all the time in the editor.
Maybe it could be better solved with an editor feature to open 3 files at same time and split the view to show all them (some snippet sites have this approach).
It doesn't shock me to open files to read part of the component code, I just think that are easier to read when component are small. And ideally, to me, file separation should be more in sub-components, not based in languages used to express behavior, elements structure or base style.
I still prefer to keep javascript, css and hml code separated, (My point against react is declare the view content in a return statement). But If html document have script and style element why not used them? the question is can a script element contain a class to be used as a viewmodel in the away to benefit of databing?
I understand all the effort to focus on critical stuff, and less in nice to have things, but sometimes I don't like to see things like this closed so quickly, with the argumentation that sounds more like a resistance to changes. I prefer to defer to a later milestone instead of hear the aurelia team ask us to dot it in other way and close the issue.
PS. Other thing that I prefer in vuejs is the router, it supports nested routes and permits to build submenus easily. Again someone closed the issue suggesting another way to it.
Separation of concerns is good, but readability and simplicity are in some cases much more important.
@AshleyGrant with vuejs is possible to split in files to, so the opposite is not disadvantage to vuejs. But by the fact is possible to use both ways, give to it more points. In a project where we can abuse of code reuse, extending classes, replace div soup by proper custom-component etc. views and view model can be much smaller and .vue files can be not a problem just because there are not so many files with more than a few hundred of lines.
Another thing that I liked in this issue was the beginning of the title. "Will it someday be possible" I like to see milestones in github projects, it gives idea o progress and also time and space to discuss things. Maybe is a policy about how to use issues, and how to discuss ideas with Github.
In the Aurelia Weekly Issue #2 it was mentioned that the poll results were in and the Aurelia Core Team would be discussing possibly implementing One-file components.
In the previous issue we had a poll asking if the community would like Aurelia to support single file components. The results are in and almost 60% of the answers are in favor, saying they'd use it. The core team listens and will discuss the best solution going forward with this.
Does anyone know where to track this discussion and possibly contribute?
Just an idea: https://github.com/aurelia/vscode-extension/issues/77
Most helpful comment
I bring you the future:
Presenting:
MyComponent.aurelia: