Find dead code in large Javascript Application [duplicate] - javascript

In order to refactor a client-side project, i'm looking for a safe way to find (and delete) unused code.
What tools do you use to find unused/dead code in large react projects? Our product has been in development for some years, and it is getting very hard to manually detect code that is no longer in use. We do however try to delete as much unused code as possible.
Suggestions for general strategies/techniques (other than specific tools) are also appreciated.
Thank you

Solution:
For node projects, run the following command in your project root:
npx unimported
If you're using flow type annotations, you need to add the --flow flag:
npx unimported --flow
Source & docs: https://github.com/smeijer/unimported
Outcome:
Background
Just like the other answers, I've tried a lot of different libraries but never had real success.
I needed to find entire files that aren't being used. Not just functions or variables. For that, I already have my linter.
I've tried deadfile, unrequired, trucker, but all without success.
After searching for over a year, there was one thing left to do. Write something myself.
unimported starts at your entry point, and follows all your import/require statements. All code files that exist in your source folder, that aren't imported, are being reported.
Note, at this moment it only scans for source files. Not for images or other assets. As those are often "imported" in other ways (through tags or via css).
Also, it will have false positives. For example; sometimes we write scripts that are meant to simplify our development process, such as build steps. Those aren't directly imported.
Also, sometimes we install peer dependencies and our code doesn't directly import those. Those will be reported.
But for me, unimported is already very useful. I've removed a dozen of files from my projects. So it's definitely worth a shot.
If you have any troubles with it, please let me know. Trough github issues, or contact me on twitter: https://twitter.com/meijer_s

Solution for Webpack: UnusedWebpackPlugin
I work on a big front-end React project (1100+ js files) and stumbled upon the same problem: how to find out which files are unused anymore?
I've tested the next tools so far:
findead
deadfile
unrequired
None of them really worked. One of the reason is that we use "not standard" imports. In additional to the regular relative paths in our imports we also use paths resolved by the webpack resolve feature which basically allows us to use neat import 'pages/something' rather than cumbersome import '../../../pages/something'.
UnusedWebpackPlugin
So here is the solution I've finally come across thanks to Liam O'Boyle (elyobo) #GitHub:
https://github.com/MatthieuLemoine/unused-webpack-plugin
It's a webpack plugin so it's gonna work only if your bundler is webpack.
I personaly find it good that you don't need to run it separately but instead it's built into your building process throwing warnings when something is not ok.
Our research topic: https://github.com/spencermountain/unrequired/issues/6

Libraries such as unrequired and deadcode only support legacy code.
In order to find the unused assets, to remove manually, you can use deadfile
library:https://m-izadmehr.github.io/deadfile/
Out of box support for ES5, ES6, React, Vue, ESM, CommonJs.
It supports import/require and even dynamic import.
It can simply find unused files, in any JS project.
Without any config, it supports ES6, React, JSX, and Vue files:

First of all, very good question, in large project coders usually try many lines of code test and at the end of result, hard to find the unused code.
There is two possible that must be work for you - i usually do whenever i need to remove and reduce the unused code into my project.
1st way WebStorm IDE:
If you're using the web-storm IDE for JS development or React JS / React Native or Vue js etc it's tell us and indicate us alote of mention with different color or red warning as unused code inside the editor
but it's not works in your particular scenario there is another way to remove the unused code .
2nd Way unrequired Library: (JSX is not supported)
The second way to remove the unused code inside the project is unrequired library you can visit here : unrequired github
another library called depcheck under NPM & github here
Just follow their appropriate method - how to use them you will fix this unused issue easily
Hopefully that helps you

I think the easiest solution for a create-react-app bootstrapped application is to use ESLint. Tried using various webpack plugins, but ran into out of memory issues with each plugin.
Use the no-unused-modules which is now a part of eslint-plugin-import.
After setting up eslint, installing eslint-plugin-import, add the following to the rules:
"rules: {
...otherRules,
"import/no-unused-modules": [1, {"unusedExports": true}]
}

My approach is an intensive use of ESlint and make it run both on IDE ad before every push.
It points out unused variables, methods, imports and so on.
Webpack (which has too nice plugins for dead code detection) take care about avoiding to bundle unimported code.

