lz-string icon indicating copy to clipboard operation
lz-string copied to clipboard

es6 module support

Open backspaces opened this issue 8 years ago • 7 comments

All modern browsers now support es6 modules (except chrome which will land shortly).

Could you include an es6 module version of lz-string? I have a project using compression (lzma & pako and soon lz-string) and want to be able to use es6 imports for them.

Here's a failed request to pako that at least shows more information: https://github.com/nodeca/pako/issues/97

The workflow needn't be arduous: you build a module based version, and use Rollup to convert to an exact duplicate of the existing system.

backspaces avatar Apr 01 '17 17:04 backspaces

Can you tell me what would the upside be?

pieroxy avatar Apr 04 '17 16:04 pieroxy

The pako request has a fair amount of information so I won't repeat that entirely.

The key advantage for the developers of modules (in the JS code) and in the web page is that the developer can change dependencies without changing the page, which he/she may not have access to. A study made a while back showed an alarming number of got dragged into the browser but were never used for just this reason. Dependencies closer to the code is a Good Thing.

But in terms of practicality, during my research on module use I found many fairly large projects like Three.js and several others that converted to modules and used a simple one-liner to convert it into IIFEs. This made their work future-proof so that when modules are widely used, they will already be available, and a Rollup bundle available for legacy browsers. This also has the huge advantage that, if you don't use a project's module, it won't be dragged in. For that to occur with bundle use, the app developer would have to include their app along with the module based project for "tree-shaking". This, along with module's use of HTTP2, makes modules much faster to use than the traditional IIFE.

Finally, workflow. I've grown weary of the typical JS edit/compile/try workflow. I want the code I write to be immediately available to try without webpack, typescript/coffeescript, systemjs, and so on having to watch my files for change. So now when I develop modules, before using Rollup for a bundle (that's a distrib task now), I just try it in a module-supporting browser, alas only Safari Tech Preview and FFox nightly .. and Edge if you have that.

So finer granularity, immediate use, optional features, HTTP2, future-proofing w/ one-liner legacy, no web page .. Free At Last!

backspaces avatar Apr 04 '17 16:04 backspaces

I am really short on time these days. Do you think you could send a pull request ?

pieroxy avatar Apr 06 '17 07:04 pieroxy

Just looked at the code and noticed the export area:

if (typeof define === 'function' && define.amd) {
  define(function () { return LZString; });
} else if( typeof module !== 'undefined' && module != null ) {
  module.exports = LZString
} else if( typeof angular !== 'undefined' && angular != null ) {
  angular.module('LZString', [])
  .factory('LZString', function () {
    return LZString;
  });
}

So in theory we'd want to add an es 6 export, something like

} else if (<test for es6 module support>) {
  export default LZString
}

But, and you won't believe this!, there is no such test! It may just fail silently, which would be OK, but worse, the es6 export is "static" and must not be conditional, it couldn't be within the if chain.

On the upside, it gets rid of the need for IIFEs, the export statement immediately places the file within it's own name scope.

There has been huge outcries from the community and these constraints may change.

Here's what I'll do: I'll simply install lz-string as usual in my project, using it as a global name. I have a few others and I'll probably just replace two of them with lz-string. Then when I look at "modularizing" the other projects, I'll see how to best "modularizing" lz-string.

From looking at other projects doing this, they tend to convert entirely to es6 modules, then use Rollup to create an IIFE "bundle" with no imports/export, just the global variable. Three.js, for example does this with their large project. And I've converted to that myself. And I believe the bundle can be enhanced to contain the other exports you support. I'll keep my eye out for how others are managing multiple exports.

Love the code, BTW, and it taught me just how much difficulty it is to support the way-too-many exports!

backspaces avatar Apr 06 '17 16:04 backspaces

I believe the eventual answer is:

  • Create the main code as an es6 module
  • Use Rollup with multiple targets, one for cjs, another for amd, one for iife etc. https://github.com/rollup/rollup/wiki/Command%20Line%20Interface#targets

In other words, Rollup, with an es6 module, can convert the output into many formats:

  • https://github.com/rollup/rollup/wiki/JavaScript-API#format

The current formats are: amd, cjs, es, iife, umd

And a single config file can output multiple targets.

backspaces avatar Apr 06 '17 19:04 backspaces

@pieroxy hello. i can't use lz-string in my new es-module-only applications

does anybody have a fork or build that can work in a modern app?

chase-moskal avatar Sep 22 '20 21:09 chase-moskal

Related to #123

Rycochet avatar Sep 23 '20 08:09 Rycochet

This now exists on the master branch and future releases, wait for 2.0.0 final to hit npmjs for it to be live!

Rycochet avatar Jun 20 '23 18:06 Rycochet