Show HN: cookies.js, making cookies a delight to work with on the front-end
github.com
github.com
This got me thinking about what the existing cookie libraries looked like in npm, since I figured it was a solved problem already, potentially even with the exact same API.
There are a lot of cookie libraries for the browser in npm! Here are the ones I found, grouped by what syntax they end up implementing, and showing their current downloads per month...
Using the .get() .set() .remove() syntax:
js-cookie (141,938)
cookies-js (36,319)
cookie-cutter (8,848)
cookie-monster (7,457)
client-cookies (216)
cookie-browser (198)
cookie-handler (118)
juicy-cookie (115)
cookies-es5 (109)
cookie.js (84)
mmm-cookies (41)
cookie-crisp (60)
easy-cookies (13)
Using the Web Storage syntax: cookie-storage (1,101)
mozilla-doc-cookies (491)
cookiestorage (27)
Using the almost-Web-Storage syntax: oven (111)
Using the `(get, set) syntax: component-cookie (7,360)
cookee (1,568)
Using your syntax: cookiesjs (49)
I think it's a good example of npm's problem as a search engine for packages. Realistically all of these libraries have the same goal, and probably achieve it equally well. A few have better browser support, a few have better docs, a few have better tests, etc.No one should be prevented from creating and publishing whatever they want as a library.
But npm should be doing a much, much, much better job at pointing people towards the popular libraries. It takes a lot of work to figure out what cookie libraries to use. Or what snake-case library to use. When it really shouldn't. You could easily eliminate most of these libraries with a few simple metadata checks. And I think it's incredibly unfortunate that npm isn't pushing people in that direction.
When I type in 'dnf search' or 'apt-get install' or 'pip search' or the equivalent, I don't get details, I just get a list of packages, one of whose title or description fields match what I pass on the command-line. A package's exported API is important (obviously, since without it you can't use it), but I'm not entirely sure the package manager is the best place to surface this information. Or maybe it should be, but no package manager so far does this well?
But what makes the problem worse is that npm advocates using lots of small modules, and using them in an environment (the browser) where duplication weight has big negative consequences.
I think there's a real opportunity to unseat npm if someone applied to same kind of UX-first thinking to package management that has been applied to other areas.
Even just downloads/month on the search results screen would be helpful, as well as repo link... I usually look at downloads and gh issues as the canary for health, which is usually a good indicator.
Side note, Bower is a dying package manager. You'd get better results if you promoted the npm link over bower.
Other reason: the syntax is more explicit, and already familiar to anybody who has used Maps [1]
I find your syntax a little confusing. It's not immediately obvious how I would set multiple cookies with different options, for instance.
[1] https://developer.mozilla.org/en/docs/Web/JavaScript/Referen...
I see, you could just call the same function few times with different options (preferred) as cookies(cookie1, opt1); cookies(cookie2, opt2); or concatenate them: cookies(cookie1, opt1)(cookie2, opt2); but this is arguably really strange syntax.
I will add more examples to the readme.md to make it more clear :+1:
There are better alternatives available (NPM/PostCSS/vanilla.js to the above)
Anyway, I didn't really intend this library to be in-the-loop. I just did it because I couldn't find one I liked in 2016. Which is just nuts on itself. so I went all old-school and tried to keep cross-browser support high and make it simple. It took an hour to be done and a couple of them to test and document it (plus another couple of them for small details such as CDN, bugs/patchs/small features).
I prefer my screwdriver, that I have to open with another screwdriver.
When you use two distinct dependencies that subsequently have the same dependency but separate major releases, you may encounter breakage.
The author simply prefers Bower because of how it handles this problem differently than npm.
"Dying" is a bit strong, but there's no question that NPM is becoming the go-to choice for javascript development across the stack.
Per RFC 6265, which is the cookie spec you seem to use, the valid chars for cookie names is defined [1] by RFC 2616 (since obsoleted by the 723x series; but agreeing on this issue [2]).
The cookie name must be a 'token', which is incidentally the exact same rule as for HTTP header names. 'token' evaluates to one or more of the following ASCII visible characters:
"!" / "#" / "$" / "%" / "&" / "'" / "*"
/ "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/ DIGIT (0-9) / ALPHA (A-Z, a-z)
Right now you allow any valid JSON object key to be set as a cookie name.EDIT: To be more precise, your defaults are fine as they URLencode the key too, along with the value. But the defaults are overridable and affect both the cookie key and value simultaneously. Allowing the value encoding to be overridden would be useful, while allowing the name encoding to be overridden can cause the cookie to fall out of spec.
var res = opt.encode(key) + '=' + encoded + ...
Where `opt.encode()` is defined as: function (val) {
return encodeURIComponent(val);
}
But from your comment I understand that this is not enough and I should dig deeper into this (though I find the RFC really dense/difficult to read). alphabetic, decimal digits, - _ . ! ~ * ' ( )
which means that out of the allowed ASCII characters in a cookie name: "!" / "#" / "$" / "%" / "&" / "'" / "*"
/ "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/ DIGIT (0-9) / ALPHA (A-Z, a-z)
the following matrix of behaviors results: Gets-Encoded? Is-Allowed? Current-Behavior
-----------------------------------------------------
! not-encoded allowed behavior-OK
# encoded allowed unnecessarily-encoded
$ encoded allowed unnecessarily-encoded
% encoded allowed unnecessarily-encoded
& encoded allowed unnecessarily-encoded
' not-encoded allowed behavior-OK
* not-encoded allowed behavior-OK
+ encoded allowed unnecessarily-encoded
- not-encoded allowed behavior-OK
. not-encoded allowed behavior-OK
^ encoded allowed unnecessarily-encoded
_ not-encoded allowed behavior-OK
` encoded allowed unnecessarily-encoded
| encoded allowed unnecessarily-encoded
~ not-encoded allowed unnecessarily-encoded
( not-encoded not-allowed invalid-must-encode
) not-encoded not-allowed invalid-must-encode
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...I see, so I could add a `cookies.encodevalue()` and default it to `cookies.encode`. However, I think that'd just add too much noise to it so I will just add a warning. Thank you.
- I just added a CDN to cookies.js
- The default is a 100-day cookie, as cookies for me imply long-lived cookies, not sessions.
- The default is that if you visit `https`, it will require secure connection.
- [configurable] to remove a cookie you can just null-ify it.
I've used both js-cookie and cookies-js, and ultimately ended up going with js-cookie. Unfortunately, I don't remember the reason why js-cookie won me over; I think I encountered some issue with cookies-js.
Edit: I'm sorry, that came off with a lot extra snark and not nearly as much joking as I was intending. I'm happy that people find working with cookies delightful.
[1] well that was the intention, obviously it didn't come off that way.
cookies({ token: '42' }, {
expires: 100 * 24 * 3600, // The time to expire in seconds
domain: false, // The domain for the cookie
path: '/', // The path for the cookie
secure: https ? true : false // Require the use of https
});I actually quite like it because you can manipulate each portion of the string separetely, vs.
token: 42; expires: 8640000; path=/; secureThis is the standard, modern way of added options to a function.
It is a front-end package, not a Node.js package. I am totally happy with the state-of-the-art Node.js cookie parsing