实现构建工具之打包改进

最近查看browserify源码,发现其没有用eval和new Function,原因如下:
确保browserify的安装使用了语法[email protected]或 后来存在一个安全漏洞,恶意文件可能会 浏览时执行代码。 该漏洞涉及破坏用于 检查语法以了解更多信息性错误。在节点0.10中,Function()以“eval()”的形式实现,这样恶意代码甚至可以执行 如果从未调用“function()”返回的函数。节点0.11确实如此 似乎不易受攻击。 多亏了Cal Leeming[[email protected]] 感谢你发现并揭露这个错误!

经过一番思考,发现之前 重写的browserify也可以改进为不使用eval和new Function
改进代码如下:
browserify.js

const fs = require("fs");
const { resolve } = require("path");

const moduleFuncCache = [];
let curIndex = 0;

//记录path和数组对应资源数组位置
const pathIndexMap = {};
const codeSplicing = (path) => {
  // 获取绝对路径
  const wholePath = resolve(path);

  if (pathIndexMap[wholePath] !== undefined) return;

  const text = fs
    .readFileSync(wholePath, "utf-8")
    .trim()
    .replace(/require/g, "_require")
    .replace(/_require\(['\"](.*)['\"]\)/g, function (matched, $1) {
      codeSplicing($1);
      return `_require(${pathIndexMap[resolve($1)]})`;
    })
    .replace(/;$/, "");

  moduleFuncCache.push(`
    function(){
      const module = {exports:{}};
      let {exports} = module;
      ${text}
      return module.exports
    }
  `);
  pathIndexMap[wholePath] = curIndex++;
};

const getCode = () => {
  // eval方式转函数
  return `
        // 自执行函数,避免全局污染
        (function(){
            const moduleCache = []
            const _require = function(index){
                // 第一次引用该模块则执行,后续从缓存中取
                if(!moduleCache[index]) moduleCache[index] = formatModuleFuncCache[index]()
                return moduleCache[index]
            }

            //数组收集,省去了json序列化的过程,从而省去转码的过程
            const formatModuleFuncCache = [${moduleFuncCache}]

            //执行入口文件代码
            formatModuleFuncCache[${moduleFuncCache.length - 1}]()
        })()
    `;
};

//主函数,传入文件路径,返回最终打包完成的代码块
const browserify = (path) => {
  // 为每个require的模块拼接代码,为其提供module实例,并返回module.exports
  codeSplicing(path);

  // 阻止代码,使其能解析代码cache对象,并依照引入顺序来执行代码块
  return getCode();
};

// 执行命令行传入打包源文件 node ./browserify.js index.js,此时path即index.js
const [path] = process.argv.splice(2);
// 写目标文件;
fs.writeFileSync("./chunk.js", browserify(path));

能够改进的核心原因是:

  • 对象不方便转字符串,需要借助json
  • json对中文解析能力弱,需要转码,而函数代码转码就需要在chunk中转回来,则被动地必须使用eval或者new Function
  • 数组很方便转化成代码字符串,不需要经过上述流程

代码地址:https://github.com/a793816354/myBrowserify/tree/arr

你可能感兴趣的:(实现构建工具之打包改进)