前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >webpack打包原理分析和实现(一)

webpack打包原理分析和实现(一)

作者头像
kiki.
发布2022-09-29 08:32:55
3270
发布2022-09-29 08:32:55
举报

首先,新建一个空文件夹,编辑器(webstrom)打开文件夹,执行npm init -y,生成package.json,在根目录新建webpack.config.js,加入如下代码(webpack 4.0的基础配置)

const path=require('path');
module.exports={
    entry:'./src/index.js',
    mode:'development',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'main.js'
    }
};

新建src目录,添加index.js,exop.js

expo.js

export const add=(a,b)=>{
    return a+b
}
export const minus=function (a,b) {
    return a-b
}

index.js

import {add,minus} from "./expo.js"
add(1,2)
console.log("hello webpack")

执行命令 npx webpack,看到生成的文件/dist/main.js:

 (function(modules) { // webpackBootstrap
 	// The module cache
 	var installedModules = {};

 	// The require function
 	function __webpack_require__(moduleId) {

 		// Check if module is in cache
 		if(installedModules[moduleId]) {
 			return installedModules[moduleId].exports;
 		}
 		// Create a new module (and put it into the cache)
 		var module = installedModules[moduleId] = {
 			i: moduleId,
 			l: false,
 			exports: {}
 		};

 		// Execute the module function
 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

 		// Flag the module as loaded
 		module.l = true;

 		// Return the exports of the module
 		return module.exports;
 	}
	...

 	// Object.prototype.hasOwnProperty.call
 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

 	// __webpack_public_path__
 	__webpack_require__.p = "";


 	// Load entry module and return exports
 	return __webpack_require__(__webpack_require__.s = "./src/index.js");
 })
 ...

打包后生成的代码,可以直接在浏览器的控制台运行,大致的意思就是,webpack实现了一个webpack_require来实现自己的模块化,把代码都缓存在installedModules里,代码文件以对象传递进来,key是路径,value是包裹的代码字符串,并且代码内部的require,都被替换成了webpack_require处理依赖模块的路径

如何自己实现一个简单的webpack打包流程呢?

实现步骤

  • 基础配置,webpack会读取配置
    • 找到入口模块
  • 入口分析
    • 分析依赖模块(拿到模块的路径)
    • 分析内容(并对内容处理)
    • 编译内容
  • 依赖模块(递归找到依赖)
    • 分析依赖模块(并对内容处理)
    • 编译内容
  • 生成bundle.js,代码可以直接在浏览器中运行

自己实现一个bundle.js

  • 模块分析:读取入口文件,分析代码 新建文件./lib/webpack.js,其中利用了node的fs,读取文件内容,为了拿到文件中依赖,不推荐使用字符串截取,引入的模块名越多,就越麻烦,不灵活,推荐使用@babel/parser,这是babel7的工具,分析包括es6的内部的语法,返回一个ast抽象树 npm i @babel/parser --save
const fs = require('fs')//node的核心模块fs
constructor(options) {
        console.log(options)
        const {entry, output} = options
        this.entry = entry
        this.output = output
        //存所有模块信息
        this.modules = []
    }
     run() {//入口函数
        const info = this.parse(this.entry)
        console.log(info)
        }
     parse(entryFile) {
        //! 分析入口模块的内容
        const content = fs.readFileSync(entryFile, 'utf-8')
        console.log(content)

        //!分析出哪些是依赖?以及依赖的路径
        const ast = parser.parse(content, {
            sourceType: 'module'
        })
        console.log(ast.program.body)
    }

新建build.js

//! 拿到webpack的配置文件
const options =require("./webpack.config.js")
const webpack=require('./lib/webpack')
//类实例化
new webpack(options).run()

执行node build.js,打印ast body部分的内容

[ Node {
    type: 'ImportDeclaration',
    start: 0,
    end: 35,
    loc: SourceLocation { start: [Position], end: [Position] },
    specifiers: [ [Node], [Node] ],
    source:
     Node {
       type: 'StringLiteral',
       start: 24,
       end: 35,
       loc: [SourceLocation],
       extra: [Object],
       value: './expo.js' },
    trailingComments: [ [Object] ] },
  Node {
    type: 'ExpressionStatement',
    start: 44,
    end: 52,
    loc: SourceLocation { start: [Position], end: [Position] },
    expression:
     Node {
       type: 'CallExpression',
       start: 44,
       end: 52,
       loc: [SourceLocation],
       callee: [Node],
       arguments: [Array] } },
  Node {
    type: 'ExpressionStatement',
    start: 54,
    end: 82,
    loc: SourceLocation { start: [Position], end: [Position] },
    expression:
     Node {
       type: 'CallExpression',
       start: 54,
       end: 82,
       loc: [SourceLocation],
       callee: [Node],
       arguments: [Array] },
    trailingComments: [ [Object] ] } ]

可以看到,index.js中的三行代码分别被解析成导入、表达式、表达式

import {add,minus} from "./expo.js" //解析导入
add(1,2)解析成表达式
console.log("hello webpack")//解析成表达式
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

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