手写一个简单的webpack实现

41 阅读1分钟

文件结构

测试代码

如下,source文件夹下的是测试代码 image.png

    // entry.js
    import message from './message.js'
    console.log(message)
    
    //message.js
    import {name} from './name.js'
    export default `${name} is a girl`
    
    // name.js
    export const name = 'lily'

mywebpack.js是模拟webpack实现的代码

    // mywebpack.js
    const fs = require('fs')
    const babylon = require('babylon')
    const traverse = require('babel-traverse').default;
    const path = require('path');
    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 mainAssets = createAsset(entry)
        const allAssets = [mainAssets]
        for(let asset of allAssets){
            const dir = path.dirname(asset.filename)
            asset.mapping = {}
            asset.dependencies.length>0&&asset.dependencies.forEach(relativePath=>{
                const absolutePath = path.join(dir,relativePath)
                const childAsset = createAsset(absolutePath)
                asset.mapping[relativePath] = childAsset.id
                allAssets.push(childAsset)
            })
        }
        return allAssets
    }
    function boundle(graph) {
        let modules = ''
        graph.forEach((module)=>{
            modules+=`${module.id}:[
                function(require,module,exports){
                    ${module.code}
                },
                ${JSON.stringify(module.mapping)}
            ],`
        })
        // 这里require,exports.default,需要深入了解一下commonjs规范
        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')
    const result = boundle(graph)
    console.log(result)

快捷命令编译

package.json的script中新增build命令

"build": "rm -f dist.js && node mywebpack.js > dist.js"