Write webpack plug-in: delete business files that are not dependent

Posted by AshtrayWaterloo on Fri, 04 Mar 2022 11:23:56 +0100

background

The SCRM project needs to be handed over to another department. Due to some considerations, the leader needs to retain the functions only needed by the other party, delete other functions, and then upload the code to the new warehouse address for handover.

After communicating with the product manager, the following requirements were identified:

  1. Keep or delete the page (function) as a unit
  2. Some functions need to be deleted on individual pages

problem analysis

Keep or delete the page (function) as a unit. In other words, according to the granularity, a route corresponds to a page. A page may contain multiple tab s. A page has multiple resources (imported components, api files, pictures, utils methods, etc.), and they are also divided into global and local.

The larger the granularity, the easier it will be to delete manually. The smaller the granularity, if it is deleted manually, you need to first confirm whether this resource is not referenced by other pages. If yes, it needs to be retained. If no, it can be deleted.

Due to the manual deletion of fine-grained resources, it takes time and effort. I hope to write a script to realize this function. When you think of file dependency, you can easily think of the dependency analysis of module s in the construction phase of webpack principle.

webpack after the initial translation environment:

  1. The built-in plug-in EntryPlugin finds the entry main according to the entry configuration JS file, call compilation The addentry function triggers the build process
  2. Call the corresponding loaders and translate them into javascript text
  3. Then it is resolved into an AST tree through acorn, traverses the AST tree, listens to the hooks corresponding to import, obtains the corresponding resource dependency, and calls addDependency of module to add the dependency to the dependency list of the current module
  4. For new dependencies, go back to step 2 to continue processing

If we can get the list of dependent files made by webpack for us, then compare the files under the src directory. If the files are not in the list of dependent files, collect them and delete them.

code implementation

const glob = require('glob');
const path = require('path');
const fs = require('fs')
class FileShaking {
    constructor(options) {
        this.options = {
            excludeRegex: [
                /readme\.md/i, // Do not delete readme files
                /utils/ // Do not delete the files in the tool method directory
            ],
            delete: false,
            ...options
        };
        this.fileDependencies = [];
        this.srcFiles = [];
        this.toDelFiles = [];
    }
    apply (compiler) {
        compiler.hooks.afterEmit.tap("FileShaking", (compilation) => {
            this.fileDependencies = Array.from(compilation.fileDependencies).filter(path => !path.includes('node_modules'));
            this.deleteIndependence();
        });
    }
    async deleteIndependence () {
        this.srcFiles = await this.getSrcFiles();
        this.srcFiles.forEach(filePath => {
            if (!this.fileDependencies.includes(filePath) && !this.matchExclude(filePath)) {
                this.toDelFiles.push(filePath)
            }
        })
        if (this.options.delete) {
            this.delFiles();
            this.delEmptyDir('./src', (err) => {
                if (err) {
                    console.log(err)
                } else {
                    console.log('Delete empty folder DONE')
                }
            });
        }
    }
    getSrcFiles () {
        return new Promise((resolve, reject) => {
            glob('./src/**/*', {
                nodir: true
            }, (err, files) => {
                if (err) {
                    reject(err)
                } else {
                    let out = files.map(file => {
                        let tmpFilePath = path.resolve(file);
                        return tmpFilePath.slice(0, 1).toUpperCase() + tmpFilePath.slice(1);
                    });
                    resolve(out)
                }
            })
        })
    }
    matchExclude (pathname) {
        let matchResult = false;
        if (this.options.excludeRegex.length) {
            for (let i = 0; i < this.options.excludeRegex.length; i++) {
                if (matchResult = this.options.excludeRegex[i].test(pathname)) {
                    return matchResult
                }
            }
        }
        return matchResult;
    }
    delEmptyDir (dir, cb) {
        fs.stat(dir, (err, stat) => {
            if (err) {
                cb(err)
                return;
            }
            if (stat.isDirectory()) {
                fs.readdir(dir, (err, objs) => {
                    objs = objs.map(item=>path.join(dir,item));
                    if (err) {
                        cb(err)
                        return
                    }
                    if (objs.length === 0) {
                        return fs.rmdir(dir, cb)
                    } else {
                        let count = 0
                        function done(...rest) {
                            count++;
                            if (count === objs.length) {
                                cb(...rest);
                            }
                        }
                        objs.forEach(obj => {
                            this.delEmptyDir(obj, done)
                        })
                    }
                })
            }
        })
    }
    delFiles () {
        this.toDelFiles.forEach(item => {
            fs.unlink(item, (err) => {
                console.log(err)
            });
        })
        console.log('Delete file DONE')
    }
}

module.exports = FileShaking;

The above code has been put into my github: https://github.com/Rockergmai...

result

  1. After deleting the routing file, run again and get the result: 162 files are deleted

The remaining demand points can be adjusted manually.

Reference

https://segmentfault.com/a/11...
https://github.com/Viyozc/use...

Topics: Webpack