问题描述
我正在尝试编写一个 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 导入的。
这就是它通过 WebPack 加载器运行时变得有趣的地方,lodash 一遍又一遍地以全尺寸捆绑。创建一个比正常导入 lodash 更大的包。
通过加载器替换导入实际上会导致该包被多次完全导入是否有特定原因?文档中是否有我遗漏的内容?
我创建了一个小版本的源代码,只替换了几个函数,而不是检查函数是否存在,动态生成名称等。
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 (将#修改为@)