3

I've recently seen a problem that I cannot explain and I don't know how to debug in a way to find out what's changing what I'm seeing. Just to start off, I'm not going to be able to set up a repro environment as I have no idea what's causing this. I can only explain what I'm seeing and see if anyone has seen it or has any idea how to figure out what's going on.

So, as the title says, I have an element on my page that starts off normally, but then at some point one of the element's class property (i.e., "class1 class2 etc") literally gets a space put in between each character (i.e., "c l a s s 1 c l a s s 2 e t c").

This occurs on page that contains two JavaScript packages, both packaged with Webpack and using Babel. This issue only occurs in IE11, so the Babel transforms are also using a number of core-js polyfills, in which I'm using core-js 3. That's common to both packages. I've seen this issue in various builds of these packages, and where some combinations do not exhibit it, but then certain versions of one package will consistently cause it. And both packages seem to be able to cause it, proven by isolating one package at a package and changing another and seeing things change. So I'm leaning towards it being something to do with the dependencies (i.e., webpack, babel, core-js, or something else, but those are the main things). I've compared the build output when I've seen which packages are good and which are bad, but didn't notice anything that stood out as a cause.

Here is a screenshot of the class property that I describe above:

example

So, my questions:

  1. Has anyone ever seen this result and have any idea why it happened? That would be great to find someone that has seen this and knows what may have caused it.
  2. Barring that, does anyone know how to isolate a property change, in this instance a class property change, and see what's causing it? I've tried going through the IE11 "Performance" tool and found the "Style Calculation" where it's calculating the change when this property change occurs, but I can't get from there to potentially what JavaScript code actually made the change. Is there any way to do that? In IE11, since that's the only place I see it.

Like I said, this is a very strange issue, so I don't really expect any answers, but I would really appreciate it if anyone had any help or some ideas as to what to do. Thanks.

EDIT: Adding some configurations, it's all pretty standard

Package 1 (non-UI component): Package 1 Babel Config:

module.exports = {
"presets": [
    [
        "@babel/preset-env",
        {
            targets: {
                browsers: [
                    "> 0.25%",
                    "last 2 versions",
                    "ie 11",
                    "edge 18",
                    "safari >= 11",
                    "not dead"
                ]
            },
            corejs: 3,
            useBuiltIns: "usage",
            debug: false
        }
    ]
],
"ignore": [
    /babel-/,
    /@babel\/runtime/,
    /core-js/,
    /regenerator-runtime/
],
"plugins": [
    [
        "@babel/plugin-proposal-decorators",
        {
            legacy: true
        }
    ],
    [
        "@babel/plugin-proposal-class-properties",
        {
            loose: true
        }
    ],
    [
        "@babel/plugin-transform-runtime",
        {
            regenerator: true,
            corejs: 3
        }
    ]
],
"sourceMaps": true,
"sourceType": "unambiguous"
};

Package 1 Webpack config (merged together):

(common):

{
entry: path.join( __dirname, 'src', 'Main.js' ),
devtool: 'source-map',
output: {
    devtoolNamespace: 'APPNAME'
},
module: {
    rules: [
        {
            enforce: 'pre',
            test: /\.js$/,
            loader: 'eslint-loader',
            exclude: [
                /node_modules/
            ]
        },
        {
            test: /\.js$/,
            loader: 'babel-loader',
        }
    ]
},
plugins: [
    new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1
    })
]
};

(production):

{
mode: 'production',
output: {
    path: path.join(__dirname, 'dist'),
    filename: libnamemin
},
optimization: {
    moduleIds: 'total-size',
    mangleWasmImports: true,
    concatenateModules: false,
    minimizer: [
        new BabelMinifyPlugin({
            removeDebugger: true,
            mangle: true
        },{
            comments: false,
            sourceMap: 'source-map'
        })
    ]
},
module: {
    rules: []
},
plugins: [
    new CleanWebpackPlugin(),
    new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        openAnalyzer: false,
        generateStatsFile: true,
        reportFilename: path.join(__dirname, './reports/bundle/report.html'),
        statsFilename: path.join(__dirname, './reports/bundle/stats.json')
    })
]
};

Package 2 (UI component using "customElements", in IE11, "webcomponentsjs" polyfill) Package 2 Babel config:

module.exports = {
"presets": [
    [
        "@babel/preset-env",
        {
            targets: {
                browsers: [
                    "> 0.25%",
                    "last 2 versions",
                    "ie 11",
                    "edge 18",
                    "safari >= 11",
                    "not dead"
                ]
            },
            corejs: 3,
            useBuiltIns: "usage",
            debug: false
        }
    ]
],
"ignore": [
    /babel-/,
    /@babel\/runtime/,
    /core-js/,
    /regenerator-runtime/,
    /webcomponentsjs/,
    /@webcomponents/
],
"plugins": [
    [
        "@babel/plugin-proposal-decorators",
        {
            legacy: true
        }
    ],
    [
        "@babel/plugin-proposal-class-properties",
        {
            loose: true
        }
    ],
    [
        "@babel/plugin-transform-runtime",
        {
            regenerator: true,
            corejs: 3
        }
    ],
    [
        "@babel/plugin-syntax-dynamic-import",
        { }
    ]
],
"sourceMaps": true,
"sourceType": "unambiguous"
};

Package 2 Webpack config (merged together):

(common)

