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

Option to ignore lazy loaded code #76

Closed
jantimon opened this issue Oct 31, 2018 · 14 comments
Closed

Option to ignore lazy loaded code #76

jantimon opened this issue Oct 31, 2018 · 14 comments

Comments

@jantimon
Copy link

jantimon commented Oct 31, 2018

It would be interesting to know the initial load size as well.

Would it be possible to skip the file sizes of dynamic imports (e.g. skip demoLibrary in onClick=async() => await import('demoLibrary').doSth)?

@ai
Copy link
Owner

ai commented Oct 31, 2018

Hi. I think Size Limit supports it out of box.

Show your Size Limit version and be config.

@jantimon
Copy link
Author

jantimon commented Nov 4, 2018

It's the size-limit version 0.21.0 (newest)

my code:

function crossBrowserFetch(url: string, init?: RequestInit): Promise<Response> {
	if (typeof fetch === 'undefined') {
		// Lazy load ponyfill if necessary
		return import(/* webpackChunkName: "lazy-fetch-ponyfill" */ 'fetch-ponyfill' as any).then(
			(fetchPonyfill) => fetchPonyfill.default().fetch(url, init) as Response
		);
	}
	return fetch(url, init);
}

Default configuration

With the default configuration it does not exclude lazy loaded scripts

"size-limit": [
    {
      "path": "index.js",
      "limit": "1.5 KB"
    }
  ]

Result:

Package size limit has exceeded by 113 B
Package size: 1.61 KB
Size limit:   1.5 KB

Explicitly ignored

If I ignore the package explicitly it seems to work.

"size-limit": [
    {
      "path": "src/index.js",
      "limit": "1.5 KB",
      "ignore": [
        "fetch-ponyfill"
      ]
    }
  ]

Result

Package size: 1.29 KB
Size limit:   1.5 KB
With all dependencies, minified and gzipped

@ai
Copy link
Owner

ai commented Nov 4, 2018

Hm. Can you show your webpack config?

@jantimon
Copy link
Author

jantimon commented Nov 5, 2018

I don't have any webpack config.
The code is transpiled using tsc before it is tested with size-limit.

The code after transpiling which is is given to size-limit is the following:

/**
 * Small helper to lazy load the fech library if missing (IE11)
 */
function crossBrowserFetch(url, init) {
    if (typeof fetch === 'undefined') {
        // Lazy load ponyfill if necessary
        return import(/* webpackChunkName: "request-registry-fetch-ponyfill" */ 'fetch-ponyfill').then(function (fetchPonyfill) { return fetchPonyfill.default().fetch(url, init); });
    }
    return fetch(url, init);
}

@ai
Copy link
Owner

ai commented Nov 6, 2018

Is it a JS library (so you will deliver it to users by npm) or an application?

@jantimon
Copy link
Author

jantimon commented Nov 7, 2018

A library just image it would only be this code:

index.js

/**
 * Small helper to lazy load the fech library if missing (IE11)
 */
module.exports = function crossBrowserFetch(url, init) {
    if (typeof fetch === 'undefined') {
        // Lazy load ponyfill if necessary
        return import(/* webpackChunkName: "request-registry-fetch-ponyfill" */ 'fetch-ponyfill').then(function (fetchPonyfill) { return fetchPonyfill.default().fetch(url, init); });
    }
    return fetch(url, init);
}

@ai
Copy link
Owner

ai commented Nov 7, 2018

Can you debug here https://github.com/ai/size-limit/blob/master/index.js#L155

What will be in assets variable

@jantimon
Copy link
Author

jantimon commented Nov 8, 2018

It looks like everything is correct.

The result of compiling the file above is:

