Vue is extremely slow to compile this HTML template in dev mode - javascript

I am using a template app setup that I bootstrapped with vue CLI. I have one component that has 20 nested div tags. Compiling such a component in dev mode takes around 10 seconds. The deeper I nest the html elements the longer it takes and the time grows exponentially.
Is this behaviour normal? Is there a way to improve compilation time?
Here's an example: https://gist.github.com/dmitrybelyakov/ed64145624f42188372500018671eb0f

Answering my own question here: following the link to this SO post by Bennett Dams, some people already investigated this, and there is an issue with prettier library that gets used internally by vue-loader, specifically their template compiler utils. The issue has been reported to prettier team here and there, but it hasn't been fixed as of yet.
Because of that, vue template compiler comes with this issue out of the box. So if you nest ~30 html elements you can basically halt your compiler (only happens in dev mode).
Same goes for when you have less nested (~4-5) levels elements, but a few of them, in which case compilation gets progressively slower and reload/inject time suffers which makes waiting for your component to reload a pain.
I have reported this issue to vue-loader team here #1426 asking for a config option to disable use of prettier, so hopefully it will get looked at.
UPDATE: this should now be fixed in vue-loader via prettify config option that was added: https://github.com/vuejs/vue-loader/issues/1426
OLD SOLUTION:
For the moment though, the only fix is to edit node_modules/#vue/component-compiler-utils/dis/compileTemplate.js to comment out the line (should be around line 97) like so:
//code = prettier.format(code, { semi: false, parser: 'babylon' });

Related

"TypeError: can't convert undefined to object" only after vite build, before, with vide dev, everything works perfectly

