Mint: A programming language for writing single page applications
mint-lang.com
mint-lang.com
But then I started looking at the examples and how styles and an xml-like syntax are given first-class support and it makes sense. It really is a hard problem to shove into an existing language, evidenced but all the transpiling that goes on now. Thanks for sharing!
Edit: coffee -> code
I've never seen the term 'coffee' used in this context. Is this a typo or some kind of slang/reference?
UI implementation (especially for the web) is a very hard problem. We've been trying to get it right for decades. This is a problem domain in need of attention. The CURRENT frontend paradigm (React/Redux SPA) is using a mix of technologies, which might benefit from consolidation and streamlining.
There's a fair amount of library discovery/evaluation overhead needed to get a fresh start in the React ecosystem, and the people who have to do it often don't have the perspective/context to make good choices efficiently.
If your employment prospects don't depend on using the major frameworks that everyone else is using, you're probably going to choose (or even create) a framework that best fits with the way you think and the way you like to work.
I don't think they're that hard to discover, although I spent a while trying other Google searches before I realized react-training's react-router was the real router everyone mentions. Somehow their website seemed quite scammy, and I was very surprised routing wasn't in some sort of core/stdlib.
- the documentation is in one place instead of several places
- the dependencies of a Mint project is usually a few megabytes since everything is included instead of hundreds of megabytes (I have a production app that does not have any dependencies at all)
- only need to learn one (compact) thing, instead of many complex things (complex since there is no compiler to make it simple)
- only need to update the code once there is a new version of the language not every time there is a new version of a dependency
On top of the libraries mentioned the language also includes a formatter, package manager, builder/dev server and testing environment, also for which you would need to add dependencies.
All of these add up to less cognitive load so I can focus on building the product instead of managing the development environment.
(edit: formatting)
I think a lot of people will gloss this over, but I thought about what I would want if I put the same amount of time and effort into something, and I would want honest feedback.
> - the documentation is in one place instead of several places
For developers with a few years experience, they don't generally have trouble finding documentation for disparate frameworks and languages. The bigger trouble is usually finding out the latest best practices.
> - the dependencies of a Mint project is usually a few megabytes since everything is included instead of hundreds of megabytes (I have a production app that does not have any dependencies at all)
There are a lot of use-cases where the bloat of the web app isn't really an issue. But for those who do (and I'm not sure who they are), it's still a somewhat unsolved problem.
> - only need to learn one (compact) thing, instead of many complex things (complex since there is no compiler to make it simple)
I don't think that's necessarily true. They would have to learn all the same concepts which exist within Mint. (And if not all the same concepts exist within Mint, then it's not up to par.) What's different is the syntax, and the semantics of how these concepts glue together within Mint. This generally means it's actually harder to learn a new all-on-one language than it is to learn React + TypeScript + styled-components for someone who already knows JS.
> - only need to update the code once there is a new version of the language not every time there is a new version of a dependency
Then how are the dependencies getting updated when there's a new version? If I use a currency library in my Mint app, how can I update it, and test it locally to make sure the updated library still works with my app? At some point we have to deal with dependencies and updating them...?
All of your counter points have merit, I think it boils down to preference at this point, but what I can tell you that after doing Elm for a while getting back to the JavaScript ecosystem is a nightmare and Mint is my way out of that (for SPAs).
> I don't think that's necessarily true. They would have to learn all the same concepts which exist within Mint. (And if not all the same concepts exist within Mint, then it's not up to par.) What's different is the syntax, and the semantics of how these concepts glue together within Mint. This generally means it's actually harder to learn a new all-on-one language than it is to learn React + TypeScript + styled-components for someone who already knows JS.
I'm not entirely convinced that that is the case, TypeScript can be it's own language in itself. Not really a problem now but a few years back people struggled to even learn new versions of JavaScript in itself, let alone a the libraries with their different paradigms.
Also to get where Mint is you would probably need to learn: TypeScript, React, styled-components, Jest, prettier, Webpack, Redux (or one of the alternatives), Babel and that's just from the top of my head.
> Then how are the dependencies getting updated when there's a new version? If I use a currency library in my Mint app, how can I update it, and test it locally to make sure the updated library still works with my app? At some point we have to deal with dependencies and updating them...?
There will be dependencies sure and you will take care of them as usual, what I am saying is that with Mint you will only need a few.
The application I've been developing (https://www.base-api.io/) and the front-end is in Mint and it has 0 dependencies (other than the standard library which is built in).
Anyway, nice job! The language looks really clean.
I think that's just a coincidence. We happen to know people who are starting to learn JavaScript (and learning new languages is always a struggle), and so naturally they also struggle to learn TypeScript when faced with those concepts for the first time. But this is more The Evolution of a Programmer kind of thing.
> Also to get where Mint is you would probably need to learn: TypeScript, React, styled-components, Jest, prettier, Webpack, Redux (or one of the alternatives), Babel and that's just from the top of my head.
A lot of these (Babel, prettier, Webpack) just need a good starter configuration and can be mostly ignored afterwards. The rest mostly boil down to concepts: Jest stands in for any testing framework, there's nothing special about it; TypeScript for a mostly-basic type system; React for a basic declarative UI framework; styled-components for mostly-just CSS encapsulation.
> There will be dependencies sure and you will take care of them as usual, what I am saying is that with Mint you will only need a few.
Ah I understand better now what you meant: the concepts that come built into Mint are ones you don't have to worry about getting an external dependency for.
Hilariously, the more difficult, time-consuming work I've done over the last couple of years has been getting these kinds of configurations setup appropriately for my org. It always feels like an enormous cost with hidden tech debt.
This story is similar to Elm. I tried to teach people without programming experience at all, they don't have bias or preference so those 'alternative languages' looks good to them. But to convince the 'legacy world' is a tough work. Anyway, appreciate the work of Mint :)
I will try Mint our later today.
It can be fun implement but I doubt this will be adopted.
- No way to render a page outside of a browser. It'd suffice to be able to run a CLI tool or import Mint as a library and generate static HTML for a given component and input data.
- The fact that two record types can't coexist with the same key names and type signatures. I worry this will lead to all kinds of headache dealing with dependency compatibility: any change to a record definition, even an internal one, becomes a breaking API change, and some libraries may not be usable together due to coincidental naming. I would much rather the compiler require that I annotate record literals with explicit type names to disambiguate, ie:
record Todo {
label : String,
done : Bool
}
...
foo = Todo { label = ..., done = ... }
Haskell dealt with a similar problem for a long time and it meant that best-practice code gave all its data type keys unwieldy prefixes to disambiguate between data types that were imported together (todoLabel and todoDone vs issueLabel and issueDone). In Mint I guess you'd also want to stick the project name in, too (so myLibTodoLabel).Its a rare line of JS that doesn't include at least one of a conditional, a function call or definition, or grouping parens, outside of declarations. If you use "parens" broadly to include square, angle, and curly braces, JSX and declarations have plenty, too (and if you don't use "parens" that inclusively, Clojure/ClojureScript doesn't have all that many, because of its use of different delimiters for different purposes, unlike classical Lisp-family languages.)
I was working for a startup, building a .Net project with Angular 1.x. And I was on a failing trajectory - code was full of holes, I was struggling to finish things on time, I was stressed, I started to hate things for no apparent reason. Finally, after years of writing software, I just wanted to quit and learn something else - woodworking, photography, cooking, landscape design - whatever. Deep down, I knew - it was not due to the technology choice. The same project could've been re-written in other languages I knew and still be as frustrating.
Long story short - I started learning Haskell. That improved my coding skills tremendously. But there was some hump I couldn't get over - Haskell was still extremely difficult, I was not even near to the level of being able to write production-ready Haskell code. Besides, I wanted to write web apps. And Haskell's options were not great at the time. After using Typescript, Coffeescript, LiveScript, IcedCoffescript, Gorillascript, Traceur, Babel, Fay, Haste, GHCJS, I finally decided to try Clojurescript. And suddenly, everything I've struggled with Haskell started making more sense. And unlike Haskell, Clojure turned out to be a much more pragmatic choice - I am more productive today than I ever was before. Even more than I was with Python, Ruby, or Go. Today, even if I have to write something in another language, I would first prototype it in Clojure and then translate it to another language. It may sound stupid, but that is the fastest way for me to build things.
Learning Clojure opened a whole new world for me. Logic programming, generative testing, dependent types, concurrency and parallelism, distributed and numerical computing, probability, etc. I never knew all these things are approachable even by a lazy and simpleminded idiot like me.
Learning Clojure improved my work, my relationship, my confidence, my health.
The only regret I have - I carried my unfounded prejudice for years, but the door was there all the time, I kept ignoring it. I just needed to walk through that doorstep.
Don't hate parentheses of Lisp - they may look ugly to you today, but trust me, there's a lot of beauty and elegance that you may not be seeing.
Side by side sample or it didn't happen. (EDIT: see below) I would imagine ClojureScript has more parens in the narrow sense, but I can imagine it being "morally correct" if one considers angle brackets, curly braces, square brackets, and parentheses per se as "morally equivalent".
EDIT: so, I found https://www.toptal.com/clojure/clojurescript-tutorial-react-... which has this simple example:
(defn component
[]
[:div
"Hello, world!"])
vs. function component() {
return (
<div>
"Hello, world!"
</div>
);
}the JS has two pairs of parens in the strict sense vs. one pair in the ClojureScript, and 5 pairs of balanced delimiters vs. 3 for the ClojureScript, and the JS doesn't minimize parens (but is idiomatic, so it better represents realistic code than minimizing parens would.) So, yeah, while this is a dirt simple example, it does demonstrate that it can be the true.
- Clojurescript code is easier to edit, e.g: if you want to wrap the string in <h1> tag there's a lot less typing you have to do.
- Cljs code is also "data", it can be send over the network without any modifications or encoding, sent to the REPL for evaluation, etc.
- You can "eval" every single part of it:
"Hello, world!" string;
[:div "Hello, world!"] vector;
component function itself - these are all valid Clojure structures.
What happens if you copy-paste any part of the JSX into JS REPL?From what I can see: it has zero incremental development. You must start with Mint and haul in other new tools, or it doesn't work. That's a nonstarter, and part of the reason why VueJS was so easy to integrate.
I read the Guide (briefly) and don't see any advantages. It looks like they thought-out the most trivial scenarios, and that's it. Recursive components? Data sharing? Messaging?
I can however elaborate on the points raised:
- Recursive components: you can do it, the type-checker allows it and it works, or goes into an infinite loop if you don't exit correctly.
- Data sharing: I don't know what you mean by this. If it's data sharing between components you can do that by creating a store and connect as many components to it as you like.
- Messaging: I don't know what you are referring to? Websockets? Http? between components?
The fact is that there is some many things built in that it is hard to fit it on a single page above the fold, that's why I would say it's advantages is: it's the only thing you should need.
> You must start with Mint and haul in other new tools, or it doesn't work.
Could you elaborate on this?
Another problem with a framework especially for UI, is that you need a network effect, that is really a good chunk of people who had tried it in production and could vouch for it, so that other folks can atleast give a thought about giving it a try. This is important given the rate of UI framework churn and JS fatigue that people have gone through in recent times.
Personally, as an UI engineer who has familiarity with almost all of the existing libraries/frameworks/toolchains this looks refreshing and would not mind trying it out.
As for my points: 1. thanks!
2 & 3: Reactive frameworks on an SPA are all about messaging between components. If I do an update on a dropdown, it is reactively stored in the component dataspace, but without a bus, my only choice for alerting other components is for the main component to watch that variable, keep a list of current components, and then iteratively broadcast: e.g. I must invent a message queue. How does Mint address address this problem?
4. was explained perfectly by a peer comment.
Multiple reasons why:
- Rich Harris (author of Svelte): eager (when laziness is preferable), styling is problematic, add confusion to attributes vs. props with disastrous ergonomics, leaky design, bad underlying model (DOM), global namespace [1]
- Serhii Kulykov (building Vaadin, a Web Components library): no form participation, broken autofill, broken accessibility, breaks SVG references, cannot extend built-in elements, handling focus, handling selection [2]
- Sarah Mei (Salesforce UX): Web Components break accessibility and assistive technology [3]
On top of that, you will always need a library/framework on top of them to orchestrate them, pass data around etc.
[1] https://dev.to/richharris/why-i-don-t-use-web-components-2ci...
[2] https://dev.to/webpadawan/beyond-the-polyfills-how-web-compo... and https://dev.to/webpadawan/the-journey-of-web-components-wron...
(I'm a student, hate webpack, and don't want to learn it's nuances for a few years. I know from googling this can be done with sufficient webpack config).
I've come from Elm where it is done in a very good way, but it's too restrictive, and I like react and it's expressiveness so I wanted to combine the two.
Vue is really good but at the end you are still writing JavaScript which is really hard to do in a safe way. And from my experience Typescript isn't 100% safe as well.
Why is this a goal? Could you elaborate?
> And from my experience Typescript isn't 100% safe as well.
Does it need to be? In my experience, enforcing reasonable standards (don't allow escape hatches like the `any` type, or the `// @ts-ignore` comment band-aid) fosters pretty strong interfaces. I haven't really needed more from the type system. Has your experience been different?
To your first question: JS's warts are well understood. You must already acknowledge this if you're a TS fan.
To your second: TS isn't 'actually' safe, to the extent something like Elm is (i.e. very small chance of runtime errors). This is also no secret - there are lots of examples out there if you care to search for them.
Further, UI development is an area where things can get messy very quickly. "Safe" languages often greatly minimize the kinds of bugs that are very easy to write in JS. This is one reason why Elm and Clojurescript have had years of adoption -- they by default make values immutable (and their entire programming paradigm doesn't actually require mutating most values ever) which removes a large class of common UI errors. There are other benefits as well.
In any language design, the total time spent discussing
a feature in this list is proportional to two raised to
the power of its position.
0. Semantics
1. Syntax
2. Lexical syntax
3. Lexical syntax of comments
In future, I would suggest not nitpicking the most trivial, irrelevant detail of a language's design. Please consider the level of effort it has taken to create this language.Device: iPhone XS (fully updated)
For additional reference, it seems to be alternating sections starting below the fold (man I hate that phrase)
An interesting use for a DSL.
The magic sauce for me is a global state data structure where all my app state goes into. And it should just be data. I don't need to wrap it in 'semantic' constructs.
And then I need an easy way to query that, something more expressive than `get-ins` like `state.path1.path2.value`.
However the state is accessed the component should just update. I don't want to provide or connect.
Instead of using cascading parameters and other ridiculously complex ways of passing state around, we inject stateful services as scoped dependencies per client request. These are effectively just POCO models with a functional interface for mutating state. Then, we take dependencies on these throughout the web application (I.e. within each component or page). An example of one of these used heavily throughout would be UserSessionService. Certain aspects of the application may have their own dedicated state machines like LoginService (which is utilized only during the login process). LoginService takes a CTOR dependency on UserSessionService and it all plays together really nicely via Microsoft's DI.
We've even wired events from server-side directly into these services so its not just for handling the client-specific interactions either. Integrating server-side events is trivial. It felt a little weird at first, but it seems we are moving in a much more sustainable direction now. I can actually test my UI state machines in complete isolation from an actual browser. Also, because they are simply .NET implementations, we can reuse these for other aspects of the application.
> Instead of using cascading parameters and other ridiculously complex ways of passing state around
So much this! There are too many folks stuck in the 'container' component pattern when really you should never pass a prop that can be queried from state. Working like this results in a sustainable application that's flexible, like you _state_ xD
I'm going to give this a really close look, thank you.
But, once you get into really complicated scenarios where structurally-unrelated components are statefully-related (e.g. navbar interacts with some component in an entirely unrelated modal), things get very nasty without some common arbiter of state being shared between these components. You can usually solve this in some way with all the SPA frameworks I've worked with, but Blazor is the first case where building these state machines as C# services has knock-on benefits that simply can't be ignored anymore IMO.
Overall, separation of state machines from the UI seems the be the theme, and certain technologies can do this a lot better than others.
We have a "service layer" for React made up of state-machine-based services (although reactive services based on RxJS observables works as well). We also created associated custom hooks that allow developers to easily "inject" a service into their React component (use use React's Context API for our "DI container"). From there they can read the service state, or send events to it to trigger behaviour that is encapsulated in the service itself.
We even have the same "most used" service; a UserSession service manages OAuth based login flow and session management.
The best part of this approach is that our service layer started in an Angular based proof-of-concept before we lifted-and-shifted it all into React.
Here’s a follow-up post with a gist of what the React integration looks like.
If it Didi I think it would be a major advantage over react, angular and Vue. Of course all these support the creation of a static file, but it's not trivial and it feels like an hack more than a feature.
Therefore if mint has/had the option to produce (also) a static website, I think it would have very nice use cases
Don’t get me wrong. I really applaud the effort and it’s great. I’m just telling you why I wouldn’t use it. I’ve been building SPA’s for over a decade and have had my lessons. Things are complex for a reason when it comes to large code bases contributed to by a large team.
At a previous workspace we used pug(jade). Great language but it’s just not about the language. The tooling around the language really matters. You want linters, prettifiers, typecheckers, sourcemaps, dependency analyzers, good ide code completion, auto doc generators, etc to work with it.
Making a language with good ecosystem is really hard.
That’s why I prefer to stick to well supported proven basics.
Typescript, prettier, jsx, eslint, webpack, stylint, scss, css modules etc
Small well supported tools that do one thing really well and work with other tools. (Unix philosophy)
Side note—your site doesn’t render well on a mobile device. The whole left side of the page is cutoff. Might want to look into that.
I feel like we are approaching the problem of frontend development complexity the wrong way. These new frameworks and domain specific languages fail to cut through the complexity of the real problem and instead mask the complexity with shiny new frameworks. These frameworks still all suffer from the same problems.
There are deeper issues that need to be addressed. The fact that their landing page doesn’t work well on mobile is evidence of that. Assuming it was created using Mint.
> There are deeper issues that need to be addressed. The fact that their landing page doesn’t work well on mobile is evidence of that. Assuming it was created using Mint.
Actually it's not created in Mint and that it doesn’t work well on mobile is the evidence that I didn't tested it thoroughly :D
That's true, but those can only be addressed by the browser makers and the standard committees. It's hard, slow work that will take years to bear any fruit. Frameworks are ways to experiment with the web environment we have available to us today.
> What is wrong with Elm?
> Elm has great developer experience, but it being a purely functional language leads to some boilerplate code and makes it harder to learn. Also, it's not possible to contribute or influence the language in any meaningful way.
> To easily install Crystal on MacOSX you can use Homebrew.
I think "Crystal" should be "Mint"...
EDIT: it's been fixed now.
I didn’t like how “uncommon” Dart and Flutter were until I used them. But I’ve really come around on both after starting to use them.
This though, cool, but I see no possibility of traction.
The answers to those questions should be on your home page.
Also it would be great if you included it here: https://github.com/krausest/js-framework-benchmark
So the bundle size should be around the same as react or smaller (the compiler can output optimized code) and the performance is the same.
Why not use something faster and smaller than React though like Preact or Inferno?
https://krausest.github.io/js-framework-benchmark/current.ht...
I'm a lot more hesitant about SSR now. Users don't mind spinning wheels as long as they can see something happening.
A new language is in the perfect position to structure components so that they can be cleanly rendered on a server first, and rehydrated on the client as-needed. Trying to do that backwards will always result in less developer and user satisfaction. That doesn't mean it's right to just keep doing things the bad old way.
I don't think this is for me, but it's an interesting experiment and I could immediately grok what it was doing.
You're right the familiarity is a good thing though - just look at TypeScript!
Fair point. I think there's a tradeoff in there somewhere. The fact that you need to do things like wrap JavaScript in order to use it within Mint sets off all kinds of alarm bells for me. I still like the concept, but justifying an entirely new language (to myself, to my higher ups, to the company at large) is a high bar.
So yeah it isn't bad if it looks similar to something lots of people already use.
The first thing I thought was that it reminds me of Svelte, which I have been using and like a lot.
Like you, I'm not sure it's for me, but I also think it's interesting.
It does look like a cleaner and more convenient coding experience.
It has a similar type system (HM) nice error messages, ADTs and if you don't do JS interop then no runtime errors.
I lost interest beacuse I wanted to help/influence it's the development but my ideas weren't welcome and after two? years since then the problems are still the same without a solution in sight.
It maybe a little bit outdated but it should get the point across, also the demo seems to be offline, I'll check in the morning and get back to you :)
I'll have to try out the docker container solution, I suppose. I uninstalled the WSL a while back, and don't really want to go back down that rabbit hole.
- Mint, the Linux distro
- Mint, the web-analytics tool
- Mint, the motion controller programming language
- MiNT, old school operating system for... Atari?
What is so great about the word "Mint"?
It is English slang for something very good, very neat, very clever, very sharp.
It’s often offered as if it’s good advice and the author was somehow completely unaware that other things might share the name, or that it will make SEO hard for a thing the commenter is likely to never want to search for.
I used to keep bookmarks of these comments, but then that became my Hacker News pastime and instead of enjoying the submissions and celebrating creators and hackers, I found I spent more time looking for people complaining about the names of things, it was hell, and I was almost at name-rage catalog sobriety, until now.
Likewise, it would be more efficient to embed one of the many existing "better CSS"s than do another one.
It's sad to say so, given how much work seems to have gone into this, but it looks DOA to me.