
Show HN: cookies.js, making cookies a delight to work with on the front-end - franciscop
https://github.com/franciscop/cookies.js
======
ianstormtaylor
Congrats on shipping it!

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.

~~~
niftich
I think you raise a good point, but when has this been the package manager's
concern?

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?

~~~
ianstormtaylor
Yup, I don't think any package manager has ever really done 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.

------
izolate
Good work, but I prefer the syntax of cookies-js [1]

Side note, Bower is a dying package manager. You'd get better results if you
promoted the npm link over bower.

[1] [https://www.npmjs.com/package/cookies-
js](https://www.npmjs.com/package/cookies-js)

~~~
berdario
Bower is definitely not dying, and in fact Npm is totally unsuited for some
communities

[http://harry.garrood.me/blog/purescript-why-
bower/](http://harry.garrood.me/blog/purescript-why-bower/)

~~~
joshwcomeau
[https://www.google.com/trends/explore?q=bower,npm](https://www.google.com/trends/explore?q=bower,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.

------
niftich
Cool submission!

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.

[1]
[https://tools.ietf.org/html/rfc2616#section-2.2](https://tools.ietf.org/html/rfc2616#section-2.2)

[2]
[https://tools.ietf.org/html/rfc7230#section-3.2.6](https://tools.ietf.org/html/rfc7230#section-3.2.6)

~~~
franciscop
I URL-Encode it:

    
    
        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).

~~~
niftich
I did more research and have a further follow-up. According to MDN [1],
encodeURIComponent escapes all characters except the following:

    
    
      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...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent)

------
brian_herman
This reminds me of jquery-cookie which was replaced by js-cookie.
[https://github.com/js-cookie/js-cookie](https://github.com/js-cookie/js-
cookie)

~~~
franciscop
Yes, after the initial simple version, when I thought of expanding it, I
looked into js-cookie and Cookies [1], but they all seem to require a `.set()`
and `.get()` methods which I find too verbose for something so simple. A
couple more of differences:

\- 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.

[1]
[https://github.com/ScottHamper/Cookies](https://github.com/ScottHamper/Cookies)

------
keeperofdakeys
It would be interesting if you adapted this to use the WebStorage api.
[https://developer.mozilla.org/en-
US/docs/Web/API/Web_Storage...](https://developer.mozilla.org/en-
US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API)

------
TheAceOfHearts
Someone already mentioned js-cookie [0], but they didn't mention that it
supports legacy browsers! If you're tied down supporting old IE, it's a great
choice.

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.

[0] [https://github.com/js-cookie/js-cookie](https://github.com/js-cookie/js-
cookie)

------
throwaway2016a
Obligatory old man rant/question... why does software development need to be
delightful? I just need it to work and not get in my way. I have other things
I can do in my life that are delightful, like reading a good book or watching
my kid's first steps.

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.

~~~
6DM
It could be argued that if it "just works" and is not in your way that it
feels delightful to program with :)

~~~
franciscop
That was totally my original meaning; sensible defaults, easy options and just
a simple function to work with makes me want to keep using a library all day.
So I try to follow that when writing a new library when I'm not comfortable
with the status quo.

------
abimaelmartell
This feels so wrong....

    
    
        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
        });

~~~
SamBam
Why? It looks pretty standard to me. It uses named variables for options,
instead of argument position, and has reasonable defaults, so you don't have
to specify every option.

This is the standard, modern way of added options to a function.

------
matthewhall
No one should ever use cookies! You should use local storage, and only send
what you need to the server and only when you need it

~~~
todd3834
There are situations where cookies make more sense. Local storage gives you
less control on the origin where that data can be accessed. Local storage
doesn't let you set things such has HttpOnly so that JavaScript can not access
the data (this is important to limit the risk of XSS when dealing with session
ids). Local storage also doesn't give you as much control over when data
should expire.

~~~
aikah
Sure but here we're talking about javascript cookies that aren't htttpOnly or
secure. The expiration date and broad compatibility are the only arguments for
the use of js cookies.

~~~
todd3834
and the `path` attribute which allows you to control where a cookie should be
used within the same origin.

------
yefim
How does this compare to Express's cookie parser
([https://github.com/expressjs/cookie-
parser](https://github.com/expressjs/cookie-parser)) which relies on cookie
([https://github.com/jshttp/cookie](https://github.com/jshttp/cookie)) for
parsing?

~~~
franciscop
> "Interactive and easy cookies from your browser in javascript"

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

