Search code examples
internet-explorerwebpackweb-componentsvelte

Web component IE11 with Svelte


I'm struggling as I'm trying to adapt webcomponents made with Svelte for IE11. I managed to show the webcomponents in the browser but I did not manage make them fully functional.

When using Svelte transitions I get the following error:

object doesn't support property or method "__shady_native_contains" in the @webcomponents file webcomponents-sd-ce.js.

I'm using webpack with @webcomponents polyfills.

Here is my courrent webpack configuration:

const sassCssConfig = {
    test: /\.s[ac]ss$/,
    use: [
        'style-loader', 'css-loader', 'sass-loader'
    ]
}

const resolveExtensions = {
    alias: {
        svelte: path.resolve('node_modules', 'svelte')
    },
    extensions: [".mjs", ".ts", ".tsx", ".js", ".json", ".svelte"]
}

module.exports = [{
    entry: ['whatwg-fetch', '@webcomponents/custom-elements', './src/main.ts'],
    mode: 'development',
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'build'),
        libraryTarget: "window",
    },
    externals: [
        {
            bc: 'bc',
            kendo: 'kendo',
            jquery: 'jQuery'
        }
    ],
    target: ['web', 'es5'],
    devtool: 'source-map',
    module: {
        rules: [
            {
                test: /(\.m?js?$)|(\.svelte$)|(\.ts$)/,
                exclude:   /\bcore-js\b/,
                resolve: {
                    fullySpecified: false
                },
                use: [
                    // Then babel
                    {
                        loader: 'babel-loader',
                       
                        options: {
                            presets: [
                                [
                                    "@babel/preset-env",
                                    {
                                        targets: {
                                            browsers: ["ie >= 10"]
                                        },
                                        useBuiltIns: "usage",
                                        corejs: 3
                                    } // or whatever your project requires
                                ],
                                "@babel/preset-typescript",
                            ],
                            plugins: [
                                // plugin-proposal-decorators is only needed if you're using experimental decorators in TypeScript
                                // ["@babel/plugin-proposal-decorators", { legacy: true }],
                                // ["@babel/plugin-proposal-class-properties", { loose: true }],
                                ['@babel/plugin-transform-typescript', { "allowNamespaces": true }],
                                 ["@babel/plugin-transform-runtime", { regenerator: true }]
                            ],
                            sourceType: 'unambiguous'
                        }
                    } 
                ],
            },
            {
                test: /\.svelte$/,
                exclude: /node_modules/,
                
                use: {
                    loader: 'svelte-loader',
                    options: {
                        customElement: true,
                        emitCss: false,
                        preprocess: require('svelte-preprocess')({})
                    },
                }
            },
            sassCssConfig
        ],
    },
    resolve: resolveExtensions,
    plugins: [
        new CopyWebpackPlugin(
            {
                patterns: [
                    {
                        context: 'node_modules/@webcomponents/webcomponentsjs',
                        from: '**/*.js',
                        to: '.'
                    }
                ]

            }
        )

    ]
},

]

In my html file I have the following setup:

<script src="//cdn.polyfill.io/v2/polyfill.min.js"></script>
<script src="~/Scripts/svelte-webpack/build/webcomponents-loader.js"></script>
<script>
  if (!window.customElements) { document.write('<!--'); }
</script>

<script src="~/Scripts/svelte-webpack/build/custom-elements-es5-adapter.js"></script>
<!-- ! DO NOT REMOVE THIS COMMENT, WE NEED ITS CLOSING MARKER -->

<script src="~/Scripts/svelte-webpack/build/bundle.js"></script>

As as side note, in main.ts I include the following for core-js / regenerator-runtime / promise-polyfill

import "core-js/stable";
import "regenerator-runtime/runtime";
import 'promise-polyfill/src/polyfill';

Has anyone encountered anything similar? I'm grateful for any help I can get on this subject.


Solution

  • I finally got the whole thing to work with IE11. The problem was solved by replacing the /cdn.polyfill.io/v2/polyfill.min.js file with cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.min.js. I can not tell what the differences are exactly, but the error is now gone.

    Here is the working configuration in the head script as well as a working rollup configuration (typescript/babel/svelte/:

    In the index.html file:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.min.js"></script>
    <script src="~/Scripts/svelte-webpack/build/custom-elements-es5-adapter.js"></script>
    <script src="~/Scripts/svelte-webpack/build/webcomponents-loader.js"></script>
    <script src="~/Scripts/svelte-rollup/build/bundle.js"></script>
    
    export default {
      input: 'src/main.ts',
      output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'build/bundle.js'
      },
      plugins: [
       
        svelte({
          dev: !production,
          customElement: true,
          emitCss: false,
          extensions: ['.svelte'],
          preprocess: sveltePreprocessor()
        }),
        // compile to IE11 compatible ES5
        babel({
            babelHelpers: 'runtime',
          extensions: [ '.js', '.mjs', '.html', '.svelte' ],
          exclude: [ 'node_modules/@babel/**', 'node_modules/core-js/**' ],
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {
                  ie: '11'
                },
                useBuiltIns: 'usage',
                corejs: 3
              }
            ]
          ],
          plugins: [
            '@babel/plugin-syntax-dynamic-import',
            [
              '@babel/plugin-transform-runtime',
              {
                useESModules: true
              }
            ]
          ]
        }),
    
        resolve({
            browser: true,
            dedupe: ['svelte']
        }),
        commonjs(),
        typescript({ sourceMap: !production, inlineSources: !production }),
    
        production && terser()
      ],
      watch: {
        clearScreen: false
      }
    }
    

    Also I added following pollyfills in my ts files as imports:

    import "core-js/stable";
    import "regenerator-runtime/runtime";
    import 'promise-polyfill/src/polyfill';
    

    tsconfig.json

    {
      "extends": "@tsconfig/svelte/tsconfig.json",
      "include": ["src/**/*"],
      "exclude": ["node_modules/*"]
    }
    

    I want to add as a sidenote, than I only switched to rollup to see if there was any difference. First I got the same error as mentionned above. So the answer really is the incompatibility of the polyfill.min.js with webcomponents-sd-ce.js in IE11, and not the bundling method.