webpack手写——bundler源码编写(三)

项目初始化

新建项目bundler,在目录下新建src目录,在目录新建文件, 目录结构如下:
在这里插入图片描述
word.js

export const word = 'hello'

message.js

import {word} from './word.js'
const message = `say ${word}`
export default message

index.js

import {message} from './message.js'
console.log(message)

实现打包工具

1.分析入口文件

bundler.js

const fs = require('fs') //获取文件信息
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    console.log(content)
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js,打印出了index.js中的内容:

katedeMacBook-Air:bundler kate$ node bundler.js
import {message} from './message.js'
console.log(message)
katedeMacBook-Air:bundler kate$ 

让代码高亮显示
安装:

npm install cli-highlight -g

运行node bundler.js | highlight

2.拿到模块的依赖

babel: 帮助我们分析语法
安装:

npm install @babel/parser --save

参考文档: https://www.babeljs.cn/docs/babel-parser
bundler.js

const fs = require('fs') //获取文件信息
const parser = require('@babel/parser')
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    console.log(parser.parse(content, {
        sourceType: 'module'
    }))
    // console.log(content)
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js | highlight,打印出抽象语法树

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
Node {
  type: 'File',
  start: 0,
  end: 57,
  loc:
   SourceLocation {
     start: Position { line: 1, column: 0 },
     end: Position { line: 2, column: 20 } },
  errors: [],
  program:
   Node {
     type: 'Program',
     start: 0,
     end: 57,
     loc: SourceLocation { start: [Position], end: [Position] },
     sourceType: 'module',
     interpreter: null,
     body: [ [Node], [Node] ],
     directives: [] },
  comments: [] }

使用babel中parse分析抽象语法树
bundler.js

const fs = require('fs') //获取文件信息
const parser = require('@babel/parser')
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    const ast = parser.parse(content, {
        sourceType: 'module'
    })
    console.log(ast.program.body)
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js | highlight

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
[ Node {
    type: 'ImportDeclaration',
    start: 0,
    end: 36,
    loc: SourceLocation { start: [Position], end: [Position] },
    specifiers: [ [Node] ],
    source:
     Node {
       type: 'StringLiteral',
       start: 22,
       end: 36,
       loc: [SourceLocation],
       extra: [Object],
       value: './message.js' } },
  Node {
    type: 'ExpressionStatement',
    start: 37,
    end: 57,
    loc: SourceLocation { start: [Position], end: [Position] },
    expression:
     Node {
       type: 'CallExpression',
       start: 37,
       end: 57,
       loc: [SourceLocation],
       callee: [Node],
       arguments: [Array] } } ]

两个node里是声明的语句, 声明的语句放置的是入口文件对应的依赖关系

使用babel中的traverse
安装:

npm install @babel/traverse --save

bundler.js

const fs = require('fs') //获取文件信息
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    const ast = parser.parse(content, {
        sourceType: 'module'
    })
    const dependencies = []
    //对代码分析
    //对ast遍历
    traverse(ast, {
        ImportDeclaration({node}) {
            // console.log(node)
            dependencies.push(node.source.value)
        }
    })
    console.log(dependencies)
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js | highlight:

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
[ './message.js' ]

路径是相对路径,需要打印出绝对路径(相对于bundler.js文件):
bundler.js

const fs = require('fs') //获取文件信息
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const path = require('path')
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    const ast = parser.parse(content, {
        sourceType: 'module'
    })
    const dependencies = []
    //对代码分析
    //对ast遍历
    traverse(ast, {
        ImportDeclaration({node}) {
            const dirname = path.dirname(filename)
            const newFile = './' + path.join(dirname, node.source.value)
            console.log(newFile)
            dependencies.push()
        }
    })
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js | highlight:

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
./src/message.js

存两个路径

const fs = require('fs') //获取文件信息
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const path = require('path')
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    const ast = parser.parse(content, {
        sourceType: 'module'
    })
    const dependencies = {}
    //对代码分析
    //对ast遍历
    traverse(ast, {
        ImportDeclaration({node}) {
            const dirname = path.dirname(filename)
            const newFile = './' + path.join(dirname, node.source.value)
            dependencies[node.source.value] = newFile
        }
    })
    console.log(dependencies)
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js | highlight:

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
{ './message.js': './src/message.js' }

3.转换成浏览器上可以运行的代码

使用babel中的core
安装:

npm install @babel/core --save

参考文档: https://www.babeljs.cn/docs/babel-core

使用babel中的preset-env
安装: npm i @babel/preset-env --save
bundler.js

const fs = require('fs') //获取文件信息
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const path = require('path')
const babel = require('@babel/core')
// 分析入口文件
const moduleAnalyser = (filename) => {
    //读取文件
    const content = fs.readFileSync(filename, 'utf-8')
    const ast = parser.parse(content, {
        sourceType: 'module'
    })
    const dependencies = {}
    //对代码分析
    //对ast遍历
    traverse(ast, {
        ImportDeclaration({node}) {
            const dirname = path.dirname(filename)
            const newFile = './' + path.join(dirname, node.source.value)
            dependencies[node.source.value] = newFile
        }
    })
    //能在浏览器上运行的模块代码
    const {code} = babel.transformFromAst(ast, null, {
        presets: ["@babel/preset-env"] //es6 => es5
    })
    console.log(code)
    //分析出入口文件和依赖和代码
    return {
        filename, 
        dependencies
        code
    }
}
//对index.js进行分析
moduleAnalyser('./src/index.js')

运行node bundler.js | highlight:

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
"use strict";

var _message = require("./message.js");

console.log(_message.message);

入口文件总的分析

//...
    //分析出入口文件和依赖和代码
    return {
        filename, 
        dependencies,
        code
    }
}
//对index.js进行分析
const moduleInfo = moduleAnalyser('./src/index.js')
console.log(moduleInfo)

运行node bundler.js | highlight:

katedeMacBook-Air:bundler kate$ node bundler.js | highlight
{ filename: './src/index.js',
  dependencies: { './message.js': './src/message.js' },
  code:
   '"use strict";\n\nvar _message = require("./message.js");\n\nconsole.log(_message.message);' }

你可能感兴趣的:(webpack)