Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate package/source to ES module(s) #537

Merged
merged 17 commits into from Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
@@ -1,4 +1,4 @@
node_modules
build
dist
.sizecache.json
*.log*
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Expand Up @@ -13,7 +13,7 @@
### Tools
We use the following tools for development:

- [Qunit](http://qunitjs.com/) for tests.
- [QUnit](http://qunitjs.com/) for tests.
- [NodeJS](http://nodejs.org/download/) required to run grunt.
- [Grunt](http://gruntjs.com/getting-started) for task management.

Expand Down
32 changes: 9 additions & 23 deletions Gruntfile.js
Expand Up @@ -24,14 +24,12 @@ module.exports = function (grunt) {
}

grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
qunit: {
all: {
options: {
urls: [
'http://127.0.0.1:9998/',
'http://127.0.0.1:9998/amd.html',
'http://127.0.0.1:9998/environment-with-amd-and-umd.html',
'http://127.0.0.1:9998/module.html',
'http://127.0.0.1:9998/encoding.html?integration_baseurl=http://127.0.0.1:9998/'
]
}
Expand All @@ -42,34 +40,21 @@ module.exports = function (grunt) {
},
eslint: {
grunt: 'Gruntfile.js',
source: 'src/**/*.js',
source: 'src/**/*.mjs',
tests: 'test/**/*.js'
},
uglify: {
options: {
compress: {
unsafe: true
},
banner: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.license %> */\n'
},
build: {
files: {
'build/js.cookie.min.js': 'src/js.cookie.js',
'build/js.cookie-<%= pkg.version %>.min.js': 'src/js.cookie.js'
}
}
},
watch: {
options: {
livereload: true
},
files: '{src,test}/**/*.js',
files: ['src/**/*.mjs', 'test/**/*.js'],
tasks: 'default'
},
compare_size: {
files: [
'build/js.cookie-<%= pkg.version %>.min.js',
'src/js.cookie.js'
'dist/js.cookie.min.mjs',
'dist/js.cookie.min.js',
'src/js.cookie.mjs'
],
options: {
compress: {
Expand Down Expand Up @@ -105,6 +90,7 @@ module.exports = function (grunt) {
}
},
exec: {
'rollup': './node_modules/.bin/rollup -c',
'browserstack-runner': 'node_modules/.bin/browserstack-runner --verbose'
}
});
Expand All @@ -116,8 +102,8 @@ module.exports = function (grunt) {
}
}

grunt.registerTask('test', ['uglify', 'eslint', 'connect:build-qunit', 'qunit', 'nodeunit']);
grunt.registerTask('browserstack', ['uglify', 'exec:browserstack-runner']);
grunt.registerTask('test', ['exec:rollup', 'eslint', 'connect:build-qunit', 'qunit', 'nodeunit']);
grunt.registerTask('browserstack', ['exec:rollup', 'exec:browserstack-runner']);

grunt.registerTask('dev', ['test', 'compare_size']);

Expand Down
55 changes: 41 additions & 14 deletions README.md
Expand Up @@ -11,6 +11,7 @@ A simple, lightweight JavaScript API for handling cookies
* [Heavily](test) tested
* No dependency
* [Unobtrusive](#json) JSON support
* Supports ES modules
* Supports AMD/CommonJS
* [RFC 6265](https://tools.ietf.org/html/rfc6265) compliant
* Useful [Wiki](https://github.com/js-cookie/js-cookie/wiki)
Expand All @@ -22,35 +23,61 @@ A simple, lightweight JavaScript API for handling cookies

## Installation

### NPM

JavaScript Cookie supports [npm](https://www.npmjs.com/package/js-cookie) under the name `js-cookie`.

```
$ npm install js-cookie --save
```

### Direct download

Download the script [here](https://github.com/js-cookie/js-cookie/blob/latest/src/js.cookie.js) and include it (unless you are packaging scripts somehow else):
The source comes as an ES module. If you download it [here](https://github.com/js-cookie/js-cookie/blob/latest/src/js.cookie.mjs) directly, you must include it as such.

Example:

```html
<script src="/path/to/js.cookie.js"></script>
<script type="module" src="./js.cookie.mjs"></script>
<script type="module">
import Cookies from "./js.cookie.mjs";

Cookies.set('foo', 'bar');
</script>
```

Or include it via [jsDelivr CDN](https://www.jsdelivr.com/package/npm/js-cookie):
*Not all browsers support ES modules natively yet*. For this reason the npm package/release
comes with both an ES module as well as an UMD module variant. Include the module along
with the fallback to account for this:

```html
<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
<script type="module" src="/path/to/js.cookie.mjs"></script>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm enforcing consumers to use a JS file with a .mjs file extension at this level seems a little odd. Would all browsers know how to interpret a .mjs file extension?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't mean to force consumers, more like provide an example of how to include the module of that package directly, along with the fallback. In general, browsers do not care about the extension, though it's important a server serves mjs files with the proper mime type of text/javascript.

Generally I'm assuming the more likely use case for ES modules is to be bundled up, so I might add that here...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or do you mean it's too early to use mjs files in general? I was looking at https://v8.dev/features/modules and it seemed the way to go..

Copy link

@markcellus markcellus Sep 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, mjs files only work with node out of the box. The only way browsers would parse a file with this extension is if, as you say, the

server serves mjs files with the proper mime type of text/javascript

In other words, this won't work for consumers if they don't know to configure their server to serve the proper mime type. I would suggest we change the .mjs extension to .js like mentioned in #537 (comment). Then it wouldn't require a server change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the value for outputting a .mjs extension is to assist on documentation. Should we stick with one file for simplicity? Is there another reason for having both .js and .mjs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I'm siding with the node developers and wish to keep the extension:

Still, we recommend using the .mjs extension for modules, for two reasons:

  1. During development, the .mjs extension makes it crystal clear to you and anyone else looking at your project that the file is a module as opposed to a classic script. (It’s not always possible to tell just by looking at the code.) As mentioned before, modules are treated differently than classic scripts, so the difference is hugely important!
  2. It ensures that your file is parsed as a module by runtimes such as Node.js and d8, and build tools such as Babel. While these environments and tools each have proprietary ways via configuration to interpret files with other extensions as modules, the .mjs extension is the cross-compatible way to ensure that files are treated as modules.

I'm assuming it will be rather rare that the source will be consumed directly, rather than being bundled up with a tool. In the latter case the extension matters less, stressing the aforementioned arguments further.

Let's see how it goes. We can always change that back later on, but let's get some feedback first and start releasing a v3 beta once we're ready...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, if it's a convention it doesn't hurt simply following it.

<script nomodule src="/path/to/js.cookie.js"></script>
```

**Do not include the script directly from GitHub (http://raw.github.com/...).** The file is being served as text/plain and as such being blocked
in Internet Explorer on Windows 7 for instance (because of the wrong MIME type). Bottom line: GitHub is not a CDN.
Note the different extensions: `.mjs` denotes an ES module.

### Package Managers
### CDN

JavaScript Cookie supports [npm](https://www.npmjs.com/package/js-cookie) and [Bower](http://bower.io/search/?q=js-cookie) under the name `js-cookie`.
Alternatively, include it via [jsDelivr CDN](https://www.jsdelivr.com/package/npm/js-cookie):

#### NPM
```
$ npm install js-cookie --save
```html
<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
```

### Module Loaders
**Never include the source directly from GitHub (http://raw.github.com/...).** The file
is being served as text/plain and as such may be blocked because of the wrong MIME type.
Bottom line: GitHub is not a CDN.

## ES Module

JavaScript Cookie can also be loaded as an AMD or CommonJS module.
Example for how to import the ES module from another module:

```javascript
import Cookies from "./node_modules/js-cookie/dist/js.cookie.mjs";

Cookies.set('foo', 'bar');
```

## Basic Usage

Expand Down Expand Up @@ -303,7 +330,7 @@ For vulnerability reports, send an e-mail to `jscookieproject at gmail dot com`
## Manual release steps

* Increment the "version" attribute of `package.json`
* Increment the version number in the `src/js.cookie.js` file
* Increment the version number in the `src/js.cookie.mjs` file
* If `major` bump, update jsDelivr CDN major version link on README
* Commit with the message "Release version x.x.x"
* Create version tag in git
Expand Down
17 changes: 0 additions & 17 deletions bower.json

This file was deleted.

13 changes: 8 additions & 5 deletions package.json
Expand Up @@ -2,7 +2,8 @@
"name": "js-cookie",
"version": "2.2.1",
"description": "A simple, lightweight JavaScript API for handling cookies",
"main": "src/js.cookie.js",
"main": "dist/js.cookie.js",
"module": "dist/js.cookie.mjs",
"directories": {
"test": "test"
},
Expand All @@ -24,7 +25,7 @@
"url": "git://github.com/js-cookie/js-cookie.git"
},
"files": [
"src/**/*.js",
"dist/**/*",
"SERVER_SIDE.md",
"CONTRIBUTING.md"
],
Expand All @@ -37,12 +38,14 @@
"grunt-contrib-connect": "2.1.0",
"grunt-contrib-nodeunit": "2.0.0",
"grunt-contrib-qunit": "3.1.0",
"grunt-contrib-uglify": "4.0.1",
"grunt-contrib-watch": "1.1.0",
"grunt-eslint": "22.0.0",
"grunt-exec": "3.0.0",
"gzip-js": "0.3.2",
"qunitjs": "1.23.1",
"requirejs": "2.3.5"
"qunit": "2.9.2",
"rollup": "^1.20.3",
"rollup-plugin-filesize": "^6.2.0",
"rollup-plugin-license": "^0.12.1",
"rollup-plugin-terser": "^5.1.1"
}
}
55 changes: 55 additions & 0 deletions rollup.config.js
@@ -0,0 +1,55 @@
import { terser } from "rollup-plugin-terser";
import filesize from "rollup-plugin-filesize";
import license from "rollup-plugin-license";

export default [
{
input: "src/js.cookie.mjs",
output: [
// config for <script type="module">
{
dir: "dist",
entryFileNames: "[name].mjs",
format: "esm"
},
// config for <script nomodule>
{
dir: "dist",
name: "Cookies",
entryFileNames: "[name].js",
format: "umd",
noConflict: true
}
]
},
{
input: "src/js.cookie.mjs",
output: [
// config for <script type="module">
{
dir: "dist",
entryFileNames: "[name].min.mjs",
format: "esm"
},
// config for <script nomodule>
{
dir: "dist",
name: "Cookies",
entryFileNames: "[name].min.js",
format: "umd",
noConflict: true
}
],
plugins: [
terser(),
license({
banner: {
content:
"/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.license %> */",
commentStyle: "none"
}
}),
filesize()
]
}
];
4 changes: 4 additions & 0 deletions src/.eslintrc
Expand Up @@ -4,6 +4,10 @@
"browser": true,
"amd": true
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"rules": {
"camelcase": "error"
}
Expand Down