feathersjs-ecosystem / feathers-redux

Integrate Feathers with your Redux store
MIT License
114 stars 23 forks source link

Ship a module build #58

Open petermikitsh opened 5 years ago

petermikitsh commented 5 years ago

If you look at the latest commonJS build, you'll see this require statement:

var _reduxActions = require("redux-actions");

This imports all of redux-actions -- which doesn't sound like a lot, but they depend a lot of utilities, for example, lodash.curry -- which is 33kb. Only createAction and handleActions are imported. (A different function in the redux-actions library imports lodash.curry).

I propose we ship a module build. Module builds are just like commonjs builds, except they use ES Module import syntax -- which is important for tree-shaking.

It's 100% backwards-compatible. You'd add a "module" property to package.json to point to the ES module build. Then people using tools like rollup and webpack will get the benefits of treeshaking awesomeness.

petermikitsh commented 5 years ago

To clarify, lodash.curry is 15kb minifed / 35kb original.

screen shot 2018-09-26 at 3 17 15 pm

eddyystop commented 5 years ago

Am I correct in thinking there would be 2 libraries in the repo. One using import syntax, the other running that import syntax and creating a webpack library?

petermikitsh commented 5 years ago

There would be 2 libraries shipped to NPM. One with require syntax, and one with import. Otherwise, the two versions would be exactly the same (in terms of their transpilation to ES5). You can make both the commonjs and and module builds using babel (it's the modules config option in @babel/preset-env). For commonjs, you leave it set to commonjs (which is the default). For module builds, you set it to false.

You can do it with babel (no webpack needed). I'd propose having two build commands in package.json, for example, build:commonjs and build:module. Then you'd use an env variable to tell babel what type of build you want.

Here's an example babel config and build commands from a project I manage.

eddyystop commented 5 years ago

I would prefer having one NPM package and using something like import feathersRedux from 'feathers-redux/xxx';. What are the downsides of this?

You could go ahead and develop on PR for this if you want to. It sounds worthwhile.

petermikitsh commented 5 years ago

Everything will still ship as one NPM module. I meant two libraries within the existing feathers-redux NPM module: the (existing) commonjs build and an additional esmodule build.

It's best to use the main and module package.json fields to point to the commonjs and esmodule builds (respectively). This allows for better support of the module in server and client environments.

For example, suppose in source code you were require feathers-redux/commonjs/index.js or feathers-redux/esmodule/index.js. If you're compiling the code on the client, and you pick the esmodule build, then you get the tree shaking awesomeness. But if you're using the module on the server (which in this case, is possible because of server-side rendering), you need to compile your server code (since NodeJS core doesn't support import-syntax).

If the package author declares defines main and module fields in package.json, you just import feathers-redux, and based off of your environment and build tools, you will automatically resolve to the commonjs or esmodule build.

I'll do a PR for it soon. Since it's totally backwards compatible and won't break anyone, I think you'll be happy to accept it.

abecks commented 5 years ago

@petermikitsh Just wondering if this ever happened?

petermikitsh commented 5 years ago

@abecks I've opened https://github.com/feathers-plus/feathers-redux/pull/60.

This probably isn't as beneficial as it would've been before, but it would still be a good addition. When I opened this issue, redux-actions was much larger:

Screen Shot 2019-06-09 at 8 56 45 PM

At the time, v2.6.1 was the latest release (18.7kB / 6.9kB). The latest release, v2.6.5 is 7kB / 2.7kB.