实现构建工具之loader实现

依然衔接上文,此文仿照webpack万物皆模块的思想,尝试为我们写的browserify引入其他模块如cssts等类型文件。

流程:

  • 非js文件也可以require
  • 最终一起打包在chunk文件中,且对应引入功能均可用

思路

经典思路,即使用loader,流程如下:
1.匹配每个require函数引入路径的后缀
2.使用对应的loader将文件代码处理一遍
3.其他与之前一样

实现

在生成函数代码块时改成如下内容

    `function(){
      ${useLoader(wholePath, codeSplicing, pathIndexMap)}
    }`

其中,useLoader如下

const { extname, resolve, dirname, basename } = require("path");
const { execSync } = require("child_process");
const fs = require("fs");

const scriptFormat = (path, code, codeSplicing, pathIndexMap) => {
  return code
    .trim()
    .replace(/require/g, "_require")
    .replace(/_require\(['\"](.*)['\"]\)/g, function (matched, $1) {
      const filePath = resolve(dirname(path), $1);
      codeSplicing(filePath);

      return `_require(${pathIndexMap[resolve(filePath)]})`;
    })
    .replace(/;$/, "");
};

const loaderMap = {
  js(path, codeSplicing, pathIndexMap) {
    const code = scriptFormat(
      path,
      fs.readFileSync(path, "utf-8"),
      codeSplicing,
      pathIndexMap
    );

    return `
        const module = {exports:{}};
        let {exports} = module;
        ${code}
        return module.exports
    `;
  },
  css(path) {
    const cssCode = fs.readFileSync(path, "utf-8");
    return `
        const style = document.createElement("style");
        style.innerText = \`${cssCode}\`
        document.head.appendChild(style)
      `;
  },
  ts(path, codeSplicing, pathIndexMap) {
    const filePath = `./test/temp_${basename(path, ".ts")}.js`;
    try {
      execSync(`tsc ${path} --outFile ${filePath}`);
    } catch (error) {}

    const code = scriptFormat(
      path,
      fs.readFileSync(resolve(filePath), "utf-8"),
      codeSplicing,
      pathIndexMap
    );

    fs.unlinkSync(resolve(filePath));
    return `
        const module = {exports:{}};
        let {exports} = module;
        ${code}
        return module.exports
    `;
  },
};

const useLoader = function (path, codeSplicing, pathIndexMap) {
  const ext = extname(path).replace(/^\./, "");
  const loader = loaderMap[ext];
  if (!loader) throw new Error("不支持 ${loader} 文件类型");
  return loader(path, codeSplicing, pathIndexMap);
};

测试

module3.ts

const {obj} = require("./module2.js");

const weather:string = 'snow'
obj.age+=10

module.exports = {
    weather
};

color.css

p {
  color: rgb(79, 114, 230);
}

index.js

const { obj } = require("./module1.js");
const module2 = require("./module2.js");
const { weather } = require("./module3.ts");
require("../asserts/css/color.css");

obj.name = "jane";
obj.age += 10;

console.log(obj);
console.log(module2);
console.log(weather);

index.html




    
    
    
    Document


    

测试文字

打印内容:

{ name: 'jane', age: 50 }
{ obj: { name: 'jane', age: 50 } }
snow

浏览器效果:

引入的ts文件,css文件均生效,且ts和js两种格式可以互相随意引用

总结

loader的工作本质是通过javascript,dom,web api等使得html文件能够作用其内容

代码路径:https://github.com/a793816354/myBrowserify/tree/arrWithLoader

你可能感兴趣的:(实现构建工具之loader实现)