What is New in Version 1.0
Today marks the release of isomorphic-git version 1.0! 🎉 There are a lot of big improvements to celebrate.
- Better IDE Integration
- Better TypeScript Integration
- More Good Defaults, Fewer Bad Defaults
- Embrace Callbacks
- Future-proof API
- Acknowledgments
- 1.0 Breaking Changes
Better IDE Integration
No longer must we maintain the index.d.ts
file by hand!
Thanks to improvements in TS 3.7, we can auto-generate the declaration file using tsc --declaration --allowJs
.
This has the added benefit that the JSDoc is also included in the index.d.ts
which leads to a much richer IDE integration. Sadly, parameter descriptions still aren't shown, but the main description body and the example code are!
Here's what the Visual Studio Code tooltip for git.log
looked like before:
And here's what it looks like in version 1.0:
The functions themselves have been tweaked so that the core object interfaces (CommitObject
, TreeEntry
, TagObject
, etc) are reused wherever possible,
so that all the functions feel consistent and there are no surprises.
The result is a cleaner API where the documentation comes to you, right where you are.
Better TypeScript Integration
The return types gel with TS better now. For example, readObject
returns a "discriminated union" type, so you can take advantage of powerful type inference, like this:
Exceptions are also well-typed now, so you can access their .data
property with confidence:
More Good Defaults, Fewer Bad Defaults
A number of helpful behaviors that had to be opt-in before to preserve backwards compatibility are now the defaults.
- The
init
function doesn't overwrite your config file if it already exists. - The
checkout
function now warns about conflicts instead of blindly overwriting files. - The
commit
function doesn't silently remove submodules.
:shudder: You live, you learn, amirite?
A number of "helpful" default behaviors have been removed, because no default is better than a bad default:
A big one was assuming if you if you used the ESM build you were in the browser and had access to fetch
and if you used the CommonJS build you were in node.
That simply isn't true in today's environment.
In version 1.0, you are always in control of whether to use http/web
or http/node
.
Another one was automatically appending .git
to the end of URLs when you clone them. That can be helpful, but it can also completely break cloning for some servers, which led to the awkward addition of the noGitSuffix
parameter (cringe).
In version 1.0, the URL you give is the URL we GET.
Embrace Callbacks
Something I tried to do early-ish in the development of 0.x was to move towards this idea that all function arguments need to be serializable. My reasoning was this:
- isomorphic-git can be pretty slow and block the main thread.
- I should encourage everyone to use isomorphic-git in a Worker.
- Therefore, I should make it easy to wrap isomorphic-git in a postMessage / RPC interface.
This led to the creation of magic-portal
and publishing the WebWorker Guide.
It also was the main constraint driving the design of the plugin system.
The idea was all the callbacks could be setup in one place.
However, since that time I have grown a tad wiser. In building real-world applications with isomorphic-git, I've realized:
- All code can be pretty slow and block the main thread.
- Therefore all the code that uses isomorphic-git should be in that Worker too.
- In that case, isomorphic-git doesn't need serializable arguments at all.
Therefore the plugin system and its awkward global state and funky namespace "cores" are gone, replaced by a vastly simpler collection of callback arguments. The new code is safer, has better locality when you're reading it, and enables some cool new behaviors like canceling running functions and infinite retry for interactive authentication.
Future-proof API
A number of other changes, such as returning Uint8Array
instead of Buffer
, were done to pave the way for future refactoring.
The size of the library can be shrunk significantly if we drop the Buffer
polyfill dependency.
Plus, Webpack 5 reportedly won't provide node polyfills automatically.
As always, all the functions are async
and take named arguments, which makes adding new features without breaking old ones easy! I'm a huge fan of this pattern, and I think it's been very successful.
It is safe to say that the API for isomorphic-git will remain backwards compatible and have no breaking changes for at least a year, possibly two or three.
Because I want you to always be able to upgrade to the latest and greatest version of isomorphic-git
without having to change any of your code.
Except for today. Today, we are making breaking changes because it is a major release.
Acknowledgments
A HUGE THANK YOU to everyone who used isomorphic-git 0.x. You've been tremendously helpful, and you early adopters have helped make this project of mine fun and fulfilling!
And an even bigger thanks to everyone who contributed directly! Seeing other people help improve the codebase has warmed my heart. And seeing your bug reports at least lets me know it is getting lots of use!
I'd like to thank a couple corporations, particularly Cardstack, CleverCloud, and OpenDevise.
Lastly, I'd like to thank Stoplight, Inc for hiring me and letting me work on isomorphic-git occasionally as part of my regular day job! Everyone has benefitted from the bugfixes, perf, and usability enhancements that have resulted from our using isomorphic-git in our world-class API designer, Stoplight Studio.
1.0 Breaking Changes
Big changes
- The supported node & browser versions have been bumped. (See beautiful table above.)
- The plugin system has been eliminated and we're back to plain old dependency injection via function arguments! The plugin cores created a mysterious "global state" that makes it easy to trip up (I myself sometimes forgot to unset plugins after running tests). The old style of passing
fs
as a function argument was less aesthetic and more verbose, but it is a much simpler model than the plugin core model, and much safer because it makes it impossible for dependencies to accidentally share the default plugin core.- The
emitter
plugin has been replaced withonMessage
andonProgress
callbacks. - The
credentialManager
plugin has been replaced withonAuth
,onAuthFailure
andonAuthSuccess
callbacks - The
fs
plugin has been replaced with anfs
parameter. - The
http
plugin has been replaced with anhttp
parameter. - The
pgp
plugin has been replaced with anonSign
callback.
- The
- There is an additional setup step to choose which
http
client to use, and functions that make HTTP requests have a new requiredhttp
parameter. Previously I used a mix of bundler and runtime magic to try and pick between a build that usedfetch
and one that usedrequire('http')
but that didn't always work. For instance, if you were bundling a node application using Webpack, it would pick the wrong build (#938). Another example: in an Electron renderer thread, both options could work (if the window is launched withnodeIntegration: true
) but in a Web Worker thread only the fetch option should work (unless you havenodeIntegrationInWorker: true
set). See "Getting Started" below to see the extra line of code you need. - The files in the package have been renamed so the import paths are short and sweet:
dist/bundle.umd.min.js
->index.umd.min.js
dist/for-future/isomorphic-git/index.js
->index.js
(the future has arrived)dist/for-node/isomorphic-git/index.js
->index.cjs
Some functions have been renamed or removed:
- The
walkBeta2
function was renamed towalk
. - The
walkBeta1
function was removed. - The
fastCheckout
function has been renamedcheckout
and the oldcheckout
has been removed. - The (previously deprecated)
sign
function was removed. - The (previously deprecated)
utils.auth
function was removed. - The (previously deprecated)
utils.oauth2
was removed. - The
config
function has been removed and replaced bygetConfig
,getConfigAll
, andsetConfig
. - The
verify
function has been removed, butlog
,readCommit
, andreadTag
all return thegpgsig
and signingpayload
now. This actually makes verification simpler and more efficient, because it can be done in batch ongit.log
output and thegpgsig
itself can be parsed and used to lookup the public key. See onSign for complete code examples.
Some function parameters have been removed or replaced:
- The undocumented parameter aliases
authUsername
andauthPassword
were removed. - The
emitter
parameter was removed and replaced with theonMessage
andonProgress
callbacks. (Note thatonMessage
emits un-trimmed strings, so you get those\r
s.) - The
username
,password
,token
, andoauth2format
parameters were removed and replaced with theonAuth
callback. - The
fast
parameter ofpull
was removed, since there is no "slow" implementation anymore. - The
signing
parameter oflog
was removed, sincelog
will always return a payload. - The
pattern
parameter was removed fromstatusMatrix
and replaced with a newfilter
function. (This is so we can drop the dependencies onglobalyzer
andglobrex
.) - The
newSubmoduleBehavior
parameter was removed and is now the default and only behavior, because it makes much more sense to have non-destructive defaults! - The
noSubmodules
parameter was removed because with the new submodule behavior it is no longer necessary to print console warnings about how submodules aren't supported. (When submodule support IS added to isomorphic-git, it will be opt-in usingrecurseSubmodules: true
or something like that.) - The
autoTranslateSSH
feature was removed, since it is trivial to implement your own version using just theUnknownTransportError.data.suggestion
- The
writeObject
function when used to write a tree now expects a plain array rather than an object with a property calledentries
which is the array. (This is so that argument towriteObject
has the same shape as the arguments towriteBlob
/writeCommit
/writeTag
/writeTree
.) - The
noOverwrite
parameter was removed frominit
and is the new behavior. - The
author.date
,committer.date
,tagger.date
parameters were removed in favor ofauthor.timestamp
,committer.timestamp
,tagger.timestamp
in order to be clear about what is actually written and share the same shape as the return types inreadCommit
,log
, andreadTag
.
The return types of some functions have changed:
- Functions that used to return
Buffer
objects now returnUint8Array
objects. (This is so we can eventually remove all internal dependencies on the Buffer browser polyfill, which is quite heavy!) - The
log
function now returns an array of the same kind of objects thatreadCommit
returns. (This change simplifies the type signature oflog
so we don't need function overloading; that function overloading was the one thing preventing me from auto-generatingindex.d.ts
.) - The
readObject
function returns a proper discriminated union so TypeScript can infer the type of.object
once you establish the value of.format
and.type
. Also.object
has the same shape as as the return value ofreadBlob
/readCommit
/readTag
/readTree
. (Meaning trees are now plain arrays rather than objects with a.entries
property that is the array.)
Some function behaviors have changed
- The
push
function now pushes to the remote tracking branch (rather than a branch with the same name) by default.
Docs and DX improvements
- The
docs/alphabetic.md
and function list inREADME.md
are auto-generated from the filenames insrc/api
. - Nearly the entire docs website is auto-generated from the JSDoc actually so keeping the docs website and source code in sync is easier.
- All the example code in JSDoc is now type-checked during CI tests.
- The live code examples on the website are displayed in a full-blown mobile-friendly code editor (CodeMirror 6).
- Each page with live code examples includes a code snippet at the bottom to reset the browser file system.
- The Getting Started guide has been updated.
- All the example code in JSDoc has been updated.
Miscellaneous stuff
- Update the README to recommend LightningFS rather than BrowserFS.
- The
internal-apis
bundle is no longer included in the published package. That was only being built to run the unit tests.