Svelte and TypeScript
svelte.dev
svelte.dev
I avoided TS like the plague because I didn't want another layer added in and I thought it was just coffeescript++ but after taking the plunge on 6to5 (renamed to babel) because "well these features are coming to JS soon anyway or have already landed in stable browsers" it was just a hop, skip, and a jump over into TS (in for a penny...). Modern JS is actually really fun to work in and TS takes to the next level with peace of mind I never had with just JS.
For me, Parcel is fun to work with. Rollup is my favorite for more advanced or customized pipelines, but Parcel has a silky smooth workflow for the typical bundling tasks in most projects. I've started using it for Node.js as well (since I want to avoid ts-node) but it seems best for frontend-only projects and components. Speaking as someone who has managed to avoid Webpack thus far despite its status as the "industry standard".
Rollup is basically a configurable Parcel.
Has that changed? Was I just not using it right or didn't read the right rollup-for-the-web documentation?
It's got a small and focused core that aims for esm (I regard the other output formats supported as esm -> that format).
You do need to plug stuff in rather than having a batteries included experience. But that is a strength imo where you want to worry only about what you need.
I do recommend adapting an existing config when using it in a new project, or creating your own templates/"create-x-app" wrapper.
I use it for my home projects, and several work ones. It's "lower level" than Babel or parcel but that means I can set it up to compile both a lean, modern esm build, and a legacy IE11 compatible polyfilled systemJS bundle much easier than I can in webpack with its proprietary bundle format or parcels zero config.
I will admit that node resolve and commonJs rollup plugins are pretty much a required part to work within the npm ecosystem right now, so it is a bit more boilerplate-y than I'd like.
Have a look at the Svelte templates, they all use Rollup. Configuring Rollup is far more straightforward than Webpack and source maps just work. I'm pretty sure you'll like it.
Out of curiosity, what are you using as your HTTP server library/framework for Rust? At this point I've used a bunch of them (maybe 3/6+ that are out there) and am curious what others are using.
* Gotham. Pros: very clean. Cons: lots of boilerplate code.
* Actix-web: Pros: very little happy-path boilerplate code. Fastest framework right now. Cons: error handling is just awful - I struggled to get `?` to work. Glacial compilation times.
* Rocket (0.5 direct Git dependency). Pros: route handlers almost entirely consist of logic I care about, even for errors. Feels very deliberately "rusty." Cons: no HTTP2. No websockets. It has been accused of being "too magic."
Each resulted in a ~20% reduction in LOC. I tend toward getting shit done, so I'm over the moon with Rocket.
* actix-web:
Pros: good docs, well supported, good eco system, Actor model fits very well with how I build systems (Actor ~= Component)
Cons: some ceremony around setup of the app object
* tower-web Pros: good ergonomics, much easier to wrangle app state
Cons: all-in-one macro is a bit hard to reason about, hard to split up bits of API (I might have just not known enough about how to break up the impl_web! macro)
* warp
Pros: express-y (req, resp) => result interface, surprisingly feature complete (http2, sse, websockets) due to building off of simple interfaces/extension points, functional APIs that are easy to compose Cons: very new, kind of experimental, docs are a little lacking but examples helphttps://parceljs.org/ is the homepage. Run the command (or put the command in an npm script) like `parcel whatever.ts` and it will output your bundle with all dependencies transpiled to JS and CSS. The simplicity does come at a cost; it's not as readily customizable as something like Rollup. I've been eagerly tracking v2 and it appears they are adding linting and much more into Parcel.
What I do now is throw a "tsc --noEmit" call before tests/prod build to type everything before parcel runs. Works well enough.
Indeed, the only thing worse than no typings is wrong typings.
Since the Web platform isn't going away from JavaScript anytime soon, and WebAssembly is relatively constrained beyond WebGL, that leaves UI frameworks as the possible "platform".
What I am looking for is that the adoption will keep carrying on, to the point that browser natively understand Typescript, or WebIDL for that matter.
But of course, that'll add quite a drag on TypeScript development. With Babel, they can just maintain the plugin themselves; with browsers, they'll have to go through the standardisation track for every syntax change they want to make.
TypeScript also has to go through the same process, after all they need to grow alongside JavaScript and besides typing, there is nothing that gets introduced that isn't JavaScript at its core.
Stick with transpilers and you're good to go from today.
There's also deno for node.js alternative that supports TS natively but not sure of its future.
Instead of trying to support all the super-dynamic parts of JS, those parts should just go away in typed mode. Unlike TS, the type system should be sound. Hindley-Milner with immutable by default and options instead of null with structural typing everywhere and typeclass module definitions.
I guess that's just StandardML with JS syntax, but that would be an amazing language to work with -- far better than either TS or ReasonML.
And regarding "the dynamic parts should just go away": No, please! And I'm saying this as a full time Scala dev doing "pure FP" in my day job who loves static types. But I also really like the "super-dynamic" parts of JS. I think such features should get integrated into some static lang. This would need some thinking though. The "old" static languages can't do that easily. To bring an example of what I mean: One can see JS objects as "extensible records". Adding and removing props on a prototype looks for example like "a super-dynamic" feature. But "extensible records" are also doable in static langs. I think more of those "super-dynamic" features are actually doable in a static context. Extending current FP languages with all kind of such features would be quite desirable, imho. "Why not have both?" :-)
After C# of course yet another DSLs.
TBH TypeScript is just better than C# for the job it does - DOM control and gluing data - structural typing that's backed by a dynamic runtime is a much better fit for those kinds of tasks than a nominal type system backed by IL level type checking - AutoMapper is nonsense created by this design decision and C# is particularly verbose (almost Java level).
C# allows you to get much lower level than TS can, you can control memory layout, allocation patterns, you have proper threading model, etc. etc.
But for dealing with single threaded DOM event loop, stitching data from all kinds of sources, simple transformations and sending it around - IMO TS is a better fit.
C# is too bloated for my taste and I have to admit, TS is too close to C# for my taste.
ReasonML files don't look like that and are even sound.
I've found it vastly increases incidental complexity and affords little to no benefit to me. The IDE completions are nice, but ultimately not worth the price, in my humble and honest opinion.
Although I've found that TypeScript is a great way to attract devs who hate JavaScript to try working on front-end.
Editors are meant to auto complete any parameters that you have typed as well as provide errors that don't fit to your typing.
Using editors like vim wouldn't work.
Hi. Fellow emacs enthusiast here. We can evangelize emacs tide mode and slander vim on other TypeScript articles, but I think it's best not to do so on this article, because it specifically mentions vim in the editor support section.
https://svelte.dev/blog/svelte-and-typescript#2_Editor_Suppo...
My work has benefited from TypeScript because we can now propagate changes to our unstable API throughout our medium sized application using the compiler. We are fairly certain that all of our components are integrated if the compiler is silent. Before this certainty, we would frequently push broken API integrations to production.
The complexity of TypeScript doesn't seem to benefit projects that are already clean and tested. TypeScript gave us some confidence of correctness when we had disorganized code and inadequate test coverage.
I encounter seemingly nonstop opaque type errors that come usually when I upgrade TS versions. I'll stipulate this was mostly written when we decided to add TS, and I was new to TS when I added it, but I tried really hard.
As an example, it took me a full week to properly add type definitions to a HOC, and I had to rope in a couple other engineers across that time who had more TS experience. Eventually I got it working, but decided to deprecate the HOC cause the file exploded from being about 50loc to well over 250.
If you have a ton of state, classes, high coupling and a lot of variance in your data structures (which Javascript really easily allows), Typescript is not an instant game-changer.
This is not that different from having good test coverage is easier during development than adding it later, as you will end up writing your code in a way that makes things more decoupled and testable.
It was way easier to get to that sweet spot with our Node.js code vs. our React code. React code is still more of a battle than non-React code, although functional components has made this better. Class based components suck the most and we just opt for using "any" instead of fighting it. Don't get me started about HoC.
I also found the typing to not really help. Non-null stuff is nice, but without range types, I don’t think the trade off is worth it. It helps about as much as Go’s type system but asks you to do 3x the work, restrict yourself to typed libraries, and setup some pretty tricky tooling.
Use it with a proper editor that supports TS like VS code or IntelliJ and figure it out.
However, from where I stand, Typescript sucks. Sucks sucks sucks. It takes everything I love about JS programming and turns it into suck.
I'd recommend any front-end dev to give Svelte a try, even just spending an hour or two messing around, to experience a way of developing web apps that's likely a bit different to what you're used to, but feels familiar enough that it doesn't require a big mental leap.
- 3 min youtube demo: https://www.youtube.com/watch?v=djRkyyBoIKs&feature=youtu.be
- 3 min eggheadio lesson: https://egghead.io/lessons/svelte-create-a-new-svelte-projec...
- TS + Sapper: https://mrsauravsahu.github.io/blog/38/
Stoked for Svelte to support it.
We've been using Svelte in production and I can't speak highly enough about the developer experience. Absolute game changer for our ssite that use it.
Svelte is a dream compared to React. That said, I've never felt like React was the right solution for the problem.
I've extensively used Gatsby and for static sites, React is absolutely overkill. For apps it can be nice.
In both cases my go-to these days is Svelte.
I haven't used Svelte yet - but am interested.
Can you explain a bit more about what you mean with your data flow and routing needs were too complex for Sapper.
And what makes Svelte a dream compared to React?
Our primary problem with Sapper is that we wanted our URL structure to be such that you can't tightly route a template/view by just looking at their URL. /senior-living/blog-post/ and /senior-living/nursing-home-name/ need to live side-by-side.
This forced us to build our own custom routing system, what we call an "inverted router" for our SSG.
Also we found it less than elegant to use DB queries with Sapper and had a lot of concerns about what was actually on the client and what wasn't.
As for why we swear by Svelte:
* Bundle size. For SEO focused sites React is overkill.
* Stores compared to Mobx or other state management
* $: reactivity
* No css-in-js hacks required. Css is automatically scoped, but can be easily globally scoped.
* Single file components are just beautiful.
* We've built in the ability to SSR our entire site, but only hydrate the parts that need to be. This is a game changer for page size and not pushing your data twice to the client.
As it currently stands the SSG is super opinionated and we did several things quite unconventionally, so we are validating some of our ideas by building out another site besides elderguide.com to make sure these decisions indeed work across a lot of use cases.
Once this second site is out the door we want to add TS support natively to the SSG and then we'll release it.
But then they introduced a whole new language for loops and control structures, and I really prefer JSX for that. JSX nails a sweet spot of bog-standard Javascript/Typescript, with enough HTML syntactic sugar to very natural web-pagey parts. As long as TS/JS is already in there, I'd rather use it everywhere.
I don't know it well enough to know if that's a necessary feature, or if the language will evolve to something closer to my sensibilities. I will probably give it a try in the future, especially if I want something more performance focused. (The virtual DOM overhead is real and the separate state mechanism is far less elegant than Svelte's solution.)
Not only in structure, but how they compose. The typical top-down tree components composition is typical. What is not immediately obvious is how child components can expose functionality upstream. So simple.
Is your custom built routing system open source?
I can imagine the Svelte community could benefit from it.
I used both React and Vue and am now only using Svelte.
You type less. Significantly less.
The thing you type is simpler. I tend to get lost in Vue's object structure.
What you type is closer to HTML/CSS/JavaScript than what you type in React/Vue. It's therefore easier to understand what gets generated.
The seamless reactivity is awesome.
Scoped CSS support is built-in so you don't need css-in-js hacks.
Built-in support for data (stores) is excellent.
The final bundle is smaller and faster.
There's more but the above are the major points.
The only downside is smaller ecosystem. But I don't care because I'm in the camp of minimizing my dependencies.
vue/react also have scoped css, but built into the building process using loaders rather than being a feature of the frameworks.
That said, I find that Svelte aligns more with my/our team's mental model about how the web should work and that is why went with it for our sites.
Just like with Vue you can write your JS/CSS/HTML in a single file, but the reactivity and state management is much easier to reason about than what we've seen elsewhere.
- `$:` is great.
- Stores and derived stores are amazing.
- Data binding / rerendering is really intuitive.
That said, the biggest headache in building our own SSG was getting SSR/Hydration working well, but that was mainly fighting Webpack and got easier when we went with Rollup.
edit: formatting.
This.
I suspect there is a certain way those who rave about TS like yourself write and structure their code (all code, regardless of language) in a way that naturally lends itself to strict typing. The "rigorous null checking" comment struck me as odd, as someone who has written JS for almost 20 years, I've just never had to think about, or use null values. I probably just use the good parts of the language and avoid the bad [2]
[1] https://news.ycombinator.com/item?id=23913294
[2] https://www.oreilly.com/library/view/javascript-the-good/978...
* Accessing a missing property or method results with undefined. Hope you remember the exact method names and field names of all objects in your codebase!
* Using "str".match(regex) results with null if there are no matches.
We are speaking about just null, not "null and undefined". Believe it or not, I simply do not use null in JS. Study the concept of "truthy and falsy" in JS.
> Accessing a missing property or method results with undefined. Hope you remember the exact method names and field names of all objects in your codebase!
I don't. I do however structure my code predictably, using consistent naming conventions and patterns. I hope you do realize JS existed for over 20 years before TS, and complex apps like gmaps and google docx were built entirely in JS.
> Using "str".match(regex) results with null if there are no matches.
const match = /bar/.exec("str");
if( match ){
// am only interested in what happens if foo returns a *truthy* result.
// The exact type of a falsy result is irrelevant, it either matches (truthy) or it doesn't (falsey)
}If a team member writes
function extractEmail(text) {
return x.match(/someregex/);
}
and you call extractEmail(x), you might get a null value.If you assume you can't get a null value, you might try to do further processing:
let [name, host] = extractEmail(x).split('@')
and get a type error thrown. That is, if you're lucky.In the more common situation, you will actually save that to a database and that database will happen to accept null values by default, and then all hell will break loose in another totally distant bit of the code that naively fetches a list of emails from the table, grouped by host name. And you will have to chase down the bit of code that inserted that null in.
This is approximately what development without types looks like. When this happens to you, I hope you remember the following bit of advice: It doesn't have to be this way :) Alternatively you can start doing paranoid validation everywhere. That works too, except the nice thing about a type system is that it can properly track whether you need to do that or not (see https://github.com/spion/branded-types for one TS technique on how to do that)
I'm anti-TS, but there is a meaningful difference between null and undefined. Most of the time it's enough to check for falsy values, but there are times when you will want a distinction between a missing value and a value of null.
Null, on the other hand, is not a lack of information. It's an absolute value just as much so as any number or string or array.
They're both falsey values, but so is the number zero. An item with a price of zero dollars is not the same as an item with an undefined price, nor is it the same as an item that explicitly has no price, i.e. null. You may not choose to model your data that way, but the terms are still meaningful, and your UI might have to change to reflect the different falsey values.
Most common case I could think of, would be in making a request from a server, using something like Apollo. `const [ data ] = useQuery(SomeQuery)` The data that comes from the server is undefined until you make the request, but null could be a valid response.
Maybe you are, but when people are talking about using TS just for the strict null checking, they typically refer to the (default-on) `strictNullChecks` config option, that is about both null and undefined.
Which is to say: whether you use null or undefined is not really relevant to the point that was being made...
I always assumed complex Google apps from that era were built with GWT, which would mean Java.
You never interact with database? You're not supposed to pass undefined as NULL value.
And a variable that is waiting to be defined is very different from a value that received null as a result.
Dealing all those mixed up as falsy is a bad design.
I had ~2000 errors and slowly worked to 0. tsc —watch is so good for iterative development.
And LSP (Language Server Protocol) really is a boon for the industry. So many tools can work together. Thank you VSCode for paving the way to an open protocol.
I'm playing with Vue version 3 with TypeScript using JSX instead of the usual HTML templates and pretty happy that it's all type checked. I have a similar project without JSX and the vast majority of the bugs are related to the logic in the HTML templates not being type checked.
It depends. If you type-check your runtime input (e.g. form fields) then it works well.
It would not surprise me if the ECMAScript folks just throw in the towel and adopt TypeScript into ECMAScript as its official type-annotation feature - like how Python is doing - except without the duplication of effort.
As someone who has no clue, and with all do respect, why would TypeScript be worth moving from just hitting save to introducing a build system and dependencies?
Please don't feel pressured to make your code more defensive by switching to a typed language. There is often a tendency to make things more complex in the name of safety especially when there's typing involved, and it's not always the right answer. Clean, readable, maintainable code can exist in dynamically typed programming languages, and don't let anyone tell you differently.
The right balance between over- and under- engineering is something that changes based on who you work with and for, what you're truly trying to accomplish, when you need it by, how quickly you can iterate, and your own personal feelings of safety and joy of programming.
It is a bit hard to define complex types. E.g. I couldn’t for the life of me annotate the return value of the pipe function:
function pipe(init, ...ops) {
return ops.reduce((acc, op) => op(acc), init)
}
For these instances they suggest writing a declaration file[2]. However I have found the documentation isn’t really clear on this usecase (in fact I find the documentation of TypeScript somewhat lacking in general).But overall getting these typehints into my editor environment has been worth it. And I haven’t had to sacrifice the save → run workflow.
1: https://www.typescriptlang.org/docs/handbook/type-checking-j...
2: https://www.typescriptlang.org/docs/handbook/declaration-fil...
EDIT: An example annotated JS file for typescript: https://github.com/runarberg/strawberry-router/blob/master/s...
`npm run check` just runs typescript’s type checker, there is no compile step.
Don't feel bad, no one can do that (yet! I think it should be possible with Variadic Tuple Types, coming in TS 4). There are a couple of attempts[1][2], but they all lack in some way. Redux does it with a boatload of overloads [3].
1: https://dev.to/ascorbic/creating-a-typed-compose-function-in...
2: https://stackoverflow.com/a/53066700/1586229
3: https://github.com/reduxjs/redux/blob/686d29b5d4e2dcb6709c16...
function pipe<T>(init: T, ...ops: ((x: T) => T)[]): T{
let r:T = ops.reduce((acc:T, op) => op(acc), init);
return r;
}
I had 5 years experience fixing type errors in C++; typescript seems like a dream in comparison.Edit: I just realized your operations probably DON'T return the same type that they are passed; they probably work in a chain like (t:T) => U, then (u:U) => V, etc. Nevermind!
type Ops<T, R, N> = [
(x: T) => N[0],
...<n>((x: N[n]) => N[n + 1]),
(x: N.last) => R,
];
function pipe<T>(init: T): T;
function pipe<R, T, Ops>(init: T, ...ops: ...Ops<T, R>): R;https://blog.isquaredsoftware.com/2019/11/blogged-answers-le...
Try in below example, it print out '12' without type related error message.
<script lang="ts"> let a: number = '1'; let b: number = 2; </script>
<p> c = {a + b} </p>
The error returned is `Type '"1"' is not assignable to type 'number'.`
On svelte, the typescript error doesn't show up until you manually run svelte-check.
The browser is a crazy environment and adds difficulty, but I find my server code can very strictly typed. The nodejs type definitions are good and if you pick an ORM library with good typescript support then both the in memory data structures and database objects can be well typed.
The build step with typescript is basically negated by ts-node for the server. Alternatively, by using tsc --watch and some clever indirection I've enabled hot reloading for most of my server code. So just to be clear, I have types helping me code using vs-code, I save and immediately see changes on the server.
If you know the tools well and how to set things up then TS + node can provide a better developer environment than many languages.
I tried, and failed, to use Babel as the TS compiler - but TSC then Babel works just fine.
Not all of us think JSX is a great thing. The "templating" language in Svelte isn't really a templating language at all, it's just Javascript with some (unavoidable) helpers. It takes about 2 minutes to learn since there are really only maybe 5 helpers.
[0]https://www.fibretiger.co.za The above was previously coded in angular 9. I've seen faster loads in CoreWebVitals, and strangely... more of our post got featured in Google-Discover(could just be coincidence)
Everything we do is written in Svelte + Sapper, not just our site, but all the backend apps as well that we use for admin + providers.
Was my only blocker :)