如果能挺过去,要更加珍惜活着的时间~
hey,各位宝宝,最近的疫情很严重,大家尽量就不要到外面浪了,好好在家做个安静的宝宝吧。不得不出门时也一定要戴口罩哦!照顾好自己,望平安... ...
为了解webpack的原理,我们来试着实现一个小型的打包工具。以下代码实现了两个功能:
- 将ES6转为ES5
- 支持在js中通过import引用CSS文件
实现
因为涉及ES6转ES5所以需要引用babel相关工具
代码语言:javascript复制yarn add babylon babel-traverse babel-core babel-preset-env
使用babel转换代码
代码语言:javascript复制const fs = require('fs')
const path = require('path')
const babylon = require('babylon')
const traverse = require('babel-traverse').default
const { transformFromAst } = require('babel-core')
function readCode(filePath){
// 读取文件内容
const centent = fs.readFilesync(filePath,'utf-8')
// 生成ast
const ast = babylon.parse(content,{
sourceType : 'module'
})
// 寻找当前文件的依赖关系
const dependencies = []
traverse(ast,{
ImportDeclaration:({node})=>{
dependencies.push(node.source.value)
}
})
// 通过AST将代码转为ES5
const {code} = trasnformFromAst(ast, null, {
presets: ['env']
})
return {
filePath,
dependencies,
code
}
}
// 接下来我们实现一个函数,有如下功能:
// 调用 readCode 函数,传入入口文件
// 分析入口文件的依赖
// 识别 JS 和 CSS 文件
function getDependencies(entry){
const entryObject = readCode(entry)
const dependencies = [entryObject]
// 遍历所有文件依赖关系
for(const asset of dependencies){
// 获得文件路径
const dirname = path.dirname(asset.filepath)
// 遍历当前文件依赖关系
asset.dependencied.forEach(relativePath=>{
// 获取绝对路径
const absolutePath = path.join(dirname, relativePath);
// CSS文件逻辑是插入style标签,JS文件需要查看是否有依赖关系
if(/.css$/.test(absolutePath)){
const content = fs.readFileSync(absolutePath, 'utf-8');
const code = `
const style = document.createElement('style')
style.innerText = ${JSON.stringfy(content).replace(/\r\n/g)}
document.head.appendChild(style)
`
dependencies.push({
filePath: absolutePath,
relativePath,
dependencied:[],
code
})
}else{
const child = readCode(absolutePath)
child.relativePath = relativePath
dependencies.push(child)
}
})
}
retrun dependencies
}
// 首先我们读取入口文件,然后创建一个数组,该数组的目的是存储代买中涉及到的所有文件
// 然后遍历这个数组,开始这个数组中只有入口文件,遍历过程中,如果入口文件依赖其他文件就会被push到数组中
// 现在我们已经获取了所有的依赖,接下来实现打包功能
function bundle(dependencies, entry){
let moudles = ''
dependencies.forEach(dep =>{
const filePath = dep.relativePath || entry;
modules = `'${filePath}'`:(
function (module, exports, require){ ${dep.code} }
)
})
const result= `
(function(modules{
// 构建require函数,目的是为了获取模块暴露出来的内容
function require(id){
const module = {exports :{}}
modules[id](module, module.exports, require)
return module.exports
}
require('${entry}')
})({${modules}})
`
// 将生成的内容写入文件中
fs.writeFileSync('./bundle.js', result)
}
到这里就实现了一个简单的打包工具,主要功能:
- 找出入口文件所有的依赖关系
- 然后通过构建 CommonJS 代码来获取
exports
导出的内容
每张故作坚强的笑脸背后,是怎样风雨漂泊的一生---Lin