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

[BUG] Not working on IE #364

Closed
mackan92 opened this issue Oct 15, 2019 · 46 comments · Fixed by #781
Closed

[BUG] Not working on IE #364

mackan92 opened this issue Oct 15, 2019 · 46 comments · Fixed by #781
Labels
bug Something isn't working

Comments

@mackan92
Copy link

mackan92 commented Oct 15, 2019

The website my team are developing is using Framer Motion. It seems that it won't work on Internet Explorer. I've tested it with IE 11. Searching for bug reports lead me to nothing.

When I tried to go in to your website on IE, https://www.framer.com/motion/, animations did not appear to be working either.

Has Framer Motion support for IE? If no, do you plan to implement it in a near future?

@mackan92 mackan92 added the bug Something isn't working label Oct 15, 2019
@mattgperry
Copy link
Collaborator

No support for IE11 now or ever I'm afraid. Time-permitting I hope to have a browser support list up in the docs, though it's basically all modern browsers.

@msheakoski
Copy link

msheakoski commented Oct 15, 2019

I wouldn't bother supporting IE11, it's a dead end. The new Chromium-based Edge supports Windows 7 and newer. I'm sure Microsoft will be pushing it heavily to existing IE users via updates, notifications, banners on their web properties, and as a default in new installs of Windows. For corporate users, there is an "IE mode" built in for legacy sites.

@thebuilder
Copy link
Contributor

thebuilder commented Oct 16, 2019

Seems like the issue on frame.com/motion is caused by arrow functions - Is the problem you are using any methods in the library that can't be polyfilled?

@msheakoski
Copy link

@thebuilder I had to support IE11 on a project that used Pose, so I imagine the polyfills needed are similar. Here is what made IE11 work:

import "core-js/features/array/find";
import "core-js/features/object/assign";
import "core-js/features/promise";
import "core-js/features/string/ends-with";
import "core-js/features/symbol/for";
import "core-js/features/weak-set";

@mackan92
Copy link
Author

Thank you for your answers. My project also has to support IE. I added the polyfills and managed to make Framer Motion partly work on IE, but there were still a lot of issues. I will look at another option, probably remove animations completely on IE and keep Framer Motion for the modern browsers.

@thebuilder
Copy link
Contributor

@mackan92 any information about what/how you added the polyfills? What issues are you seeing? Broken animations, or script errors?
Are you loading the the ES version of Framer Motion, or the ES5 version?

https://unpkg.com/browse/framer-motion@1.6.14/dist/

Most likely Webpack is loading the es version and just uses that uncompiled.

@thebuilder
Copy link
Contributor

thebuilder commented Oct 18, 2019

https://github.com/react-spring/react-spring/ has had the same issue with shipping ES6 bundle - They solved it by having you import the .cjs file instead.

@anilanar
Copy link

anilanar commented Oct 28, 2019

If it's just a polyfill problem, I highly suggest everyone to use babel-preset-env or babel-plugin-transform-runtime with useBuiltIns and to not ignore node_modules, except a few like react-dom. You will thank me later.

@samuelgoddard
Copy link

Did anyone figure out how to get this working with Gatsby? Or could anyone point me in the right direction for how I could potentially support IE11 with Framer Motion / Gatsby. Thank you!

@designbyadrian
Copy link

@samuelgoddard Gatsby shouldn't have any impact on wether Framer Motion works with IE11. Maybe you issue is a combination of three: 1) Framer Motion with IE11, 2) using JS polyfills with Gatsby, 3) Framer Motion page transitions in Gatsby.

@samuelgoddard
Copy link

@designbyadrian thanks for the reply, I don't really know where to start with debugging - I'm getting Object doesn't support property or method 'append' i IE11 when using framer motion page transitions, I've tried polyfilling it using polyfill.io but I then get an Object doesn't support this action error. Do you have any idea at all? Example site can be found here - https://prb-architects.netlify.app/

@mattgperry
Copy link
Collaborator

mattgperry commented Jul 26, 2020 via email

