前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实现小型打包工具

实现小型打包工具

作者头像
用户3258338
发布2020-02-17 14:35:47
5070
发布2020-02-17 14:35:47
举报
文章被收录于专栏:女程序员的日常_Lin

如果能挺过去,要更加珍惜活着的时间~


hey,各位宝宝,最近的疫情很严重,大家尽量就不要到外面浪了,好好在家做个安静的宝宝吧。不得不出门时也一定要戴口罩哦!照顾好自己,望平安... ...

为了解webpack的原理,我们来试着实现一个小型的打包工具。以下代码实现了两个功能:

  1. 将ES6转为ES5
  2. 支持在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)
}

到这里就实现了一个简单的打包工具,主要功能:

  1. 找出入口文件所有的依赖关系
  2. 然后通过构建 CommonJS 代码来获取 exports 导出的内容

每张故作坚强的笑脸背后,是怎样风雨漂泊的一生---Lin

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 女程序员的日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档