{
entry: path.join( __dirname, 'src', 'App.js' ),
devtool: 'source-map',
output: {
    devtoolNamespace: 'APPNAME'
},
module: {
    rules: [
        {
            enforce: 'pre',
            test: /\.js$/,
            loader: 'eslint-loader',
            exclude: [
                /node_modules/
            ]
        },
        {
            test: /\.(svg|png|woff|woff2)$/,
            loader: 'url-loader'
        },
        {
            test: /\.css|\.s(c|a)ss$/,
            use: [
                'to-string-loader',
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 1
                    }
                },
                {
                    loader: 'sass-loader',
                    options: {
                        sassOptions: {
                            importer: jsonImporter()
                        }
                    }
                }
            ]
        },
        {
            test: /\.js$/,
            loader: 'babel-loader',
            options: {
                root    : __dirname,
                rootMode: 'upward-optional'
            }
        }
    ]
},
plugins: [
    new UnusedFilesWebpackPlugin({
        patterns: ['./src/resources/images/*', './src/resources/logos/*'],
    }),
    new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1
    })
]
};

(production):

{
mode: 'production',
output: {
    path: path.join(__dirname, 'build'),
    filename: 'APPNAME.min.js'
},
optimization: {
    moduleIds: 'total-size',
    mangleWasmImports: true,
    concatenateModules: false,
    minimizer: [
        new BabelMinifyPlugin({
            removeDebugger: true,
            mangle: true
        },{
            comments: false,
            sourceMap: 'source-map'
        })
    ]
},
module: {
    rules: []
},
plugins: [
    new CleanWebpackPlugin(),
    new webpack.DefinePlugin({
        'process.env.__TF_NAME__': JSON.stringify(pkg.name),
        'process.env.__TF_VERSIONBUILD__': JSON.stringify('__METADATA_VERSION_BUILD__'),
        'process.env.__TF_VERSION__': JSON.stringify('__METADATA_VERSION__'),
        'process.env.__TF_BUILDDATE__': JSON.stringify((new Date(Date.now())).toUTCString())
    }),
    new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        openAnalyzer: false,
        generateStatsFile: true,
        reportFilename: path.join(__dirname, './reports/bundle/report.html'),
        statsFilename: path.join(__dirname, './reports/bundle/stats.json'),
    })
]
};
Chris
  • 76
  • 1
  • 4
  • I think for us to be able to help we would need some additional information about your build process, probably at least your webpack + babel config. Also does this happen immediately when rendered in IE 11, or does it occur after interacting with the page? Are you doing server side rendering? Also when you reference "both packages" are you specifically talking about webpack + babel? – kyle Sep 18 '20 at 22:59
  • "both packages" mean my two packages that are javascript/webpack/babel packages that do different things, so maybe there's some interaction going on that shouldn't be is one thought. This occurs after the page loads and after all the code is run. One package of mine is runs mostly after the "load" event, but this issue seems to occur after it completely finishes, but that could just be when I'm seeing it render. My second package is a customElement UI package, in IE11 using the "webcomponentsjs" polyfill, but it's not running shown on the page this occurs, only the JS is loaded. – Chris Sep 18 '20 at 23:55
  • Continued: There is server side rendering with an old Perl application, but all the server side processing is finished by the time this occurs. It happens after my non-UI javascript/webpack/babel package completes its processing. But like I said in my original question, I've seen the issue occur because of both of the packages, which makes mean lean towards something in the dependencies that both share. – Chris Sep 18 '20 at 23:59
  • ContinuedAgain: My webpack + babel config is fairly simple. Both use webpack 4.43.0 and babel 7.x. Core-js 3 for polyfills that IE11 definitely uses some of. "useBuiltIns" value of "usage" for the Babel functions.I'll edit the original with the babel config. – Chris Sep 19 '20 at 00:02
  • Just a small concern why "to-string-loader" in passed as string in array, while other's in object. Isn't this should be like https://stackoverflow.com/a/54966115/10102695 – Dolly Sep 19 '20 at 05:06
  • @Dolly, sure, it can be done that way too. But either way works. That's definitely not the issue here though. Thanks anyway. – Chris Sep 21 '20 at 06:18
  • @kyle do you have any idea how to keep packages like these completely separate? as I was trying to continue debugging this, I was stepping through some parts of the code and realized that one of the string polyfills (for split method) makes the call from one of my applications, and the code it ends up in is in the other application. Both use the same version of "corejs", so it shouldn't matter, but maybe it does. Is there a way to make sure the polyfills remain isolated? Or maybe even create a shared packages that is separate that both can use? I'd settle for isolated at first though. – Chris Sep 21 '20 at 06:21
  • @Chris, I want to confirm with you whether the classes got applied on the web page or it has no effect on the page? I also suggest you test the issue with the other IE 11 versions to check whether issue occurs on any version of the IE 11 or it only occur with specific versions. It may help you narrow down the issue. – Deepak-MSFT Sep 21 '20 at 08:06
  • @Chris I still am not exactly sure why you have two configs, it looks like you may want to have a single config with multiple entry points. https://webpack.js.org/concepts/entry-points/ – kyle Sep 21 '20 at 18:31
  • @kyle It's two configs because they're two completely separate components that are built similarly (i.e. using webpack). They are two JavaScript modules that get loaded on the same page. I don't know if they're interacting at all, but they could be. But that's why there's two, two components. And each component has two different builds, a dev and production, but I don't think that's what you were talking about. – Chris Oct 27 '20 at 22:11

1 Answers1

1

This was not an easy issue to Google for, but I was able to find this post while trying to!

Eventually I was able to find the cause of the issue through (tedious) debugging. It turned out to be a result of an issue with core-js:

https://github.com/zloirock/core-js/issues/751

Downgrading using the following command resolved the issue:

npm install core-js@3.5.0 --save

Kevin
  • 1,403
  • 2
  • 11
  • 15