@GooBall
Copy link

GooBall commented Jul 27, 2020

@InventingWithMonster That would probably be the best of both worlds. I'm in a position where the product I'm working on is not going to be able to drop support for IE11 until 2021 at the earliest.

For future me, @samuelgoddard and anyone else Googling... even if you are using CRA or react-app-polyfill but have upgraded to framer-motion v2, you will be getting the IE console error of 'Proxy' is undefined in some chunk.js file and Object doesn't support property or method 'append'.

As Matt says, V2 doesn't work with IE so downgrading to framer-motion@1.10.3 should get you back on track.

@brentg5
Copy link

brentg5 commented Aug 4, 2020

Thank you for working on this @InventingWithMonster! As much as I'd love to sunset IE11, we are also in a similar state and need to support it for a while. Looking forward to seeing what you come up with.

@greypants
Copy link

greypants commented Aug 7, 2020

I might be able to add an extra entry point like import { ieMotion as motion } where you accept ~1.5kb extra bundle size in exchange for IE11 support?

@InventingWithMonster☝️ That would be awesome.

Sadly, IE 11 support is critical for us. We're an enterprise company with a surprising number of clients with a death grip on IE 11. We love framer motion ❤️, and would love continued support. We'll pay the extra 1.5kb gladly.

Will roll back to 1.x.x for now.

@tolesdev
Copy link

@InventingWithMonster Any progress with IE11 support?

@barchenaqaunt
Copy link

Hey,
I'm using version 2.6.13, when I'm loading my app in IE 11 the browser crash and I get an error - "Proxy is undefined".
did anyone encounter this problem and found a way to deal with it?
Lowering the version to 1.x.x isn't an option for me

@brentg5
Copy link

brentg5 commented Sep 14, 2020

@InventingWithMonster Is there any chance we could reopen this issue? The op closed it, but clearly there is a lot of critical interest in IE11 support, even if it results in a larger bundle size. Without it, many of your enterprise consumers will be put in a tough position.

@mattgperry
Copy link
Collaborator

Yep this is worth keeping open imo, I will manage to take a look in the coming weeks

@mattgperry mattgperry reopened this Sep 14, 2020
@mergetron mergetron bot closed this as completed in #781 Sep 24, 2020
@mattgperry
Copy link
Collaborator

mattgperry commented Sep 24, 2020

The linked PR ^ shows a new API that will help you create a replacement for motion that doesn't use Proxy. Please note that this doesn't constitute IE11 support, for instance future versions of Motion may require new polyfills, or make others unnecessary.

However this is a nicer solution IMO than a separate legacy entry point, both in terms of code complexity on our side (= no dusty API corners to break for you) and also it will actually be slightly smaller than importing motion itself.

@thebuilder
Copy link
Contributor

thebuilder commented Sep 26, 2020

This is great - How do you envision it actually being used? Should we create all the HTML tag's we'd want to support in the custom motion and share that instance throughout the application?

import { createDomMotionComponent } from 'framer-motion'

/** IE 11 supported version of the motion component */
export const motion = { 
  div: createDomMotionComponent("div"),
  span: createDomMotionComponent("span") ,
  svg: createDomMotionComponent("svg") ,
}

@mattgperry
Copy link
Collaborator

Yeah exactly this ^

@thebuilder
Copy link
Contributor

thebuilder commented Sep 27, 2020

Just to improve upon it, a check for Proxy support could be added, so it only uses the fallback if needed:

Not recommend - See below
import { motion, createDomMotionComponent } from 'framer-motion

/** IE 11 supported version of the motion component */
export const motion = typeof Proxy === 'undefined' ? { 
  div: createDomMotionComponent("div"),
  span: createDomMotionComponent("span") ,
  svg: createDomMotionComponent("svg") ,
} : motion;

@mattgperry
Copy link
Collaborator

mattgperry commented Sep 28, 2020

I would recommend against that approach as Motion's motion isn't necessarily the same as the user-generated one leading to obscure runtime errors.

