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

fix: IE11 clone() #1029

Merged
merged 4 commits into from
Oct 21, 2020
Merged

fix: IE11 clone() #1029

merged 4 commits into from
Oct 21, 2020

Conversation

TheHalcyonSavant
Copy link
Contributor

Moving _whitelist and _blacklist initializations inside proto fixes: createSetIterator called on incompatible receiver error in IE11

Moving `_whitelist` and `_blacklist` initializations inside `proto` fixes: `createSetIterator called on incompatible receiver` error in IE11
@jquense
Copy link
Owner

jquense commented Sep 4, 2020

Not sure why CI didn't run here, but this likely breaks a lot of things...I don't think this is fixing the issue correctly, but it's hard to understand what the IE error even is here.

src/mixed.js Outdated
@@ -92,6 +89,9 @@ const proto = (SchemaType.prototype = {
__isYupSchema__: true,

constructor: SchemaType,

_whitelist: new RefSet(),
_blacklist: new RefSet(),
Copy link
Owner

Choose a reason for hiding this comment

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

this moves the properties to the prototype which is incorrect. They are instance properties and should not be shared between all instances of SchemaType, which is what would happen here.

@TheHalcyonSavant
Copy link
Contributor Author

TheHalcyonSavant commented Sep 4, 2020

To be able to replicate the IE11 failure, first prepare the build for es5 commonjs:

const nodeResolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');
const babel = require('rollup-plugin-babel');
const filesize = require('rollup-plugin-filesize');

const base = {
  input: './src/index.js',
  plugins: [
    nodeResolve({
      main: true,
      browser: true
    }),
    commonjs(),
    babel({
      babelrc: false,
      presets: [[
        '@babel/preset-env', {
          targets: {
            ie: '11'
          }
        }
      ]],
    }),
  ],
};

module.exports = [
  {
    ...base,
    output: [
      {
        file: 'dist/yup.js',
        format: 'iife',
      },
    ],
    plugins: [...base.plugins, filesize()],
  },
];

Then, expose all yup functions to global window object from within src/index.js.
You can download a standard polyfill (from polyfill.io or core-js) that contains the Set and its dependencies.
After running ./node_modules/.bin/rollup -c, create the following html for testing:

<html>
<head>
    <script src="some-default-es5-polyfills.js"></script>
    <script src="dist/yup.js"></script>
</head>
<body>
    <script>
        const object = window.yup.object;
        const string = window.yup.string;
        const number = window.yup.number;
        const date = window.yup.date;

        function testRun() {
            let s = string();
            try {
                s = s.required().concat(string()).concat(null);
            } catch (ex) {
                console.error(ex.stack);
            }
            const contactSchema = object().shape({
                name: s
            }).shape({
            age: number()
                .required()
                .positive()
                .integer(),
            email: string()
                .email(),
            website: string()
                .url(),
            createdOn: date()
                .default(function () { return new Date() })
            }).shape(null);

            contactSchema.isValid({
                // name: 'jimmy',
                age: 24,
                email: 'jdog@cool.biz'
            }).then(console.log);

            contactSchema.isValid({
                name: 'jimmy',
                age: 24,
                email: 'jdog@cool.biz'
            }).then(console.log);
        }

        testRun();
    </script>
</body>
</html>

Running this in IE11 breaks on concat in the try catch block. Further investigation shows that this._whitelist.list.size has <Permission denied>:
image

My PR fixes this bug. It doesn't break anything else as far as I know.
It would be better if the code was fully written with es6 classes, but this is a quick solution until full refactoring.

@jquense
Copy link
Owner

jquense commented Sep 4, 2020

Thanks for providing more context! It looks like this only fixes the issue because it avoids trying to clone the RefSets, but it creates a subtle and bad bug where one instance of these RefSets is shared between all schema globally. Judging from the error it looks like the actual bug is in the Concat method, but not sure where. And to be clear even with es6 classes this would still not work. The code as it's is functionally the same as an es6 class

@TheHalcyonSavant
Copy link
Contributor Author

Thanks for responding!

I ran my local tests badly, which misled me that everything was fine.
The bug seems very deep, not just with concat. I’ve seen it elsewhere with cloning and chaining of RefSet, but I can’t reproduce it for other cases. So far, I can reproduce it only for string().required().concat(string()), therefore I will remove this usage and continue.

@TheHalcyonSavant
Copy link
Contributor Author

TheHalcyonSavant commented Sep 6, 2020

Also, boolean().oneOf([true]) fails in IE11. In other words, every function that depends on concat

@TheHalcyonSavant
Copy link
Contributor Author

For some reason, the RefSets aren't cloned during the SchemaType.clone and this causes all of the IE11 bugs.
My guess is that other browsers don’t lock the inherited size property, and that’s why they can successfully clone Sets and Maps. Or maybe the bug could be inside lodash cloneDeepWith or in the polyfills, but I can’t debug any further as I have a solution.

This new commit doesn’t break any of the 536 tests, would you accept it?

@jquense jquense merged commit 7fd80aa into jquense:master Oct 21, 2020
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

Successfully merging this pull request may close these issues.

2 participants