findead
With findead you can find all unused components in your project. Just install and run:
Install
npm i -g findead
Usage
findead /path/to/search

This question recalls me that react by default removes the deadcode from the src when you run the build command.
Notes:
you need to run build command only when you want to ship your app to production.

Related

Other way to share react ts components between projects

I have been looking for a way to mostly share some code between projects specifically for SPFX and fluent ui. We found 3 main ways to do that.
1.
Creating a component library is the way that seemed least complicated cause it uses the same infrastructure and do all building without the need to configure it.
But this adds some issues, we need to built and manually link the solution locally to make it work, this will also work if we put in a repo. so this is mitigated.
The second is that implicitly this will also require the fluent ui and react. Plus having to place it inside a SPFX component library project.
2.
I saw some promise using paths in ts and this works fine while using the ts compiler. It will go to the folder that your proj is referring and build it at calling time. which is great. But it did not work in SPFX.
3.
Another way was to have a post install to sync the folders which seems easy enough but I wonder how practical this is plus how people are doing it, if they are, how.
All I wanted to figure out now is a way to take my component code and share as if they were in a folder of my src or a simple extension of the code. No need to have extra dependencies or build steps, just the code that can be used as a ts/tsx file. ex:
shared lib:
//assuming I have react and fluentui already installed for the project.
import button from 'fluentui';
export const fancyCustomButtom = (props) => {
return (<Button text="Standard" />);
};
src project folder:
import {fancyCustomButtom} from 'shared-lib'
It is fine if it needs to build the files before we can use it but can we do it at build time or when the package is installed? also wouldn't it increase my bundle size by making both module dependent on things already available (react, fluentui)?
Given the way Microsoft have architected the loading of bundles in SharePoint and Teams - I believe an SPFX component library is the best way to share code between different solutions, particularly if you are looking to minimise bundle size...
Imagine you have a library for something re-usable: a form, a set of standard branded components - something of that nature. You could put your shared code in repos and add references to it - either by publishing your own repo publicly or using the npm install git+https://yourUrl syntax; but what effectively happens there is that your code is pulled down in to node_modules for each project, and any referenced module code is included in your bundles. If you have two, three, four or more webparts on the same page - using those same libraries, you're multiplying how many times that code is included on the page.
If you follow Microsoft's guide on setting up a component library project however, your npm link commands allow your types to be recognised in consuming projects without needing to actually include the bundled distribution code. You can deploy your library code once to the App Catalog, and if it's referenced in other solutions -- it's loaded on pages as needed: once.
I have found the development experience to be quite flaky at times, but it does work. When I run gulp clean on my library code, or come back to it after some time, I sometimes find that I need to run npm link and npm link my-project-name again as per the instructions in the above tutorial. Whenever you run gulp build on your library, you should also rebuild the project that consumes the library, either by using gulp build / bundle or by saving a file (if you're running gulp serve). This process works well for developing, and once it comes time to deploy, all you need to do is add a named reference to your library inside package.json and then deploy both .sppkg files to your App Catalog.
In terms of your last question re: bundle size - react is not actually included in the dependencies for an SPFX library project, but you will find it's available to use. When you build your library, if you take a look in the generated javascript in your dist folder, you will see it's listed as one of the dependencies for the webpacked content along with react-dom and ControlStrings. It's on line 1.
office-ui-fabric-react is included as a devDependency thanks to the #microsoft/sp-webpart-workbench package that gets scaffolded with all SPFX projects - and if you check your library's dist javascript, you will see that included components are being webpacked and included in your bundle. I'm not entirely sure if when you pull this code in to your consuming project, whether webpack then tree-shakes to de-duplicate and ensures only necessary code is included: I don't know. Someone else may be able to illuminate us there or provide a more accurate explanation of what's going on... I will update this response if anyone comments to let me know.
And finally, this is more of a personal way of working, but it may be worth consideration:
When developing a library, I sometimes reference it in other projects via a local npm install ../filepath command. This ensures that when I install the library as described, the consuming project installs any necessary dependencies. I'm able to tweak both projects if I need o. When it comes time to deploy, I commit my changes to both projects, deploy my library code to the App Catalog, and then npm uninstall the library from the consuming project and add a reference as described in the above tutorial. When I deploy projects that use my library, they just work.
I recently developed a library that uses pnpjs, in particular the #pnp/sp library that is used to talk to SharePoint. If you look at the Getting Started guide for that library, they expect you to pass a reference to your Application Customizer or Web Part context during setup, or explicitly set things up using a base URL and so forth - and of course, a library doesn't really have a page context of any sort - the whole point of this code is that it's reusable. So that poses a challenge. My solution was to do the setup in the consuming web part(s) and ensure that they pass a reference to the sp object (which is of type SPRest) to any code or components that exist in my library. My library has peerDependencies on those pnp libraries so that the code isn't duplicated in consuming projects. Sometimes you have to think about what your library needs to include in its bundle and what you expect consuming solutions to already have, and maybe find ways to ensure things aren't included that aren't needed.
For example, in the scenario you talk about, you may want to ensure fluentui or office-ui-fabric-react are only devDependencies or peerDependencies for your library. As long as your library and the project(s) consuming your library both use the right version(s) you shouldn't have any trouble, and you can document any pre-requisites with your library documentation. You can check which versions of these libraries are installed per the SPFX version you are currently using ie. SPFX v1.11 or v1.12 etc. Just run npm ls <packagename> to get a breakdown, or check your package.json file.

'Modern' way of customizing Javascript libraries

Javascript dinosaur here. Back in the good old days, customizing a JS library was pretty easy. I'd download the non-minified version, put that sucker on the /js folder, do the changes necessary to the code and embed it on the html. Like this:
<script src="Sortable.js"></script>
Enter the marvelous world of modern javascript, a great advance where no project folders have less than 14mb. In this world, I don't download the file and put it on the /js folder, I install the package with 12 warnings and import it, and then a little program compiles it for me every time I need to test it. Takes 10x longer, but hey, my code is now compatible with the 0.0003% of users who use Internet Explorer 4. Wonderful. Anyway, this is the modern code:
import Sortable from 'sortablejs/modular/sortable.core.esm.js';
Sarcasm aside, I have a serious question: When customizing a library in a modern setup, of course, I won't change the final compiled version as it would be overwritten in a new build. I also wouldn't change the files sitting in node_modules folder, because these will be overwritten with every update. So what's the best way to do this?
Something tells me I have to fork the library, put the fork on npm and import the fork. I don't want to believe it. Is this really what I have to do to customize literally 2 lines of code?
If I had such a task, I would rather download the source code, do the changes, build it, and "install" it as a dependency using Local Path:
{
"name": "project",
"dependencies": {
"sortablejs" : "file:../path/to/sortablejs/bin"
}
}
But it's difficult to update the package with those changes. That's why you may consider using something like patch-package or using Yarn's yarn patch <package>, which lets you keep your changes separately from your package (in theory, I've never used it before).