You'd be writing in an environment with Proxy, so your module would export motion. So you go ahead and use motion.header or motion.custom(Component), but neither of these have been implemented. You ship it, it works in all testing environments, but it'd only be someone using it in IE11 who would get the runtime error. It's probably safer to use your custom motion component always, so if you use an undefined component it breaks for you in dev.

@thebuilder
Copy link
Contributor

Tried it on our production website, and it's working great. Did have to modify the typescript types to get them to match, since it createDomMotionComponent doesn't match the exported motion types.

// createDomMotionComponent
ForwardRefExoticComponent<MotionProps & React.RefAttributes<unknown>>

// motion.div type
ForwardRefComponent<UnwrapFactoryElement<ReactHTML[K]>, HTMLMotionProps<K>>

The result is the returned type doesn't contain the HTMLProps. Could it make sense to reuse the UnwrapFactoryElement and UnwrapSVGFactoryElement types to create the correct types? The function gets the DOM element as a string, so should be possible to map the same way.

I've generated my own list of ValidMotionTypes by reusing the exported HTMLMotionComponents. Could be optimized further, but works for now.

import React from 'react';
import {
  createDomMotionComponent,
  motion as originalMotion,
} from 'framer-motion';
import { CustomDomComponent } from 'framer-motion/types/render/dom';
import {
  HTMLMotionComponents,
  SVGMotionComponents,
} from 'framer-motion/types/render/dom/types';

type CustomMotionType = {
  custom: <Props>(
    Component:
      | string
      | React.ComponentClass<Props, any>
      | React.FunctionComponent<Props>,
  ) => CustomDomComponent<Props>;
};

type ValidMotionTypes = CustomMotionType &
  Pick<
    HTMLMotionComponents & SVGMotionComponents,
    // List all the exported HTML/SVG tags here. This ensures
    'div' | 'span' | 'button' | 'a' | 'article' | 'header' | 'svg' | 'path'
  >;

export const motion = {
  div: createDomMotionComponent('div'),
  span: createDomMotionComponent('span'),
  button: createDomMotionComponent('button'),
  a: createDomMotionComponent('a'),
  article: createDomMotionComponent('article'),
  header: createDomMotionComponent('header'),
  svg: createDomMotionComponent('svg'),
  path: createDomMotionComponent('path'),
  custom: originalMotion.custom,
} as ValidMotionTypes;

// re-export everything
export * from 'framer-motion';

@linusklingzell
Copy link

Tried this fix/solution in a clean CRA with polyfills for IE11 but can't make this to work. As soon as I import import { createDomMotionComponent } from 'framer-motion' without even using it, I get an error that Proxy is not defined when running the code in IE11 browser. Is there something else more than correct polyfills to make this to work?

@mattgperry
Copy link
Collaborator

@linusklingzell Have you enabled code splitting in your bundler?

@anzorb
Copy link

anzorb commented Oct 22, 2020

@mattgperry I am guessing this doesn't polyfill motion.custom? I see the createMotionProxy function being bundled in, even with above workaround. I am also using CRA + ie11 polyfills.

Cheers!

@linusklingzell
Copy link

Tried code splitting as you suggested @mattgperry with dynamic imports but I still get the same error

@rr-justin-hanselman
Copy link

rr-justin-hanselman commented Nov 5, 2020

Hello,

I've just run into this problem. Chakra-ui uses the new framer-motion but we still want to support IE11 until it is no longer profitable.

My plan is to resolve my module to a wrapper that can export a non-proxied equivalent of motion if I detect the need to like @thebuilder suggested.

However, I was wondering why the index-legacy.ts was removed:
b4319c7

Rather than having to keep a separate list of modules, I would like to import the defaults and custom, which seemed to be exposed previously, but is now removed. Could you maybe explain why this functionality is gone or its downsides? @mattgperry

Thanks!

@mattgperry mattgperry reopened this Nov 6, 2020
@mattgperry
Copy link
Collaborator

Reopening as there's clearly some further things to figure out

