微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

webpack loader,替换 import 依然使用原包

如何解决webpack loader,替换 import 依然使用原包

我正在尝试编写一个 WebPack 加载器,目的是动态替换 lodash 导入。作为一种学习练习,可以更加熟练地使用 WebPack。 (我知道还有其他方法可以减小 lodash 包的大小,例如 lodash-es

目前,加载器的工作方式是替换 lodash 的所有实例,并用动态生成名称替换它。例如,它会转换:

import _ from "lodash"
_.filter(x,x=>x.Enabled)

import kittyKitchenMischief_filter from "lodash/filter"
kittyKitchenMischief_filter(x,x=>x.Enabled)

使用加载器,我注意到 lodash 被一遍又一遍地捆绑。而不是特定的模块。我添加一个简单的函数来将输出写入新文件,因为 WebPack 正在运行加载器。如果我从生成的源构建它工作正常。只有我需要的函数是从 lodash 导入的。

Lodash Minimized

这就是它通过 WebPack 加载器运行时变得有趣的地方,lodash 一遍又一遍地以全尺寸捆绑。创建一个比正常导入 lodash 更大的包。

Why you add lodash so many times?!

通过加载器替换导入实际上会导致该包被多次完全导入是否有特定原因?文档中是否有我遗漏的内容


我创建了一个小版本的源代码,只替换了几个函数,而不是检查函数是否存在,动态生成名称等。

module.exports = function (src) {   
    if (!src.includes("lodash")) return src; //Ensure source has the word lodash somewhere in it
    let source = (" " + src).slice(1); // force copy of source string not refrence

    let actuallyUsed = []; //Lodash functions that are actually used in the source
    let lines = source.replace(/(\r)/gi,"").split("\n"); //Split source line by line
    let lodashImportedLine = undefined; //Line that imports lodash
    let lodashImportedname = undefined; //Lodash is imported as (typically `_` or `lodash`)

    //Functions used in the test codebase (there is another function that finds these,regardless of name)
    const functionsUsed = [{ old: "cloneDeep",new: "mountainActDirect" },{ old: "filter",new: "speedWindPrice" },{ old: "find",new: "eveningPassageIndicate" },{ old: "first",new: "rhymeSenseChanging" },{ old: "forEach",new: "toldRubberBlanket" },{ old: "indexOf",new: "standSetssplit" },{ old: "map",new: "fewBeyondSaved" },{ old: "meanBy",new: "sentenceSettleRSStairs" },{ old: "orderBy",new: "distanceOldestElectric" },{ old: "sortBy",new: "allowRoomMoment" },{ old: "uniq",new: "considerHeatheading" }];

    //Find Import Line
    for (let index = 0; index < lines.length; index++) {
        //Get line and line as lowercase
        const line = lines[index];
        const lcx = line.toLowerCase();

        //Check if the line is an import statement for lodash
        if ( lcx.includes("import") && lcx.includes("lodash") && !lcx.includes("lodash/") ) {
            lodashImportedLine = line; //Set the import line title
            let spaces = line.split(" "); //Split line by space
            lodashImportedname = spaces[1].trim(); //Get import name
            break; //It is found we do not need to continue iterating
        }
    }

    if (!lodashImportedLine) return src; //If the import line was not found return nothing

    //After locating name remove multiline functions `e.g. lodash\n.filter`
    let re = new RegExp(`${lodashImportedname}[\n\r\s]+\.`,"gim");
    let re2 = new RegExp(/\.[\s]+\./,"gim");
    source = source.replace(re,`${lodashImportedname}`).replace(re2,`${lodashImportedname}`);
    lines = source.replace(/(\r)/gi,"").split("\n");

    //Replace all terms
    for (let index = 0; index < lines.length; index++) {
        const line = lines[index];

        //Find all times used
        for (let index = 0; index < functionsUsed.length; index++) {
            const fused = functionsUsed[index];
            let re = RegExp(`${lodashImportedname}.${fused.old}`,"gi");
            let match_res = line.match(re);

            //If the match is not null
            if (match_res) {
                //If the match is an array check the first value is not an empty string
                if (match_res[0]) actuallyUsed.push(fused);
            }
        }
    }

    //Get All unique functions used
    let unique = actuallyUsed.filter((item,i,ar) => ar.indexOf(item) === i);

    //Replace functions used with random name_truename
    for (let index = 0; index < unique.length; index++) {
        const fused = unique[index];
        let re = RegExp(`${lodashImportedname}.${fused.old}`,"g");
        source = source.replace(re,`${fused.new}_${fused.old}`);
    }

    //Create imports for those functions
    let newImports = unique.map( (x)=>`import ${x.new}_${x.old} from "lodash/${x.old}"` );

    //Replace current import with new imports;
    let newImportStatement = newImports.join("\r\n");
    source = source.replace(`${lodashImportedLine}`,newImportStatement);
    
    return source;
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。