All good time of day! In pursuit of my
previous post , I want to show a simple example of a micro component of autocomplete on
SvelteJS . Who has not had time to get acquainted with this little framework - wellcome under the cat!
Disclaimer (Attention <sarcasm /> detected!)Immediately declare that none of the existing, as well as the frameworks of the future, and not close stands next to $ mol. I am by no means arguing that any other framework is cooler than $ mol, because it is simply impossible to compete with $ mol in coolness. This is the coolest framework ever created by mankind. I’m sure $ mol will save the world!
Well, now you can talk about Svelte) Since this is a Friday post, I will try not to delay it too much.
So, the task is to make a reusable micro component of autocompletion with support for asynchronous loading of the list of options. In other words, we start entering the desired value - a list of options drops out, which can be set both statically (a certain array), and dynamically loaded from the server.
Actually the svelte component itself may look like this:
')
<input list="suggestions" bind:value="search" placeholder="Start typing..." /> {{#await suggestions}} {{then options}} <datalist id="suggestions"> {{#each options as option}} <option>{{ option }}</option> {{/each}} </datalist> {{/await}} <script> export default { data: () => ({ search: '', suggestions: [] }) }; </script>
RemarkThe attentive reader will immediately notice the kind of “life-hack” that is present here. Namely, the use of the html5 <datalist /> tag, which was actually created for such things, but still has poor
browser support .
I want to note that I use it here purely for demonstration purposes in order to visually simplify the code for better understanding, and also because the specific implementation of the drop-down list is not the purpose of the article. Changing the list from <datalist /> to <ul /> with a couple of styles is not a difficult task.
As a result, we have a simple template with an input field and a list of options attached to it. The input field is bandaged to the “search” variable in the component data, and the list of options is dynamically set using the “suggestions” array.
Notice the {{#await /}} in the template. It is this simple construction that allows us not to worry whether the “suggestions” variable is a real array or whether it is a promise that will be resolved into an array.
Here, perhaps everything, now let's move on to using:
<h1>Selected location: {{ location }} </h1> <Autocomplete bind:search="location" bind:suggestions="locations" /> <script> import Autocomplete from './Autocomplete.html' import { fetchLocations } from './api.js' export default { data: () => ({ location: '' }), computed: { locations: location => { return location.length >= 3 ? fetchLocations(location) : [] } }, components: { Autocomplete } }; </script>
This is a parent component that implements the domain-logic of a particular case. In this case, it is the choice of location (city).
First, the auto-completion component is connected, as well as a module that implements interaction with the server API. We also have a variable "location", where we actually save the selected value. It binds to “search” from the autocomplete component via props, and is also outputted by some resulting value a little higher.
Next, an interesting point. Since Svelte supports the output of asynchronous values ​​via {{#await /}}, as well as computed props, which may depend on other data, we can write a super simple calculated property to get a list of options from the server and link it to change "Location". Those. when the user enters a value in the field, the reactive variable “location” changes, resulting in a recalculation of the calculated “locations” property. This property is also bound to "suggestions" from the autocomplete component via props. And everything works like “magic”))))
I also note that in order for the example to work well, an implementation of the debounce method is necessary in order not to overwhelm the server with unnecessary requests. In this case, it is assumed that debounce is already implemented inside the fetchLocations () function, because it has no direct relation to the example.
This is how super easy it is to implement a reused micro-component of auto-completion on Svelte.
Further, since to the previous article about Svelte many questions were asked concerning the principle of Svelte, AoT compilation of svelte components and the likely duplication of code. I present a free translation of
this comment by the creator of Svelte Rich Harris (Rich Harris):
This is a good question. I would answer it in several ways:
- Part of the code is reused between components (for example, such methods as detachNode, etc.) if we compile the code using the shared: true flag (which happens automatically when using integration with build-tools, such as svelte-loader or rollup-plugin-svelte ). In that case, all these things are not duplicated, reducing overhead.
- The code is generated so that it is more or less readable, but at the same time is not quite large in size.
- However, in theory there is a transition point where the size of the generated code exceeds the size of the framework + templates. However, by the time your application grows to that size, you will most likely need to use code-splitting techniques. For example, load components asynchronously, based on the current URL. Code separation methods work much better with Svelte than with traditional frameworks, because traditionally, even the smallest piece of code depends on the entire library.
- The size of the code is only one of their Svelte goals. Other goals are high performance, providing good experience for developers (since the compiler is based on static code analysis, we can have useful error messages and other kinds of warnings, like in Elm). Also a big plus of this approach is the absence of the need to say “no” to good ideas of new features for the framework, because the emergence of new features does not affect people who do not use them. Traditional frameworks are always forced to find a balance between the size of the framework and the needs of its users. And so on.
- In any case, we can and will reduce the size of the generated code, for example, using smarter processing of spaces or using innerHTML in cases where there is a large piece of static markup that does not make sense to generate programmatically. As a result, the size of the generated code will only decrease with the development of the compiler.
Of course there are tradeoffs, for example, with respect to Ractive - this is flexibility. We cannot do this.observe ('some.nested.property', () => {}) or use adapters for complex variables, or have {{#with ...}} blocks in templates and other things. All this makes sense in Ractive, which uses the “do what I mean” philosophy. While Svelte is based on static analysis and more on the fact that “do what I say”, in the end it is a more rigorous version.
From myself I want to add that I have not tried Svelte on a more or less large project (although I am planning). I also do not oppose such giants as Angular or even Vue. Ractive is playing on that pitch rather than Svelte.
However, I think that it perfectly occupies a niche of small (widgets, etc.) and medium projects (mobile and TV applications, etc.). In such projects, Svelte certainly provides a smaller bundle size and greater speed. If this is important for you, you should get to know him better.
Great weekend to everyone! And may the Power of Friday arrive with you!
UPDATE:
For those who are concerned about duplicating code in Svelte. There is new information directly from Rich Harris. My comment on this topic can be found
here .
UPDATE 2:
Who is interested in Svelte and would like to follow its development -
welcome to the Russian-language telegram channel
SvelteJS . We will be glad to you!