@rr-justin-hanselman
Copy link

rr-justin-hanselman commented Nov 6, 2020

After working on it yesterday, I was able to get the wrapper to work, with the current framer-motion package.

The wrapper file (client/framer-motion-wrapper.js in my solution):

import { motion as origMotion, createDomMotionComponent } from '../node_modules/framer-motion';
import { proxyDefined } from './clientState';

// fragile copied from internal framer-motion supported-elements.ts
import { htmlElements, svgElements } from './framer-motion-supported-elements';

// Adapted from https://github.com/framer/motion/commit/b4319c78fb4bde28ce0d2a8008df48d7e3fd1c8b
const createNonProxyMotion = () => {
  let motionProxy = {
    custom: (component) => {
      createDomMotionComponent(component);
    },
  };
  motionProxy = htmlElements.reduce((acc, key) => {
    acc[key] = createDomMotionComponent(key);
    return acc;
  }, motionProxy);
  motionProxy = svgElements.reduce((acc, key) => {
    acc[key] = createDomMotionComponent(key);
    return acc;
  }, motionProxy);
  return motionProxy;
};

export const motion = proxyDefined ? origMotion : createNonProxyMotion();

export * from '../node_modules/framer-motion';

Note, because motion calls to Proxy on module initialization, you STILL need a proxy-polyfill before your module-wrapper, I have a main polyfill that is included at the top of my entry-point with this logic:

// determine the state of the client before polyfilling
import { proxyDefined } from './clientState';

// ...Other polyfills

// Example: immer assumes es6 if polyfill is defined - keep this in mind if other libraries are failing after polyfilling
import { enableES5 } from 'immer';
// We have to include this for now, since framer-motion requires the Promise call immediately
import 'proxy-polyfill';

if (!proxyDefined) enableES5();

The clientState.js is basically a copy-paste of the proxy-polyfill switch:

const hasProxy = (scope) => !!scope.Proxy;

// Using the same Proxy polyfill checks as proxy-polyfill
export const proxyDefined = hasProxy((typeof process !== 'undefined'
&& {}.toString.call(process) === '[object process]')
|| (typeof navigator !== 'undefined' && navigator.product === 'ReactNative')
  ? global
  : self);

Finally, whatever your packing solution, you will want to perform a module replacement. Here's the example with webpack:

    config.plugins.push(new webpack.NormalModuleReplacementPlugin(
      /^framer-motion$/, path.resolve(__dirname, 'client/framer-motion-wrapper.js'),
    ));

Hopefully this helps in both the bug-fixing and anyone else hoping to still support IE11. If you find a better solution, I would love to hear!

@masaroli
Copy link

Greetings! I've started a small project with framer motion. I didn't know it doesn't support IE. Tried using createDomMotionComponent instead of motion but the animations go into a loop and I couldn't figure out why. With motion works fine but the fix doesn't. Also, the types don't match as @thebuilder commented.

@mackan92
Copy link
Author

mackan92 commented Nov 25, 2020

@rr-justin-hanselman
I have tried to do exactly as you and I have managed to make the wrapper work. Unfortunately, I am still getting "'Proxy' is undefined" on IE. The polyfill you are using, 'proxy-polyfill', is it this one? https://www.npmjs.com/package/proxy-polyfill

Update: Now I managed to import the polyfill mentioned above correctly. It works with IE 11!
I imported the polyfill like this:
import 'proxy-polyfill/proxy.min.js';

I use the latest version of Framer Motion (2.9.4).

@bernhardw
Copy link

@mackan92 Would you mind posting the files and changes you have made to make it work in IE 11?
The polyfill works, but I'm having troubles copying the additional files (framer-motion-supported-elements.ts, clientState.ts etc.) together.

@katiawheeler
Copy link

I can confirm, I'm still getting this error on IE 11 using the provided createDomMotionComponent - the proxy-polyfill is also not working for me 😞

@rr-justin-hanselman
Copy link

@mackan92 - nice!

@bernhardw - I probably should've clarified -