!function(e) {
    function t(t) {
        for (var n, o, u = t[0], i = t[1], c = 0, a = []; c < u.length; c++) o = u[c], r[o] && a.push(r[o][0]), r[o] = 0;
        for (n in i) Object.prototype.hasOwnProperty.call(i, n) && (e[n] = i[n]);
        for (f && f(t); a.length;) a.shift()()
    }
    var n = {},
        r = {
            0: 0
        };

    function o(t) {
        if (n[t]) return n[t].exports;
        var r = n[t] = {
            i: t,
            l: !1,
            exports: {}
        };
        return e[t].call(r.exports, r, r.exports, o), r.l = !0, r.exports
    }
    o.e = function(e) {
        var t = [],
            n = r[e];
        if (0 !== n)
            if (n) t.push(n[2]);
            else {
                var u = new Promise(function(t, o) {
                    n = r[e] = [t, o]
                });
                t.push(n[2] = u);
                var i, c = document.getElementsByTagName("head")[0],
                    f = document.createElement("script");
                f.charset = "utf-8", f.timeout = 120, o.nc && f.setAttribute("nonce", o.nc), f.src = function(e) {
                    return o.p + "" + e + ".demo.js"
                }(e), i = function(t) {
                    f.onerror = f.onload = null, clearTimeout(a);
                    var n = r[e];
                    if (0 !== n) {
                        if (n) {
                            var o = t && ("load" === t.type ? "missing" : t.type),
                                u = t && t.target && t.target.src,
                                i = new Error("Loading chunk " + e + " failed.\n(" + o + ": " + u + ")");
                            i.type = o, i.request = u, n[1](i)
                        }
                        r[e] = void 0
                    }
                };
                var a = setTimeout(function() {
                    i({
                        type: "timeout",
                        target: f
                    })
                }, 12e4);
                f.onerror = f.onload = i, c.appendChild(f)
            } return Promise.all(t)
    }, o.m = e, o.c = n, o.d = function(e, t, n) {
        o.o(e, t) || Object.defineProperty(e, t, {
            enumerable: !0,
            get: n
        })
    }, o.r = function(e) {
        "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
            value: "Module"
        }), Object.defineProperty(e, "__esModule", {
            value: !0
        })
    }, o.t = function(e, t) {
        if (1 & t && (e = o(e)), 8 & t) return e;
        if (4 & t && "object" == typeof e && e && e.__esModule) return e;
        var n = Object.create(null);
        if (o.r(n), Object.defineProperty(n, "default", {
                enumerable: !0,
                value: e
            }), 2 & t && "string" != typeof e)
            for (var r in e) o.d(n, r, function(t) {
                return e[t]
            }.bind(null, r));
        return n
    }, o.n = function(e) {
        var t = e && e.__esModule ? function() {
            return e.default
        } : function() {
            return e
        };
        return o.d(t, "a", t), t
    }, o.o = function(e, t) {
        return Object.prototype.hasOwnProperty.call(e, t)
    }, o.p = "", o.oe = function(e) {
        throw console.error(e), e
    };
    var u = window.webpackJsonp = window.webpackJsonp || [],
        i = u.push.bind(u);
    u.push = t, u = u.slice();
    for (var c = 0; c < u.length; c++) t(u[c]);
    var f = i;
    o(o.s = 0)
}([function(e, t, n) {
    e.exports = n(1)
}, function(e, t, n) {
    e.exports = function(e, t) {
        return "undefined" == typeof fetch ? n.e(1).then(n.t.bind(null, 2, 7)).then(function(n) {
            return n.default().fetch(e, t)
        }) : fetch(e, t)
    }
}]);

So the main code is the webpack load code from here:

https://github.com/webpack/webpack/blob/9b97f3aeb124776731b9830c4964f496a3cdfed8/lib/web/JsonpMainTemplatePlugin.js#L149-L203

@ai
Copy link
Owner

ai commented Nov 8, 2018

I need a list of assets. Did webpack created a separated file for dynamic import.

@jantimon
Copy link
Author

jantimon commented Nov 8, 2018

console.log(assets)
-> 
[ 'demo.js' ]
 console.log(stat.assetsByChunkName)
->
 { 
  main: 'demo.js',
  'request-registry-fetch-ponyfill': '1.demo.js' 
}

@jantimon
Copy link
Author

jantimon commented Nov 8, 2018

My confusion was because of the large size but it is the webpack code which is added to the code.

@ai
Copy link
Owner

ai commented Nov 10, 2018

Seems like assets is correct and it should count only demo.js size.

Do you have a project to repeat the error. I afraid that webpack just do not move polyfill to that file.

@jantimon
Copy link
Author

jantimon commented Nov 12, 2018

Sure - but I guess your tool is delivering the "correct" result unfortunately it counts also the size of the webpack dynamic module loader.
So even with only 1 line of code you start with a quite high number.

I attached a demo project: size-limit-demo.zip
Just run npm i && npm run size

You will see that the index.js file (431 bytes without gzip without minifcation) will show the following result:

Package size: 597 B
With all dependencies, minified and gzipped

Especially for such a small library (4 lines of code) that's a quite huge number

@ai
Copy link
Owner

ai commented Nov 14, 2018

unfortunately it counts also the size of the webpack dynamic module loader.

Yeap, it is by design. Your user may not have dynamic import() in their bundle and your library cost (for them) will include dynamic module loader.

So even with only 1 line of code you start with a quite high number.

Yeap, Size Limit was specially designed to detect this case.

Here is another example when Size Limit helped to decrease library real cost by one LOC theKashey/react-focus-lock#48

Here is what I suggest or your case:

  1. Do not use fetch() polyfill. Dynamic load blocks you from using another bundler. And it requires dynamic module loader for any user.
  2. Add add fetch() polyfill to library docs.
  3. Keep if (global.fetch) check, but just show the warning for a user, that they must have fetch() own polyfill.
  4. You may wrap this check and warning in if (process.env.NODE_ENV === 'development') to cut this check in production bundle (anyway most of the developers will see this warning when they will test your library in different browsers).

@ai ai closed this as completed Nov 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants