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

🐛Cache issue with identical files with relative import #933

Closed
eXon opened this issue Mar 2, 2018 · 7 comments · Fixed by #1011
Closed

🐛Cache issue with identical files with relative import #933

eXon opened this issue Mar 2, 2018 · 7 comments · Fixed by #1011

Comments

@eXon
Copy link
Contributor

eXon commented Mar 2, 2018

It seems like there is a cache issue when you have two identical files in two different folder, but they have relative import path. As an example, I have folder1/subFolder/index.js and folder2/subFolder/index.js importing ../index.js. However, folder1/index.js and folder2/index.js are two different files.

It looks like Parcel is thinking they are both the same but they are not because of the relative path.

😯 Current Behavior

Here is a proof of concept: https://github.com/exon/parcel-cache-bug

If you build and run it, it will print:

FOLDER1!!!
FOLDER3!!!

🤔 Expected Behavior

However, the expected result were:

FOLDER1!!!
FOLDER2!!!
FOLDER3!!!

💁 Possible Solution

I don't know the Parcel cache system but I guess it should transform the import path into something more absolute starting from the project root.

@pcattori
Copy link
Contributor

pcattori commented Mar 9, 2018

I've noticed that I get similar behavior only when serving parcel build results with express in production, where as in development I use express with parcel's Bundler and do not see this behavior.

This is currently the only reason I am not adopting Parcel for bigger projects. I LOVE what you guys are doing with Parcel 😄 so I hope this gets resolved soon!

@pcattori
Copy link
Contributor

could be related to #551

@pcattori
Copy link
Contributor

pcattori commented Mar 17, 2018

@eXon I reproduced your issue (I did have to tweak the start script in your package.json from "start": "node dist/parcel-cache-bug" to "start": "node dist/index.js").

I ruled out the Parcel .cache being the culprit as the behavior still occurs even after I nuked the cache (rm -rf .cache) and ran yarn build --no-cache to effectively run parcel build index.js --no-cache.

I de-minified dist/index.js:

require = function(r, e, n) {
    var t = "function" == typeof require && require;

    function o(n, u) {
        if (!e[n]) {
            if (!r[n]) {
                var i = "function" == typeof require && require;
                if (!u && i) return i(n, !0);
                if (t) return t(n, !0);
                var f = new Error("Cannot find module '" + n + "'");
                throw f.code = "MODULE_NOT_FOUND", f
            }
            l.resolve = function(e) {
                return r[n][1][e] || e
            };
            var c = e[n] = new o.Module(n);
            r[n][0].call(c.exports, l, c, c.exports)
        }
        return e[n].exports;

        function l(r) {
            return o(l.resolve(r))
        }
    }
    o.isParcelRequire = !0, o.Module = function(r) {
        this.id = r, this.bundle = o, this.exports = {}
    }, o.modules = r, o.cache = e, o.parent = t;
    for (var u = 0; u < n.length; u++) o(n[u]);
    return o
}({
    9: [function(require, module, exports) {
        module.exports = function() {
            console.log("FOLDER1!!!")
        };
    }, {}],
    3: [function(require, module, exports) {
        var r = require("../");
        r();
    }, {
        "../": 9
    }],
    11: [function(require, module, exports) {
        module.exports = function() {
            console.log("FOLDER2!!!")
        };
    }, {}],
    13: [function(require, module, exports) {
        module.exports = function() {
            console.log("FOLDER3!!!")
        };
    }, {}],
    7: [function(require, module, exports) {
        var global = (1, eval)("this");
        var e = (0, eval)("this"),
            r = require("../");
        r(), e.different = !0;
    }, {
        "../": 13
    }],
    1: [function(require, module, exports) {
        require("./folder1/subfolder"), require("./folder2/subfolder"), require("./folder3/subfolder");
    }, {
        "./folder1/subfolder": 3,
        "./folder2/subfolder": 3,
        "./folder3/subfolder": 7
    }]
}, {}, [1])
//# sourceMappingURL=/dist/index.map

Looks like at the bottom both folder1 and folder2 are being set to 3 presumably because the actual text they contain is the same (note that even if you had used different variable names across folder2/subfolder/index.js or folder3/subfolder/index.js, parcel ends up changing those and abstracting them so its not sufficient just to have different variable names, the actual values in the code have to be different).

I'm going to do some more digging to see what part of Parcel could be causing the issue...

@pcattori
Copy link
Contributor

pcattori commented Mar 17, 2018

The correct thing would be:

    9: [function(require, module, exports) {
        module.exports = function() {
            console.log("FOLDER1!!!")
        };
    }, {}],
    3: [function(require, module, exports) {
        var r = require("../");
        r();
    }, {
        "../": 9
    }],
    <some id>: [function(require, module, exports) {
        var r = require("../");
        r();
    }, {
        "../": 11
    }],
    11: [function(require, module, exports) {
        module.exports = function() {
            console.log("FOLDER2!!!")
        };
    }, {}],
    13: [function(require, module, exports) {
        module.exports = function() {
            console.log("FOLDER3!!!")
        };
    }, {}],
    7: [function(require, module, exports) {
        var global = (1, eval)("this");
        var e = (0, eval)("this"),
            r = require("../");
        r(), e.different = !0;
    }, {
        "../": 13
    }],
    1: [function(require, module, exports) {
        require("./folder1/subfolder"), require("./folder2/subfolder"), require("./folder3/subfolder");
    }, {
        "./folder1/subfolder": 3,
        "./folder2/subfolder": <some id>,
        "./folder3/subfolder": 7
    }]

(note where I added elements referencing <some id>)

@pcattori
Copy link
Contributor

pcattori commented Mar 17, 2018

Looks like the culprit might be the following:

  1. Deduplicating assets based on generated JS
  2. Setting dependencies via the deduplication cache

In this case, both ./folder1/subfolder/index.js and ./folder2/subfolder/index.js have identical generated JS (remember that this would still be the case if the source had different variable names since we compare the generated JS not the source), so the packager doesn't add the ./folder2/subfolder/index.js asset (1).

Then, when ./index.js asks for its dependency on ./folder2/subfolder/index.js, the Packager returns a reference to ./folder1/subfolder/index.js that it got by asking its cache for a match for the generated JS of ./folder2/subfolder/index.js.


Proposed fix: deduplication check both the generated JS AND the absolute dependency paths.

@henri-hulski
Copy link

Related to #1152.

@henri-hulski
Copy link

This is also true for module imports not only for relative imports.

import { httpPost, httpPut } from '@cerebral/http/operators'
import { redirectToSignal } from '@cerebral/router/operators'

are getting the same index:

"@cerebral/http/operators":67,"@cerebral/router/operators":67,

devongovett pushed a commit that referenced this issue Jul 2, 2018
2zH pushed a commit to 2zH/parcel that referenced this issue Jul 11, 2018
devongovett pushed a commit that referenced this issue Oct 15, 2018
devongovett pushed a commit that referenced this issue Oct 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants