依然衔接上文,此文仿照webpack万物皆模块
的思想,尝试为我们写的browserify引入其他模块如css,ts等类型文件。
流程:
- 非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