clientState.ts should be your own file in your library that you import in your project at the top of whatever file you're using to import all your necessary polyfills. The reason for this is that certain other libraries already detect if proxy is in on the window and change their implementation (in my case, immer was doing this automatically so I had to keep proxy-polyfill unimplemented until later). You use the clientState.ts to simply get all the info about the client before you start importing things that will change the window.

As for the frame-motion-supported-elements.ts, those were literaly copy-pasted from the framer-motion repo into a file on my project (they are not publicly exposed right now from what I can see). Do a search in the repo for the file I've commented above that line and you should find it.

Hope this helps!

@mattgperry
Copy link
Collaborator

I've added sideEffects: false to the package.json in the latest versions which should aid code-splitting. Is it possible for one of you who had trouble with createDomMotionComponent still triggering the Proxy error to try with 3.5.3?

@klaasman
Copy link

Hi Matt,

I'm running a nextjs application where I don't notice any difference between importing v3.5.2 and v3.5.3: both versions result in the proxy error in IE11 while only the createDomMotionComponent is imported.

By the way, to me it looks like importing the proxy-polyfill works.

@mattgperry
Copy link
Collaborator

mattgperry commented Mar 2, 2021

I'm closing this now as we should have fixed code-splitting in Webpack with 3.8.0. Please reopen if you are using ES modules and this still doesn't work.

@pleunv
Copy link

pleunv commented Mar 2, 2021

I'm honestly a bit lost when reading through this issue and I can't immediately find docs about this, so apologies for bumping this. Am I right in assuming that this approach outlined earlier by @thebuilder should allow for IE11 compatibility today after the fix in 3.8?

This is great - How do you envision it actually being used? Should we create all the HTML tag's we'd want to support in the custom motion and share that instance throughout the application?

import { createDomMotionComponent } from 'framer-motion'

/** IE 11 supported version of the motion component */
export const motion = { 
  div: createDomMotionComponent("div"),
  span: createDomMotionComponent("span") ,
  svg: createDomMotionComponent("svg") ,
}

I'm guessing this also still depends on Proxy being polyfilled?

The part that confuses me the most is that this now seems to be fixed with the code-splitting added in 3.8, can anyone elaborate on how the lack thereof was breaking IE11 compatibility? Mostly out of curiosity :)

@mattgperry
Copy link
Collaborator

mattgperry commented Mar 2, 2021

@pleunv the idea with the code-splitting is you shouldn’t need a polyfill for Proxy any more as, if it works successfully, the code that uses Proxy won’t be included. I think a guide is a good idea but the method you outlined is what I had in mind

Edit: to address your last question, it was IE11 even encountering Proxy that breaks it, which is why this requires code splitting in Webpack to fix.

@pleunv
Copy link

pleunv commented Mar 2, 2021

Totally clarifies it, thank you!

@hanseltime
Copy link

Hey @mackan92,

Could you elaborate on this code-splitting? I have version 4.1.17, but looking at the code here, the actual framer-motion module calls proxy during initialization code.

To my understanding, that should mean I need a proxy polyfill so that the framer-motion module doesn't fail.

Note: I have a working example of wrapping this module for that logic, but it's more complicated than just having a switch in framer-motion:
https://github.com/hanseltime/stylis-ie11-plugins/tree/master/examples/chakra-app

If I'm missing a document or method for ensuring this "@PURE" function is split out completely, I'd love to be enlightened!

Thanks

@thathurtabit
Copy link

Hopefully I'm not missing any documentation on this, but for our needs we're OK with not having FramerMotion animate on IE11, but would it cause errors in IE11? Would I need to do a browser check for IE11 and provide a different (basic) component for those users? Thanks.

@kwanso-awais
Copy link

kwanso-awais commented Jan 23, 2023

This is framer motion transition is working fine locally but too jagged on live eCommerce store. Can you please help me.
Local Transition
You can check below video link. Transition is working fine here but not on live server
https://www.loom.com/share/9b6268f8de014a14ae2f50fa5716320a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.