Closed asturur closed 1 year ago
please no typescript
@jimmywarting Typescript support is one of our most commonly requested features. Feel free to elaborate if you have specific objections to adding support for it.
esm is also a desirable request, working with typescript and esm is a total nightmare. beside you can have a type safety system with vanila js + jsdoc and writing the code in such a manner that it don't require annotation... like using # instead of private, use classes instead of prototype, avoid using promise constructor and instead use async/await so the IDE can really figure out what something return and so on.
it's also possible to generate d.ts files from js also
i created https://jimmywarting.github.io/you-might-not-need-typescript/ to this end...
I think it's not necessary to migrate to Typescript, but it would be great to have up to date d.ts typings for Fabric.
i was supposed to fill up the issue text. I ll do soon. We are looking for suggestion, we are all ears and we don't have strong opinions yet.
We would like to move away from legacy js anyway.
I am for TS (gave a read to what you wrote @jimmywarting, looks interesting). IMO the disadvantage of .d.ts files is maintenance. Because it is not part of the code it can quickly become outdated and irrelevant. Personally speaking I find TS most helpful in replacing the need for docs in my workflow. My IDE suggests whatever TS has to offer and my learning curve grows exponentially because of it. Bottom line, that's what won me over, besides the trivial (great 😅) advantages. Regarding the type nightmare - I understand what you mean and I don't deny, but I would expect the pain to reduce after the first adoption phase. I can counter with my pains from js. The first that come to mind - not knowing function signatures and having to guess, remember them or log arguments if the above fails. Or some minor typo that breaks my code and an error that sends me to a wild goose chase after the wrong thing. Is JSDOC typedef visible outside of it's file/module? If not it is an absolute killer to any kind of js typings. From the maintainer point of view I think it cuts down Q&A as well. So I'm for. I do think that a simple configuration file (tsconfig.json) in a project can silence ts for a dev that doesn't want it. And it is the standard as far as I can tell (saw many large repros migrate to ts, including google open source). I think that when considering this move we should try to foresee what is right for 1-2 years ahead, not only for today. In other words, we need to think what is best for fabric in the long term (and hopefully the short as well). I would like fabric to be easy. Easy to use, easy to learn, easy to plug and play, easy to contribute to, easy to maintain. That's what I want to achieve from the migration.
IMO the disadvantage of .d.ts files is maintenance. Because it is not part of the code it can quickly become outdated and irrelevant.
this can be auto generated durning release...
I think that when considering this move we should try to foresee what is right for 1-2 years ahead, not only for today.
what would you think could happen when optional static typing comes into play? typescript will become obsolete.
saw many large repros migrate to ts
just b/c big companies did it dosen't mean it's better than one or the other, it just comes to a preferences and the developers background (like coming from c, rust, go or any other typed language)
there are ppl who have ditched typescript and went back to vanilla js afterwards (even in big companies too)
For me it feels like typescript are trying to fit a square into a circle, javascript is a dynamic language, and it's nothing wrong with that, it can be a positive thing also...
there are ways to write the code in such a way that auto completion and annotation isn't necessary from either jsdoc or typescript also. The public/private keyword and explicit return type for example are not needed, they are unnecessary, even for typescript. the only time you really need to explicit say what something returns is if you do something like:
function sleepFoo() {
return new Promise(rs => {
setTimeout(() => {
rs('bar')
}, 100)
})
}
which don't have to be annotated at all if you did:
async function sleepFoo() {
await sleep(100)
return 'bar'
}
beside typescript don't do any type protection after you compile it to js. ppl can still make mistake afterwards. typescript only provide type hints/error upfront durning developing. And there is going to be ppl that don't use typescript at all
@asturur will you also move away from supporting Legacy JS entirely & only support TypeScript and/or ECMAScript Modules?
Based on my experience, most of the projects can be migrated to TS with minimal effort (obviously, the types will not be very strict, some compromises will take place), but it's a proper foundation to improve these types in future.
TS can work even w/o types as plain JS, types can be introduced function by function, file by file.
Additionally, w/o TS project will have to support custom .d.ts files, which is a nightmare, it's much easier to convert code to TS and generate .d.ts automatically.
I am for TS too, because:
fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray)
createClass
method sometimes misleading people(ES 6 class looks more explicity), it hard to know which method should be implemented or overrided(the underscore method or not or both?)
var MyClass = fabric.util.createClass(fabric.Object, {
bar: [], // dont't do this
initialize: function () {},
})
var c1 = new MyClass()
c1.bar.push(1)
var c2 = new MyClass()
console.log(c2.bar) // => [1]
var MyClass = fabric.util.createClass(fabric.Object, { initialize: function () { this.bar = [] // do this instead }, }) var c1 = new MyClass() c1.bar.push(1) var c2 = new MyClass() console.log(c2.bar) // => []
3. there are some global variables in fabric namespace, which is hard to find(you have to read the source code to find it), with TS, just give me a interface, problem solved.
```js
fabric.disableStyleCopyPaste
fabric.copiedText
fabric.Control
class is a absolute beautiful abstraction for object transform action, but when i involved in this part of code, it's hard to find where i am.I updated the description. Probably the best option is to maybe convert a non working example of a class, to see how does it looks like in modern JS and TS. Maybe RECT that is a quick one.
I'm for vanilla JS, because we finally have decent traction on modern features being implemented in ES. Looking at the long-term, I feel it would be better for FabricJS to stay with a maturing vanilla JS because many new features on the roadmap will make TS irrelevant anyway.
If we were having this discussion a half a decade ago, I would have been all for TypeScript.
Colleagues, main point about Typescript is it’s strong and flexible type system. No vanilla js (even with jsdoc) gives true type checking during compilation time. In all my JS projects migrated to TS, type checks found a number of potential issues that were overlooked.
Second reason is DTS (definition) files. Since we’re talking about library development, TS is a de facto standard. Definitions must be produced in any case, if we target large audience, which includes other TS projects.
Definitions on top of JS tend to have errors, mismatches and discrepancies, and require a lot of manual maintenance. Of course one can generate dts from jsdoc, but this will not do type checking… and in case JSDoc has issues those issues will silently leak into DTS, which means more maintenance efforts.
Third, TS is mature tool, with huge community, it’s safe and proven. Vanilla JS is catching up, it’s still years behind TS in terms of features. And even when it will catch up, vanilla won’t have types anyway, which brings us back to previous points.
PS. I forgot to mention, that most IDE are able to infer TS types even when they are not explicitly defined. TS compiler can do that too. This means less things to write, less things to support which in turn means less things that can go wrong.
I don't consider any compile to js a "standard" language... It don't run anywhere without being compiled to js in the first place
It is built on top of standard js
I like buildless setup a lot It loads so insanely fast 🚀 Having esm would be cool too
Only time when i actually use any build tool is if I need to down level anything for older environments
But all browser basically have auto update now and IIE it's pretty dead...
which are the functions of TS that are better than JS, types apart? i thought where identical. I wonder if we can get best of bot, we write in ts, and we can build into plain js and bundled legacy js
I wonder if we can get best of both, we write in TS, and we can build into plain JS and bundled legacy JS
The only way you are going to get both of both world is if you write in JS and turn on checkJS to utilize all TypeScript features, you may even use typescript to bundle to legacy js form plain js jsdoc can do type checking
VScode has a nice interfear type from usage that helps u fill in the jsdoc when necessary, you can write interfaces (typedef) and import them with jsdoc as well...
yes my initial idea was that strong jsdoc could generate d.ts files. But i never found a proper tool to do it.
Isn't TS with ripped types just plain JS?
There must be an option for the compiler, don't touch js
no?
ok let's start to check checkJS
Isn't TS with ripped types just plain JS?
not when you have target set to like some very old environment, it's always going to do some form of transformation to your code. 1000 of developers think they write es syntax with their extension-less imports but the reality is that it most often is compiled to cjs, the lack of extension create wasteful IO time to look for the correct file...
There must be an option for the compiler, don't touch js no?
alloJS? ignore, exclude, include... something something
@jimmywarting Your point "annoying sourcemaps, extra compile time, bloated code that looks nowhere near the actual input" contradicts with your other point "target set to like some very old environment, it's always going to do some form of transformation to your code" — you can't publish raw ESM code.
"all browser basically have auto update now and IE it's pretty dead" — Random old browsers still exist in corporate sector, where auto update may be turned off... Also don't forget government sector. You still have to compile CJS and maybe even ES5. Obviously we should not target IE6 or IE7, but only targeting latest Chrome is another extreme.
Fabric is a very popular lib, most popular based on stars, it cannot throw away compatibility, so there WILL be a build/compile script, one or the other.
Competition is tough...
VSCode does have a good support for JSDoc, but I've never seen a reliable tool to check JSDoc types on CI, whereas TS compiler will do it during the build as normal part of CI process.
@asturur wrote:
which are the functions of TS that are better than JS, types apart? i thought where identical. I wonder if we can get best of bot, we write in ts, and we can build into plain js and bundled legacy js Isn't TS with ripped types just plain JS?"
This is true, for the most part JS now is TS without types, except a few features like decorators (which Fabric may use as strong-typed mixin replacement). When TS is used you get types for free, DTS for external consumption.
you can't publish raw ESM code.
I could if i wanted to. I can code and develop in raw ESM, making sure it run just fine in latest chrome and maybe firefox, without having to compile anything.
And when i want to make a release then i can run some test that builds some UMD, test it in several browsers and releases both ESM (maybe as is - for those who wish to simply import()
it) and also release the UMD version for the rest.
it's possible to use webpack, rollup or tsc or whatever.
@jimmywarting
I could if i wanted to. I can code and develop in raw ESM, making sure it run just fine in latest chrome and maybe firefox, without having to compile anything. And when i want to make a release then i can run some test that builds some UMD
Yeah, you can do that, but you trade compilation time during dev at expense of testing and verification time. And again, you won't have to support DTS files separately... It's always a tradeoff. So unless you actually ship raw ESM I don't see practical benefits. I advocate for "Eating your own dog food" to be sure I am seeing what others will see, as close as it can be. And as early as I can, ideally during development, not verification.
Compilation time in watch mode of a library the size of fabric is few seconds. It's not a big deal. But then during development you can be sure the code you see is exactly what will be shipped.
To me, when you develop a LIBRARY — TS is a no brainer choice. When you develop an APP — your approach may be OK.
Also there are rust (SWC) or Go (esbuild) based compilers that are even faster than regular TSC/Babel/Rollup/etc., and looks like it's the general direction where industry is moving, Next.js used to be a JS project, and they did full transition to TS, it's just one example... overall the trend is towards TS in lib development.
Overall the choice should be based on if team will be able to deliver faster and better quality with TS or with JS + custom DTS. From my experience in multiple teams and products, TS helps to speed up overall delivery if all factors are considered (development, dev experience, CI, QA, support).
I think it is clear that fabric should not and cannot deal with the build process. It is unwise, to say the least, and a damn waste of effort. The effort should be targeted towards fabric and making it awesome. Let everyone do what they do best. And of course fabric must use a liable mechanism, no alpha/beta products. Too much headache in something that no one should have to manage except the occasional ci config. The patience to except alpha/beta and the occasional break/bug is ONLY intended for fabric features. We cannot abuse that. Already I argue it is abused with no need. I mean to say the decision needs to be mainstream. And it MUST make this repo easier and readable! Because it isn't! I am an expert in fabric internals not because I want too. But because I had no choice but to dig in the source code and break my head against it. What other choice is there today?? Why should anyone want to work with a repo that demands so much just to get some minor customization working? It's too hard, messy, horrible DX. The point is taking fabric forward, not drowning it with more noise.
Yes but indeed there would be 2 targets eventually. One to get modern JS out of TS, another to have the standard browser ready lib
I think it is clear that fabric should not and cannot deal with the build process. It is unwise, to say the least, and a damn waste of effort.
Well we don't get away without publishing a ready to consume module. Is what npm user expect. You don't build stuff that is in your node_modules folder usually. You expect it to be ready to use. If you want to use the modules right away you usually import them from the src directory. There is not just a single way to do things of course, but i m sure we have to build.
Types would be amazing whether provided by declaration files or an actual Typescript port.
https://jimmywarting.github.io/you-might-not-need-typescript/ is interesting, and does make valid points. However, here I stand in a sea of Typescript projects wanting more Typescript :-)
I think it is clear that fabric should not and cannot deal with the build process. It is unwise, to say the least, and a damn waste of effort.
Well we don't get away without publishing a ready to consume module. Is what npm user expect. You don't build stuff that is in your node_modules folder usually. You expect it to be ready to use. If you want to use the modules right away you usually import them from the src directory. There is not just a single way to do things of course, but i m sure we have to build.
Sure, we have to build. But with minimum effort. Let the build tool do all the work, that's what I was aiming to stress.
I think building is something we should avoid for Fabric. But we can definitely move towards ESM. I would not use TS, instead of it I'd create a d.ts files and add typings through JSDoc if needed.
For what it's worth, I want to voice my thoughts:
jsdom
bump from v15 to v19. v15 chains to a lot of outdated dependenciesrollup
config (but other build utils can also easily be made to do this): https://github.com/twbs/bootstrap/blob/main/package.json#L40-L42They do not provide their own TS definitions, they are maintained separately here
I worked a lot with this project. Separate declaration is one of the reasons why bugs occur because of discrepancies. And a need to do coordinated merges, which is painful. It is a very bad approach. Types should be shipped along with library.
The resulting compiled JS is committed to git when they do a release
This is also considered as bad practice, build artifacts should not be part of version-controlled repo because it leads to horrific merge conflicts.
Here's an example that illustrates why Fabric has to be written in TS:
http://fabricjs.com/docs/fabric.Object.html#forEachControl
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/fabric/fabric-impl.d.ts — does not even mention this method forEachControl
And I doubt JSDOC to TS types generator will be a good solution: it is awkward and does not give all benefits that TS can provide.
@kirill-konshin I have a huge patch file of types for fabric on top of the npm types module. I agree it is bad.
i posted on defintely typed if someone wanted to help build official d.ts file to keep here, but i got no one to volunteer. i m all for types comeing from here, the only thing at stake is between full TS and JS + .d.ts
@folknor release 5.0 is around the corner. I'm looking for the small last fixes to pull in.
see the ts proto - very simple, nothing fancy, minimal effort (promises included with a bit of a more advanced type related to the function), proper js class: https://github.com/ShaMan123/fabric.js/blob/ts-proto/src/shapes/Rect.ts
run npx tsc
or npm run tsc
after you've updated dev deps. It will output a readable js file next to the ts one.
Give it a go.
I'm also for TS. Most of the things I wanted to say to @jimmywarting's arguments @kirill-konshin already said it. And I'll gladly help if you decide to migrate to TS.
My main concern currently is that there is no tree shaking or real modules. For the TS/ES6/Plain or whatever point, we have babel so there is no reason to not just write everything the way @asturur and the other maintainers want. But still, will give +1 for TS because this will help everybody in the long way.
With those changes we would have proper modules, and custom build would go away.
Whatever you will decide, let the contributors know how we can help in getting things done - I think there are quite a bunch of people willing to help for this transition.
So for example, help me figuring out, what is the best transpiler for library? i work on apps and there webpack + babel is a standard, but i don't think is for libraries. Can TS do transpilation and bundling all together?
I'm using webpack to build a library which bundles current fabricjs and our custom vuejs code - so this is doable. But I think there is a lot going on with esbundle, swc, parcel etc. currently which might be a better solution. Maybe someone with more experience can chime in here and make a good proposal what bundler solution is the best for fabric.
You can use TSC compiler to build the library.
If you want to also publish the final build like this one https://cdn.jsdelivr.net/gh/fabricjs/fabric.js@vv6/dist/fabric.js you can do an extra step and compile it using Webpack with SWC loader (which is the fastest way to compile TS without types, since you don't need types in Webpack bundle).
Here's how I did it long time ago: https://github.com/ringcentral/ringcentral-js/blob/master/sdk/package.json
3 builds: ES5 for oldies, ES6 with tree-shaking for modern tools, UMD (webpack) for direct consumption.
I'm also using fabric in the project I'm at currently, and personally, would love to see typescript used. Especially since now, I'm investigating some internal issue that feels like a race condition causing some of the variables being undefined when being accessed
I personally also would love to see TS support. I have made a few (small) contributions to this repo and I found it quite hard to navigate the codebase without reliable signatures for complex methods. And it would really be my pleasure to help migrate to TS if there's anything you need 🙂
I'm definitely down to help work on the migration too; I just found a pretty big discrepancy between the DefinitelyTyped types and the actual lib, and so I think that migrating to TS would be pretty awesome.
So the question is, how do we want to approach this? Should we first use a tool to generate initial types and slowly fill stuff in from there?
Also, what should we do about the "Klass" stuff? Do we want to gut that and replace it with real modern classes?
So the question is, how do we want to approach this? Should we first use a tool to generate initial types and slowly fill stuff in from there?
Any experience with reliable tools?
Also, what should we do about the "Klass" stuff? Do we want to gut that and replace it with real modern classes?
Absolutely! We have been preparing fabric for it (#3684 )
Any experience with reliable tools?
Unfortunately no. I'm going to do some research to see what's available. Ideally a tool to add simple types like string
, bool
, etc. Manual typing could be done for the fabric objects. I'm planning on creating a branch with the basic types added from whatever tool I end up using and then going from there.
Hello everyone!
FabricJS is nearly 12 years old.
The library has still its place around the internet, is good for many things, is never perfect, but i know that for who approach rich canvas based interactive apps, this is a nice piece of software to leverage.
While our main fault are still lack of great docs and updated and clarifying examples, now also the javascript code looks like a lot obsolete.
There are things we could leverage like Promises, default value for arguments, fat arrow for loops and readibility, native classes, proper getters and setters.
We would like to take the occasion to revisit the shape of the codebase to something more modern. This would include proably a bundler, proper import statements instead of a single file that gets built like lego blocks, maybe tree shaking for who import just what he wants to import.
This would make the custom built unnecessary, using other libraries easier including touch interactions.
So a move to es201X is coming anyway.
The question is if we want to add type descriptors or if we want to make a TS migration right away.
The benefits of consuming TS are clear to me, the benefit of writing typescript a little less, i'm not a great fan and also i m not great a TS. Is very easy to use TS in the wrong way and produce subpar results.
We are open to suggestions and understand what is the best way to make everyone happy. external type definition in form of d.ts files are a good middle way if there is a way to enforce correctness at build time. A new lint profile is required. A new build tool too. Legacy JS support is not going away. A bundler will produce the correct code for older browsers. But probably IE11 is out of the game anyway. I would love to have 2 builds, a legacy one and a modern one ( the classic last 2 versions of each browser )
So which are your reason to list TS on the pro/cons of this change? I understand you may not like TS. that is fine. I don't like it either. But if is terse, with types out of the way, and a transpiled build is available, what is your main point against or for it?