I'm using Vite combined with React and Typescript.
When I run vite dev the live version of the website runs perfectly, not even errors on the console.
When I run vite build and then vite preview all I get to see is a white page and the
TypeError: can't convert undefined to object
error in the console.
I cannot trace the problem in my code because the error happens after the build/minimization, but just to be sure, I added safety checks in the instances where I call Object.keys().
This is the segment of the code where the error starts:
Object.keys(pd).forEach(function (e) {
if (pd[e] === 0)
Xd.prototype["on" + e] = function () {
this.scope.emit(e);
};
else if (pd[e] === 1)
Xd.prototype["on" + e] = function (t) {
this.scope.emit(e, t);
};
});
Edit:
I was checking the minimized code and right before the long block of code where the bug is, I saw a MuiTouchRipple. I'm using the MaterialUI library, is it possible that the library is causing this problem?
I tried to update from version 5.4.2 to 5.6.3, but after the build it still crashes.
I managed to fix it.
Posting the debug steps for the newbies like me.
Debug
1. Disable minimization
This allows you to see the original code, it's still in a bundled form, so you still cannot identify the exact file where the problem is, but at least you know something more. (in my specific case, since I'm using vite I had to change a variable in the config file, see https://vitejs.dev/config/#build-minify).
2. Change typescript compiler options
In my case the target and module were set to ESNext, trying to change it to ES6 or to commonjs helped to have a better searchable code.
(see https://www.tsmean.com/articles/learn-typescript/typescript-module-compiler-option/)
3. Search the code that causes the error
When I tried to search the code in vscode it did not appear. That's a good sign, at least my code was not causing the problem!
But at the same time: what now?
The solution I found is to either disable vscode excluded folders from the search (by default vscode does not search in node_modules), or to use grep -r in the project folder.
I found the latter to be faster and more efficient.
Solution
In my specific case the problem was an old library that hasn't been updated in years (https://www.npmjs.com/package/react-html-parser). Once I removed it everything started working.
I had similar problem, and for me this was caused by "target": "es5" in tsconfig.json.
After changing to esnext, problem is gone.
https://esbuild.github.io/content-types/#es5
I had a similar problem. For me it was the build.lib.formats setting in vite.config.ts, that I needed to remove.

How to get javascript variables in a debugger when using webpack

I am developing a react application with the bundler Webpack.
I would like to debug this application with a browser console (here i use chrome).
I have used source-maps and equivalent in my webpack config:
devtool = 'inline-source-map';
Now errors are displayed with the exact line of the original file.
The problem is that i want to access to live variables with the console.
So far I found two ways to display them:
1- Add a library in webpack.config.js
output: {
library: "lib"
},
export variable in the code export var foo = 34; and finally inside the browser console use lib.foo.
2- use breakpoint and access to variable set in the file
Is there another solution to access live variables?
Thanks
There are other solutions, but that means defining global variables and that should be avoided as it can have side effects in the code you're trying to debug, so you might run into problems that are not identical with and without exposing the variables, which makes your debugging experience very frustrating.
Using breakpoints is the best you can do for debugging purposes. The browser debuggers, especially the Chrome devtools, are extremely powerful and it's absolutely worth spending some time to get familiar with them.
Because pausing the app at every breakpoint you set for getting to a certain point can be tedious, you can use conditional breakpoints. One way is to use the debugger statement in your code, in that case you can guard it by any JavaScript you like, for instance this will only pause when the input to the function is 5:
function debug(input) {
if (input === 5) {
debugger;
}
// Other code
}
Another way is to add conditional breakpoints in the Chrome devtools. As you've configure source maps, you can set the breakpoints in the original source under Sources > top > webpack:// > .
To set a conditional breakpoint you simply right-click a line and choose Add conditional breakpoint... and enter the condition, e.g. input === 5. You can also Edit breakpoint... to change or add a condition to an existing breakpoint. For more information about breakpoints in Chrome see Pause Your Code With Breakpoints.
In the Sources tab you can also right click anywhere and Add folder to workspace so you can edit the sources directly and save the changes to disk (in older versions of Chrome it's a bit more complicated to add a folder to the workspace). To let Chrome know that the source maps of webpack correspond to your workspace, you can right-click any webpack source map and select Map to File System Resource... and you simply choose the correct file of the workspace. After that, all the sources of webpack should automatically be mapped to the correct files. Now you can set the breakpoints there and when you change something and save it (Ctrl + S or Cmd + S), webpack will recompile it. See also Set Up Persistence with DevTools Workspaces.
Sometimes setting a breakpoint might be too much effort for only getting values of variables. With just console.log you probably end up with a lot of different messages. To make it easier to find the messages you need, you can use console.group which lets you put messages inside a group, that can be expanded and collapsed. The groups can also be nested. Use console.groupCollapsed if you want the group to be collapsed initially.

Angular 1.x migration performance issues

I am upgrading a huge angular 1 project from 1.3.x to 1.6.x because we require some patches in the latest version. After updating it seems that the entire application has slowed dramatically. I have been looking through the migration documentation but is there anything that could be causing major slow downs? Any bad code or gotchas that would cause this? I am having issues just with visual changes such as ng-show and ng-hide being slow and twitchy.
This is the CPU profile before upgrade:
This is the CPU profile after upgrade:
Thank you!
EDIT:
Let me give a little more context. I have a feeling this has to do with the digest cycle. For example, I a navbar where an icon will hide and another will show on hover.
Here is what it looks like in angular 1.3
Here is what it looks like in angular 1.6
I am getting a forced reflow performance warning after the update. Also this (recalculate style) is directed from angular-animate s computeCssStyles function (or at least that is the line of code it's directing me towards). I am also not calling any of $animate in my code. Is this just a product of the angular digest method? Also is there anything that I am missing from the migration docs about possible changes to digest?
Code example:
showDropdown is changed from false to true on hover and visa versa.
<i> ng-show="! showDropdown" </i><i> ng-show="showDropdown" </i>
EDIT:
Short term fix as I am not using animate anywhere in my code but it seems to be firing as per the newer angular digest method. I just disabled animations as a partial short term fix.
$animate.enabled(false);
Managing memory is difficult in JavaScript. Here are few best practices to improve the performance in terms of loading pages and freeing memory.
Removing Detached Node manually - Work on to remove detached object.
var myNode = document.getElementById("bodyPanel");
if(myNode !== null){
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
}
On every page switch, call destroy inside Angularjs controller. Also javaScript object Reference to null
$scope.$on("$destroy",function() {
$window.off("resize.Viewport");
});
Create Angular js Service to keep important data in memory to avoid fetching from HTML5 storage system.
As mentioned in comment, use ng-if instead of ng-show.

How can I make the Topbar extension work with the newest MediaWiki?

I run a MediaWiki site which uses the Topbar extension. I recently upgraded the installation to the bleeding edge version from MediaWiki's master branch: version 1.28.0-alpha (91e56cc).
Afterwards, the Topbar extension no longer works:
Usually, the topbar div is not inserted at all.
Occasionally, the topbar div appears but the links are nonfunctional.
The latter issue may be a problem with my CSS (I do not know), but the intermittent behavior concerns me. So the first order of business is to make sure the topbar div at least appears every time.
This extension is just a small javascript that is supposed to run when the page loads, to add a chunk of HTML near the top (<div id="mw-writh-topbar" ...>). It does so using a jQuery function.
Unfortunately, I am not really a web developer, so even this simple routine is a bit over my head.
Here's what I do know:
There are no 500 server errors, no overt problem with the PHP.
At some point early in my investigation, the developer console sometimes complained about Uncaught ReferenceError: jQuery is not defined, but I cannot reproduce it anymore now. Research vaguely suggested it could be because the extension does not use the new ResourceLoader mechanism, so I tried to migrate Topbar to use the ResourceLoader mechanism (via maintenance/convertExtensionToRegistration.php, and then wfLoadExtension('Topbar') in LocalSettings.php) but it did not seem to make any difference.
The Topbar hooks seem to be called, because css/Topbar.css gets added to the page. But I have no clue whether js/Topbar.js ever runs, and if so, what happens.
So: how can I debug this?
You need to convert the code to use ResourceLoader - currently the extension adds the code using OutputPage's addScriptFile(), and just assumes jQuery will be available by the time it runs. Starting with MediaWiki 1.26, everything loads asynchronously, so this doesn't work, and thus the need to convert it to the new system.
Instructions for doing so are here:
https://www.mediawiki.org/wiki/ResourceLoader/Migration_guide_for_extension_developers
https://www.mediawiki.org/wiki/ResourceLoader/Developing_with_ResourceLoader#Registering
Two notes:
Since MediaWiki 1.25, extensions are supposed to use the so-called "extension registration" instead of following the above manuals, but this might require more work and expertise.
Ugly hack warning: you can ignore all of this, and simply wrap the code in the JS file using RLQ.push( function(){ /* All of the code here */ } );. This shoves it all into the ResourceLoader's queue, so it will load after jQuery is available. I do not recommend this, but show it here for completeness' sake.

Bower components and Codekit 2

I have recently been getting into using CodeKit, and now version 2 is out, which is what this question regards. There seems to be great potential in using the bower components installer; however, there is little to no documentation on the working relationship between CodeKit and bower components. My code follows as:
// #codekit-prepend "../bower_components/jquery/dist/jquery.js"
// #codekit-prepend "../bower_components/PhysicsJS/dist/physicsjs-full-0.6.0.js"
Physics(function(world){
// code straight out of the example online from the bottom of http://wellcaffeinated.net/PhysicsJS/basic-usage
});
Then I get 'Physics' is not defined. errors on any reference. This is one example but I seem to always get stuck at this point and I'm wondering: Is there a working way to use prepended libraries through CodeKit's bower components integration?
It seems as though I forgot something quite simple. It took me hours to figure out that simply adding $(document).ready(function(){ at the beginning and closing those tags at the end fixed the problem. Not sure exactly how that works if the libraries are in the same file but I guess it adds a little delay to the execution of the code, allowing the libraries to be considered for the code that follows.

Categories