實(shí)現(xiàn)構(gòu)建工具之loader實(shí)現(xiàn)

依然銜接上文,此文仿照webpack萬(wàn)物皆模塊的思想,嘗試為我們寫(xiě)的browserify引入其他模塊如css,ts等類(lèi)型文件。

流程:

  • 非js文件也可以require
  • 最終一起打包在chunk文件中,且對(duì)應(yīng)引入功能均可用

思路

經(jīng)典思路,即使用loader,流程如下:
1.匹配每個(gè)require函數(shù)引入路徑的后綴
2.使用對(duì)應(yīng)的loader將文件代碼處理一遍
3.其他與之前一樣

實(shí)現(xiàn)

在生成函數(shù)代碼塊時(shí)改成如下內(nèi)容

    `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} 文件類(lèi)型");
  return loader(path, codeSplicing, pathIndexMap);
};

測(cè)試

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>測(cè)試文字</p>
    <script src='./dist/chunk.js'></script>
</body>
</html>

打印內(nèi)容:

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

瀏覽器效果:
\color{rgb(79, 114, 230)}{測(cè)試文字}

引入的ts文件,css文件均生效,且ts和js兩種格式可以互相隨意引用

總結(jié)

loader的工作本質(zhì)是通過(guò)javascript,dom,web api等使得html文件能夠作用其內(nèi)容

代碼路徑:https://github.com/a793816354/myBrowserify/tree/arrWithLoader

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容