50 lines of code to implement Webpack component usage statistics

50 lines of code to implement Webpack component usage statistics

background

Recently, a leader wanted us to build a component library, and then I wanted to know which components of the third-party component library currently used in the project are most frequently used. I originally wanted to consult my friend, but he was too busy, so I had to do it myself. I wonder if I can use webpack to realize my idea.

Effect

We use @material-ui, here are the components used

accomplish

We know that the source of the loader is a static string of the file as shown below

The fastest solution is to use regular expressions to count strings, but this will cause inaccurate statistics if there are any comments. So we can use AST to achieve this. Many experts have already talked about the concept of AST, so I won’t go into details.

Analyzing AST

I use @babel/parser to analyze it. Let's first look at the following code on the website.

import { Box } from '@material-ui/core';
import Autocomplete from '@material-ui/lab/Autocomplete';

We can see that the path is program => body, and then the declaration type is type: ImportDeclaration. Let's continue to look at the following structure

"source": {
     "type": "StringLiteral",
     "value": "@material-ui/core"
 },
 // The second paragraph "source": {
      type": "StringLiteral",
     "value": "@material-ui/lab/Autocomplete"
 },

We send the value in this field with the package name we want, so the first code is

const ast = parser.parse(source, {
      sourceType: 'module',
      plugins: ['jsx'],
 });
const getImport = 'ImportDeclaration';
const getMaterialImport = packageName || '@material-ui';
const importAst = ast.program.body.filter(
  // type node type, here we filter the import declaration type and filter at the same time (i) => i.type === getImport && i.source.value.includes(getMaterialImport),
);

After getting the relevant ast array, the next step is to get the component name. By observation, we find that there are two fields in the specifiers identifier field that contain component names: imported, local

  • imported means variables exported from the exporting module
  • local represents the variables of the current module after import

Here I use local because the imported field will not appear in the following method.

import Autocomplete from '@material-ui/lab/Autocomplete';

Now that we have the package name, it will be easy to get to the point and post the complete code.

demo

const parser = require('@babel/parser');
const loaderUtils = require('loader-utils');
const total = {
  len: 0,
  components: {},
};
// Object sorting const sortable = (obj) => Object.fromEntries(Object.entries(obj).sort(([, a], [, b]) => b - a));
module.exports = function(source) {
  console.log(source, '--');
  const options = loaderUtils.getOptions(this);
  const { packageName = '' } = options;
  const callback = this.async();
  if (!packageName) return callback(null, source);
  try {
    // Parse into ast
    const ast = parser.parse(source, {
      sourceType: 'module',
      plugins: ['jsx'],
    });
    if (ast) {
      setTimeout(() => {
        const getImport = 'ImportDeclaration';
        const getMaterialImport = packageName;
        const importAst = ast.program.body.filter(
          // type node type, here we filter the import declaration type and filter at the same time (i) => i.type === getImport && i.source.value.includes(getMaterialImport),
        );
        total.len = total.len + importAst.length;
        for (let i of importAst) {
          const { specifiers = [] } = i;
          for (let s of specifiers) {
            if (s.local) {
              const { name } = s.local;
              total.components[name] = total.components[name] ? total.components[name] + 1 : 1;
            }
          }
        }
        total.components = sortable(total.components);
        console.log(total, 'total');
        callback(null, source);
      }, 0);
    } else callback(null, source);
  } catch (error) {
    callback(null, source);
  }
};

Calling the loader

 {
  test: /\.(jsx|)$/,
  exclude: /node_modules/,
  include: [appConfig.eslintEntry],
  use: [
    {
      loader: path.resolve(__dirname, './loader/total.js'),
      options:
        packageName: '@material-ui',
      },
    },
  ],
},

A simple statistical function is completed. Of course, there may be other better ways. I just provide this idea. Welcome to discuss

at last

What is the significance of doing this? For example, after our own component library goes online, we can count the number of component references and use a certain time dimension, such as weeks. We can use data to analyze the optimization direction of the next version of our component library, and we can also use it as a KPI reporting tool. After all, it is supported by data.

This concludes the article on how to use Webpack components in 50 lines of code. For more information on Webpack component usage statistics, please search previous articles on 123WORDPRESS.COM or continue browsing the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Electron-vue uses webpack to package multiple pages of entry files
  • Implementation of webpack code fragmentation
  • How to debug loader plugin in webpack project
  • 80 lines of code to write a Webpack plugin and publish it to npm
  • Implementation steps for building multi-page programs using Webpack
  • webpack -v error solution

<<:  Complete steps of centos cloning linux virtual machine sharing

>>:  MySQL 5.7.18 release installation guide (including bin file version)

Recommend

How to use resident nodes for layer management in CocosCreator

CocosCreator version: 2.3.4 Most games have layer...

JavaScript code to implement a simple calculator

This article example shares the specific code of ...

Three uses and differences of MySQL not equal

Judgment symbols are often used in MySQL, and not...

Introduction to the process of creating TCP connection in Linux system

Table of contents Steps to create TCP in Linux Se...

How to filter out duplicate data when inserting large amounts of data into MySQL

Table of contents 1. Discover the problem 2. Dele...

Example code of setting label style using CSS selector

CSS Selectors Setting style on the html tag can s...

How to implement one-click deployment of nfs in linux

Server Information Management server: m01 172.16....

Docker and portainer configuration methods under Linux

1. Install and use Docer CE This article takes Ce...

Vue implements a simple shopping cart example

This article example shares the specific code of ...

Some pitfalls of JavaScript deep copy

Preface When I went to an interview at a company ...

HTML insert image example (html add image)

Inserting images into HTML requires HTML tags to ...

CSS sets the box container (div) height to always be 100%

Preface Sometimes you need to keep the height of ...

Graphic tutorial on installing tomcat8 on centos7.X Linux system

1. Create the tomcat installation path mkdir /usr...