Is it ok to refer to node_modules directly?

The project I'm currently working on (Java/JSP) currently uses no package manager to manage its JavaScript dependencies.
The used libraries are just committed under version control, and referred as such from the JSP pages...
I would like to evolve to a workflow were we would use a package manager (e.g. yarn), and later on eventually also webpack to further optimise the build.
I would like to do this in a phased approach. As I have little to none experience with such a frontend workflow, I have some questions:
Would it be weird to just start with defining the used libraries in a package.json file, and use yarn to manage to package?
yarn will then fetch the modules and store them in the node_modules folder.
Is it bad practice to refer to the scripts in that node_modules folder directly from within the JSP files?
Example
package.json:
"dependencies": {
"jquery": "^3.4.1"
}
app.jsp:
<script src="node_modules/jquery/dist/jquery.min.js"></script>
Yes, that's completely ok. It's the way we normally initialize frontend projects (probably sometimes, some higher-level script does it for us but still). Just run npm init.
Oh yes, that's quite bad. Most probably, it simply will not work. If you want to load something directly on a page, you need a cdn version.
To be honest, having a package.json is not that useful without a building tool like webpack, gulp or grunt.
UPD:
Regarding why loading things directly from node_modules might hurt:
A lot of modern JS packages (like, for instance, React) use modules that are not implemented yet in any browser or ES5+ syntax which is supported only by some browsers.
This way, you may load React directly but it will crash in any browser with something like import is not defined.
Basically, a lot of modern packages expect you to either have a building tool or use cdn version.
Honestly, I don't know how many packages let you seamlessly load things directly from node_modules.
So, in your particular situation, I'd say that if particular packages you use let you do so & are shipped with browser-compatible version, you can just go ahead & do it this way.
Nevertheless, I see it highly possible that sooner or later you will face a package that will not let you to include it this way (or worse: it will, but will crash some browsers that don't support latest JS features/introduce other nasty bugs in your app).
Hopefully, at this stage, you will already have the building tool configured.
Bonus:
Relatively recently some browsers started to support modules!
There are even tools like snowpack that do something particularly similar to what you are looking for.
Even though, you still need to be very careful with this. Direct inclusion of lodash.js, for instance, will generate 640 GETs (check out this article -> "Libraries" section).
NPM packages are meant to be run with Node, not in a browser. You would need to serve a browser-friendly version, using something like webpack or browserify.

Easy IDEA sharing of JS code between different JS projects?

I want to share common JS code between different JS projects in a very easy way.
I thought about creating a Bower component (see: LINK) or a private NPM component (see: LINK).
However, I want it to be used in a very IDE friendly way. A such, that when we update the Common code (project) we don't need to first publish the changed Common code.
Let me explain what I mean by how we do this in Java with Eclipse (we use mostly IntelliJ with Python and React JS currently): In a Java project we include Common Java code through a maven dependency, and also open the Common Java code as a project in Eclipse. Eclipse is then smart enough to see that it will include a direct link to the Common code project, instead of including the Common code as jar such that you don't need to first deploy the Common code project to the private repo when making changes to it.
We aren't experts in JS code yet, so how can we realise this same kind of friendly IDE usage with JS ?
I solved it by using npm-link:
1) Used npm-link as explained here: LINK
2) Solved the babel problem as explained here: LINK
In my case, my babel config looks like:
options: {
presets: ['babel-preset-es2015', 'babel-preset-react'].map(require.resolve),
plugins: ['babel-plugin-transform-react-jsx-img-import'].map(require.resolve)
}
Works pretty wel. I looked at npm local-dependencies, but it didn't work with the current npm version. Currently it does as they fix it. But I always have to run "npm start" just like other sync npm modules. Neither do I want to use local dependencies as several developers put the shared code at different places, which make it fragil.

