用js写一个模块打包工具

# 概览
1. 找到入口文件
2. 解析入口文件, 提取它依赖的文件
3. 解析入口文件的依赖的依赖, 递归去创建一个文件间的依赖图, 描述所有文件的依赖关系
4. 把所有文件打包成一个文件

## 开发

1. 新建几个js文件
* name.js
* message.js
* entry.js

2. 三个文件依赖关系
entry 依赖-> message 依赖-> name

3. 创建一个my-webpack.js 我们在这个文件开发

4.了解几个工具库
* babylon 生成ast语法树
* babel-traverse 遍历ast语法树
* babel-core 提取语法树里面的代码

5. 创建一个打包命令在package.json
"scripts": {
    "build": "rm -rf dist.js && node my-webpack.js > dist.js"
  }
const fs = require('fs')
const babylon = require('babylon')
const path = require('path')
const traverse = require('babel-traverse').default
const babel = require('babel-core')
let ID = 0

function createAsset (filename) {
  const content = fs.readFileSync(filename, 'utf-8')

  const ast = babylon.parse(content, {
    sourceType: 'module'
  })

  const dependencies = []

  traverse(ast, {
    ImportDeclaration: ({ node }) => {
      dependencies.push(node.source.value)
    }
  })

  const id = ID++

  const { code } = babel.transformFromAst(ast, null, {
    presets: ['env']
  })

  return {
    id,          // 模块唯一标识
    filename,    // 模块路径
    dependencies,// 模块中使用的依赖
    code         // 模块代码
  }
}

function createGraph (entry) {
  const mainAsset = createAsset(entry)
  const allAsset = [mainAsset]
  for (let asset of allAsset) {
    const dirname = path.dirname(asset.filename) // 获取绝对路径
    asset.mapping = {} // 当前文件的依赖对象, key:路径, 值是id
    asset.dependencies.forEach(relativePath => {
      const absolutePath = path.join(dirname, relativePath) // 依赖文件的绝对路径
      // 获取文件的依赖
      const childAsset = createAsset(absolutePath)

      asset.mapping[relativePath] = childAsset.id

      allAsset.push(childAsset) // 遍历整个依赖图
    })
  }
  return allAsset
}

function bundle (graph) {
  let modules = ''

  graph.forEach(module => {
    modules += `${module.id}:[
      function (require, module, exports) {
        ${module.code}
      },
      ${JSON.stringify(module.mapping)}
    ],`
  })

  const result = `
    (function(modules){
      function require(id) {
        const [fn, mapping] = modules[id]

        function localRequire(relativePath) {
          return require(mapping[relativePath])
        }

        const module = {exports:{}}

        fn(localRequire, module, module.exports)

        return module.exports
      }
      require(0)
    })({${modules}})
  `

  return result
}

const graph = createGraph('source/entry.js')

console.log(bundle(graph))
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 平台:Windows 7 版本:1.7.7 简介 Sea.js实现了对JS代码的模块化组织,大大提高了前端开发效率...
    逸之阅读 4,607评论 1 4
  • webpack 支持 AMD 和 CommonJS 类型,通过 loader 机制也可以使用 ES6 的模块格式,...
    赛亚人之神阅读 205评论 0 0
  • 1.模块回顾 模块化为了解决什么? 主要是为了解决变量污染的问题,以及便于维护,以及重用 什么是模块?模块化? 模...
    moly琴阅读 317评论 0 0
  • 1. 简介 介绍模块打包工具 2. 什么是模块 关于模块和模块化,百度百科有一段引用自《Java应用架构设计:模块...
    love丁酥酥阅读 306评论 0 1
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 129,954评论 2 7

友情链接更多精彩内容