Load remote scripts with browserify

I really like using cdnjs to load up javascript on the client-side, it makes my project smaller and cleaner, and loads everything faster as well. I currently use require.js for module loading, which can load from cdnjs and shim traditional scripts to work with it easily. I've been looking more into browserify recently as an alternative, and while I did find browserify-shim, which can shim non-cjs modules much like require does, I'm curious if there is a way to load a script from a remote source with browserify, or if you have to install everything locally no matter what.
If the answer is that you would have to install everything locally through npm, this makes things a little weird. On one hand, you can add node_modules to the .gitignore file and not have to worry about keeping all the deps on version control if you are using a package.json, but on the other hand, you'd need to get the modules back in there on deploy, which means an additional post-deploy step that would run npm install and that node would need to be installed wherever you are deploying to, which also seems a little awkward to me for a static site especially.
Really, any ideas or discussion on this would be great : )
The way I think about it is this, you have three options: concat the JS files together locally (browserify) before deployment, load them in real-time (require.js), or a mix of both. To be fair, you can use require.js to concat your files with r.js too. For me at least, I like how browserify is designed to use the same syntax and mentality as npm modules. I think in the end the weirdness your experiencing doesn't really matter. If all the code is packaged together, you deploy, and there aren't any dependencies, seems like a win to me. Also, I think this is more in line with Java and similar compiled languages are doing, which is putting all the deps together in a deployable package. I know I mention Java but don't let that scare you because really we are all benefitting from the ideas of those around us even the languages we think we don't like. If I had to bet my money, I would bet on browserify since it's offering (what I consider) to be a more mature means of handling modules (organized by file based rather than syntax). The npm also gives us a great way to share our code so two thumbs up for them.

Categories

Resources